Patch [ 584078 ] Misc samples fixes from Dimitri Schoolwerth
[wxWidgets.git] / samples / exec / exec.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: exec.cpp
3 // Purpose: exec sample demonstrates wxExecute and related functions
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 15.01.00
7 // RCS-ID: $Id$
8 // Copyright: (c) Vadim Zeitlin
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "exec.cpp"
22 #pragma interface "exec.cpp"
23 #endif
24
25 // For compilers that support precompilation, includes "wx/wx.h".
26 #include "wx/wxprec.h"
27
28 #ifdef __BORLANDC__
29 #pragma hdrstop
30 #endif
31
32 // for all others, include the necessary headers (this file is usually all you
33 // need because it includes almost all "standard" wxWindows headers
34 #ifndef WX_PRECOMP
35 #include "wx/app.h"
36 #include "wx/frame.h"
37
38 #include "wx/utils.h"
39 #include "wx/menu.h"
40
41 #include "wx/msgdlg.h"
42 #include "wx/textdlg.h"
43 #include "wx/filedlg.h"
44 #include "wx/choicdlg.h"
45
46 #include "wx/button.h"
47 #include "wx/textctrl.h"
48 #include "wx/listbox.h"
49
50 #include "wx/sizer.h"
51 #endif
52
53 #include "wx/txtstrm.h"
54
55 #include "wx/process.h"
56
57 #include "wx/mimetype.h"
58
59 #ifdef __WINDOWS__
60 #include "wx/dde.h"
61 #endif // __WINDOWS__
62
63 // ----------------------------------------------------------------------------
64 // the usual application and main frame classes
65 // ----------------------------------------------------------------------------
66
67 // Define a new application type, each program should derive a class from wxApp
68 class MyApp : public wxApp
69 {
70 public:
71 // override base class virtuals
72 // ----------------------------
73
74 // this one is called on application startup and is a good place for the app
75 // initialization (doing it here and not in the ctor allows to have an error
76 // return: if OnInit() returns false, the application terminates)
77 virtual bool OnInit();
78 };
79
80 // Define an array of process pointers used by MyFrame
81 class MyPipedProcess;
82 WX_DEFINE_ARRAY(MyPipedProcess *, MyProcessesArray);
83
84 // Define a new frame type: this is going to be our main frame
85 class MyFrame : public wxFrame
86 {
87 public:
88 // ctor(s)
89 MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size);
90
91 // event handlers (these functions should _not_ be virtual)
92 void OnQuit(wxCommandEvent& event);
93
94 void OnKill(wxCommandEvent& event);
95
96 void OnClear(wxCommandEvent& event);
97
98 void OnSyncExec(wxCommandEvent& event);
99 void OnAsyncExec(wxCommandEvent& event);
100 void OnShell(wxCommandEvent& event);
101 void OnExecWithRedirect(wxCommandEvent& event);
102 void OnExecWithPipe(wxCommandEvent& event);
103
104 void OnPOpen(wxCommandEvent& event);
105
106 void OnFileExec(wxCommandEvent& event);
107
108 void OnAbout(wxCommandEvent& event);
109
110 // polling output of async processes
111 void OnIdle(wxIdleEvent& event);
112
113 // for MyPipedProcess
114 void OnProcessTerminated(MyPipedProcess *process);
115 wxListBox *GetLogListBox() const { return m_lbox; }
116
117 private:
118 void ShowOutput(const wxString& cmd,
119 const wxArrayString& output,
120 const wxString& title);
121
122 void DoAsyncExec(const wxString& cmd);
123
124 // the PID of the last process we launched asynchronously
125 long m_pidLast;
126
127 // last command we executed
128 wxString m_cmdLast;
129
130 #ifdef __WINDOWS__
131 void OnDDEExec(wxCommandEvent& event);
132 void OnDDERequest(wxCommandEvent& event);
133
134 bool GetDDEServer();
135
136 // last params of a DDE transaction
137 wxString m_server,
138 m_topic,
139 m_cmdDde;
140 #endif // __WINDOWS__
141
142 wxListBox *m_lbox;
143
144 MyProcessesArray m_running;
145
146 // any class wishing to process wxWindows events must use this macro
147 DECLARE_EVENT_TABLE()
148 };
149
150 // ----------------------------------------------------------------------------
151 // MyPipeFrame: allows the user to communicate with the child process
152 // ----------------------------------------------------------------------------
153
154 class MyPipeFrame : public wxFrame
155 {
156 public:
157 MyPipeFrame(wxFrame *parent,
158 const wxString& cmd,
159 wxProcess *process);
160
161 protected:
162 void OnTextEnter(wxCommandEvent& event) { DoSend(); }
163 void OnBtnSend(wxCommandEvent& event) { DoSend(); }
164 void OnBtnGet(wxCommandEvent& event) { DoGet(); }
165
166 void OnClose(wxCloseEvent& event);
167
168 void DoSend() { m_out.WriteString(m_textIn->GetValue() + '\n'); DoGet(); }
169 void DoGet();
170
171 private:
172 wxProcess *m_process;
173
174 wxTextInputStream m_in;
175 wxTextOutputStream m_out;
176
177 wxTextCtrl *m_textIn,
178 *m_textOut;
179
180 DECLARE_EVENT_TABLE()
181 };
182
183 // ----------------------------------------------------------------------------
184 // wxProcess-derived classes
185 // ----------------------------------------------------------------------------
186
187 // This is the handler for process termination events
188 class MyProcess : public wxProcess
189 {
190 public:
191 MyProcess(MyFrame *parent, const wxString& cmd)
192 : wxProcess(parent), m_cmd(cmd)
193 {
194 m_parent = parent;
195 }
196
197 // instead of overriding this virtual function we might as well process the
198 // event from it in the frame class - this might be more convenient in some
199 // cases
200 virtual void OnTerminate(int pid, int status);
201
202 protected:
203 MyFrame *m_parent;
204 wxString m_cmd;
205 };
206
207 // A specialization of MyProcess for redirecting the output
208 class MyPipedProcess : public MyProcess
209 {
210 public:
211 MyPipedProcess(MyFrame *parent, const wxString& cmd)
212 : MyProcess(parent, cmd)
213 {
214 Redirect();
215 }
216
217 virtual void OnTerminate(int pid, int status);
218
219 virtual bool HasInput();
220 };
221
222 // A version of MyPipedProcess which also sends input to the stdin of the
223 // child process
224 class MyPipedProcess2 : public MyPipedProcess
225 {
226 public:
227 MyPipedProcess2(MyFrame *parent, const wxString& cmd, const wxString& input)
228 : MyPipedProcess(parent, cmd), m_input(input)
229 {
230 }
231
232 virtual bool HasInput();
233
234 private:
235 wxString m_input;
236 };
237
238 // ----------------------------------------------------------------------------
239 // constants
240 // ----------------------------------------------------------------------------
241
242 // IDs for the controls and the menu commands
243 enum
244 {
245 // menu items
246 Exec_Quit = 100,
247 Exec_Kill,
248 Exec_ClearLog,
249 Exec_SyncExec = 200,
250 Exec_AsyncExec,
251 Exec_Shell,
252 Exec_POpen,
253 Exec_OpenFile,
254 Exec_DDEExec,
255 Exec_DDERequest,
256 Exec_Redirect,
257 Exec_Pipe,
258 Exec_About = 300,
259
260 // control ids
261 Exec_Btn_Send = 1000,
262 Exec_Btn_Get
263 };
264
265 static const wxChar *DIALOG_TITLE = _T("Exec sample");
266
267 // ----------------------------------------------------------------------------
268 // event tables and other macros for wxWindows
269 // ----------------------------------------------------------------------------
270
271 // the event tables connect the wxWindows events with the functions (event
272 // handlers) which process them. It can be also done at run-time, but for the
273 // simple menu events like this the static method is much simpler.
274 BEGIN_EVENT_TABLE(MyFrame, wxFrame)
275 EVT_MENU(Exec_Quit, MyFrame::OnQuit)
276 EVT_MENU(Exec_Kill, MyFrame::OnKill)
277 EVT_MENU(Exec_ClearLog, MyFrame::OnClear)
278
279 EVT_MENU(Exec_SyncExec, MyFrame::OnSyncExec)
280 EVT_MENU(Exec_AsyncExec, MyFrame::OnAsyncExec)
281 EVT_MENU(Exec_Shell, MyFrame::OnShell)
282 EVT_MENU(Exec_Redirect, MyFrame::OnExecWithRedirect)
283 EVT_MENU(Exec_Pipe, MyFrame::OnExecWithPipe)
284
285 EVT_MENU(Exec_POpen, MyFrame::OnPOpen)
286
287 EVT_MENU(Exec_OpenFile, MyFrame::OnFileExec)
288
289 #ifdef __WINDOWS__
290 EVT_MENU(Exec_DDEExec, MyFrame::OnDDEExec)
291 EVT_MENU(Exec_DDERequest, MyFrame::OnDDERequest)
292 #endif // __WINDOWS__
293
294 EVT_MENU(Exec_About, MyFrame::OnAbout)
295
296 EVT_IDLE(MyFrame::OnIdle)
297 END_EVENT_TABLE()
298
299 BEGIN_EVENT_TABLE(MyPipeFrame, wxFrame)
300 EVT_BUTTON(Exec_Btn_Send, MyPipeFrame::OnBtnSend)
301 EVT_BUTTON(Exec_Btn_Get, MyPipeFrame::OnBtnGet)
302
303 EVT_TEXT_ENTER(-1, MyPipeFrame::OnTextEnter)
304
305 EVT_CLOSE(MyPipeFrame::OnClose)
306 END_EVENT_TABLE()
307
308 // Create a new application object: this macro will allow wxWindows to create
309 // the application object during program execution (it's better than using a
310 // static object for many reasons) and also declares the accessor function
311 // wxGetApp() which will return the reference of the right type (i.e. MyApp and
312 // not wxApp)
313 IMPLEMENT_APP(MyApp)
314
315 // ============================================================================
316 // implementation
317 // ============================================================================
318
319 // ----------------------------------------------------------------------------
320 // the application class
321 // ----------------------------------------------------------------------------
322
323 // `Main program' equivalent: the program execution "starts" here
324 bool MyApp::OnInit()
325 {
326 // Create the main application window
327 MyFrame *frame = new MyFrame(_T("Exec wxWindows sample"),
328 wxDefaultPosition, wxSize(500, 140));
329
330 // Show it and tell the application that it's our main window
331 frame->Show(TRUE);
332 SetTopWindow(frame);
333
334 // success: wxApp::OnRun() will be called which will enter the main message
335 // loop and the application will run. If we returned FALSE here, the
336 // application would exit immediately.
337 return TRUE;
338 }
339
340 // ----------------------------------------------------------------------------
341 // main frame
342 // ----------------------------------------------------------------------------
343
344 // frame constructor
345 MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
346 : wxFrame((wxFrame *)NULL, -1, title, pos, size)
347 {
348 m_pidLast = 0;
349
350 #ifdef __WXMAC__
351 // we need this in order to allow the about menu relocation, since ABOUT is
352 // not the default id of the about menu
353 wxApp::s_macAboutMenuItemId = Exec_About;
354 #endif
355
356 // create a menu bar
357 wxMenu *menuFile = new wxMenu(_T(""), wxMENU_TEAROFF);
358 menuFile->Append(Exec_Kill, _T("&Kill process...\tCtrl-K"),
359 _T("Kill a process by PID"));
360 menuFile->AppendSeparator();
361 menuFile->Append(Exec_ClearLog, _T("&Clear log\tCtrl-C"),
362 _T("Clear the log window"));
363 menuFile->AppendSeparator();
364 menuFile->Append(Exec_Quit, _T("E&xit\tAlt-X"), _T("Quit this program"));
365
366 wxMenu *execMenu = new wxMenu;
367 execMenu->Append(Exec_SyncExec, _T("Sync &execution...\tCtrl-E"),
368 _T("Launch a program and return when it terminates"));
369 execMenu->Append(Exec_AsyncExec, _T("&Async execution...\tCtrl-A"),
370 _T("Launch a program and return immediately"));
371 execMenu->Append(Exec_Shell, _T("Execute &shell command...\tCtrl-S"),
372 _T("Launch a shell and execute a command in it"));
373 execMenu->AppendSeparator();
374 execMenu->Append(Exec_Redirect, _T("Capture command &output...\tCtrl-O"),
375 _T("Launch a program and capture its output"));
376 execMenu->Append(Exec_Pipe, _T("&Pipe through command..."),
377 _T("Pipe a string through a filter"));
378 execMenu->Append(Exec_POpen, _T("&Open a pipe to a command...\tCtrl-P"),
379 _T("Open a pipe to and from another program"));
380
381 execMenu->AppendSeparator();
382 execMenu->Append(Exec_OpenFile, _T("Open &file...\tCtrl-F"),
383 _T("Launch the command to open this kind of files"));
384 #ifdef __WINDOWS__
385 execMenu->AppendSeparator();
386 execMenu->Append(Exec_DDEExec, _T("Execute command via &DDE...\tCtrl-D"));
387 execMenu->Append(Exec_DDERequest, _T("Send DDE &request...\tCtrl-R"));
388 #endif
389
390 wxMenu *helpMenu = new wxMenu(_T(""), wxMENU_TEAROFF);
391 helpMenu->Append(Exec_About, _T("&About...\tF1"), _T("Show about dialog"));
392
393 // now append the freshly created menu to the menu bar...
394 wxMenuBar *menuBar = new wxMenuBar();
395 menuBar->Append(menuFile, _T("&File"));
396 menuBar->Append(execMenu, _T("&Exec"));
397 menuBar->Append(helpMenu, _T("&Help"));
398
399 // ... and attach this menu bar to the frame
400 SetMenuBar(menuBar);
401
402 // create the listbox in which we will show misc messages as they come
403 m_lbox = new wxListBox(this, -1);
404 wxFont font(12, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL,
405 wxFONTWEIGHT_NORMAL);
406 if ( font.Ok() )
407 m_lbox->SetFont(font);
408
409 #if wxUSE_STATUSBAR
410 // create a status bar just for fun (by default with 1 pane only)
411 CreateStatusBar();
412 SetStatusText(_T("Welcome to wxWindows exec sample!"));
413 #endif // wxUSE_STATUSBAR
414 }
415
416 // ----------------------------------------------------------------------------
417 // event handlers: file and help menu
418 // ----------------------------------------------------------------------------
419
420 void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
421 {
422 // TRUE is to force the frame to close
423 Close(TRUE);
424 }
425
426 void MyFrame::OnClear(wxCommandEvent& WXUNUSED(event))
427 {
428 m_lbox->Clear();
429 }
430
431 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
432 {
433 wxMessageBox(_T("Exec wxWindows Sample\n© 2000-2001 Vadim Zeitlin"),
434 _T("About Exec"), wxOK | wxICON_INFORMATION, this);
435 }
436
437 void MyFrame::OnKill(wxCommandEvent& WXUNUSED(event))
438 {
439 long pid = wxGetNumberFromUser(_T("Please specify the process to kill"),
440 _T("Enter PID:"),
441 _T("Exec question"),
442 m_pidLast,
443 // we need the full unsigned int range
444 -INT_MAX, INT_MAX,
445 this);
446 if ( pid == -1 )
447 {
448 // cancelled
449 return;
450 }
451
452 static const wxString signalNames[] =
453 {
454 _T("Just test (SIGNONE)"),
455 _T("Hangup (SIGHUP)"),
456 _T("Interrupt (SIGINT)"),
457 _T("Quit (SIGQUIT)"),
458 _T("Illegal instruction (SIGILL)"),
459 _T("Trap (SIGTRAP)"),
460 _T("Abort (SIGABRT)"),
461 _T("Emulated trap (SIGEMT)"),
462 _T("FP exception (SIGFPE)"),
463 _T("Kill (SIGKILL)"),
464 _T("Bus (SIGBUS)"),
465 _T("Segment violation (SIGSEGV)"),
466 _T("System (SIGSYS)"),
467 _T("Broken pipe (SIGPIPE)"),
468 _T("Alarm (SIGALRM)"),
469 _T("Terminate (SIGTERM)"),
470 };
471
472 int sig = wxGetSingleChoiceIndex(_T("How to kill the process?"),
473 _T("Exec question"),
474 WXSIZEOF(signalNames), signalNames,
475 this);
476 switch ( sig )
477 {
478 default:
479 wxFAIL_MSG( _T("unexpected return value") );
480 // fall through
481
482 case -1:
483 // cancelled
484 return;
485
486 case wxSIGNONE:
487 case wxSIGHUP:
488 case wxSIGINT:
489 case wxSIGQUIT:
490 case wxSIGILL:
491 case wxSIGTRAP:
492 case wxSIGABRT:
493 case wxSIGEMT:
494 case wxSIGFPE:
495 case wxSIGKILL:
496 case wxSIGBUS:
497 case wxSIGSEGV:
498 case wxSIGSYS:
499 case wxSIGPIPE:
500 case wxSIGALRM:
501 case wxSIGTERM:
502 break;
503 }
504
505 if ( sig == 0 )
506 {
507 if ( wxProcess::Exists(pid) )
508 wxLogStatus(_T("Process %ld is running."), pid);
509 else
510 wxLogStatus(_T("No process with pid = %ld."), pid);
511 }
512 else // not SIGNONE
513 {
514 wxKillError rc = wxProcess::Kill(pid, (wxSignal)sig);
515 if ( rc == wxKILL_OK )
516 {
517 wxLogStatus(_T("Process %ld killed with signal %d."), pid, sig);
518 }
519 else
520 {
521 static const wxChar *errorText[] =
522 {
523 _T(""), // no error
524 _T("signal not supported"),
525 _T("permission denied"),
526 _T("no such process"),
527 _T("unspecified error"),
528 };
529
530 wxLogStatus(_T("Failed to kill process %ld with signal %d: %s"),
531 pid, sig, errorText[rc]);
532 }
533 }
534 }
535
536 // ----------------------------------------------------------------------------
537 // event handlers: exec menu
538 // ----------------------------------------------------------------------------
539
540 void MyFrame::DoAsyncExec(const wxString& cmd)
541 {
542 wxProcess *process = new MyProcess(this, cmd);
543 m_pidLast = wxExecute(cmd, wxEXEC_ASYNC, process);
544 if ( !m_pidLast )
545 {
546 wxLogError( _T("Execution of '%s' failed."), cmd.c_str() );
547
548 delete process;
549 }
550 else
551 {
552 wxLogStatus( _T("Process %ld (%s) launched."),
553 m_pidLast, cmd.c_str() );
554
555 m_cmdLast = cmd;
556 }
557 }
558
559 void MyFrame::OnSyncExec(wxCommandEvent& WXUNUSED(event))
560 {
561 wxString cmd = wxGetTextFromUser(_T("Enter the command: "),
562 DIALOG_TITLE,
563 m_cmdLast);
564
565 if ( !cmd )
566 return;
567
568 wxLogStatus( _T("'%s' is running please wait..."), cmd.c_str() );
569
570 int code = wxExecute(cmd, wxEXEC_SYNC);
571
572 wxLogStatus(_T("Process '%s' terminated with exit code %d."),
573 cmd.c_str(), code);
574
575 m_cmdLast = cmd;
576 }
577
578 void MyFrame::OnAsyncExec(wxCommandEvent& WXUNUSED(event))
579 {
580 wxString cmd = wxGetTextFromUser(_T("Enter the command: "),
581 DIALOG_TITLE,
582 m_cmdLast);
583
584 if ( !cmd )
585 return;
586
587 DoAsyncExec(cmd);
588 }
589
590 void MyFrame::OnShell(wxCommandEvent& WXUNUSED(event))
591 {
592 wxString cmd = wxGetTextFromUser(_T("Enter the command: "),
593 DIALOG_TITLE,
594 m_cmdLast);
595
596 if ( !cmd )
597 return;
598
599 int code = wxShell(cmd);
600 wxLogStatus(_T("Shell command '%s' terminated with exit code %d."),
601 cmd.c_str(), code);
602 m_cmdLast = cmd;
603 }
604
605 void MyFrame::OnExecWithRedirect(wxCommandEvent& WXUNUSED(event))
606 {
607 wxString cmd = wxGetTextFromUser(_T("Enter the command: "),
608 DIALOG_TITLE,
609 m_cmdLast);
610
611 if ( !cmd )
612 return;
613
614 bool sync;
615 switch ( wxMessageBox(_T("Execute it synchronously?"),
616 _T("Exec question"),
617 wxYES_NO | wxCANCEL | wxICON_QUESTION, this) )
618 {
619 case wxYES:
620 sync = TRUE;
621 break;
622
623 case wxNO:
624 sync = FALSE;
625 break;
626
627 default:
628 return;
629 }
630
631 if ( sync )
632 {
633 wxArrayString output, errors;
634 int code = wxExecute(cmd, output, errors);
635 wxLogStatus(_T("command '%s' terminated with exit code %d."),
636 cmd.c_str(), code);
637
638 if ( code != -1 )
639 {
640 ShowOutput(cmd, output, _T("Output"));
641 ShowOutput(cmd, errors, _T("Errors"));
642 }
643 }
644 else // async exec
645 {
646 MyPipedProcess *process = new MyPipedProcess(this, cmd);
647 if ( !wxExecute(cmd, wxEXEC_ASYNC, process) )
648 {
649 wxLogError(_T("Execution of '%s' failed."), cmd.c_str());
650
651 delete process;
652 }
653 else
654 {
655 m_running.Add(process);
656 }
657 }
658
659 m_cmdLast = cmd;
660 }
661
662 void MyFrame::OnExecWithPipe(wxCommandEvent& WXUNUSED(event))
663 {
664 if ( !m_cmdLast )
665 m_cmdLast = _T("tr [a-z] [A-Z]");
666
667 wxString cmd = wxGetTextFromUser(_T("Enter the command: "),
668 DIALOG_TITLE,
669 m_cmdLast);
670
671 if ( !cmd )
672 return;
673
674 wxString input = wxGetTextFromUser(_T("Enter the string to send to it: "),
675 DIALOG_TITLE);
676 if ( !input )
677 return;
678
679 // always execute the filter asynchronously
680 MyPipedProcess2 *process = new MyPipedProcess2(this, cmd, input);
681 long pid = wxExecute(cmd, wxEXEC_ASYNC, process);
682 if ( pid )
683 {
684 wxLogStatus( _T("Process %ld (%s) launched."), pid, cmd.c_str() );
685
686 m_running.Add(process);
687 }
688 else
689 {
690 wxLogError(_T("Execution of '%s' failed."), cmd.c_str());
691
692 delete process;
693 }
694
695 m_cmdLast = cmd;
696 }
697
698 void MyFrame::OnPOpen(wxCommandEvent& event)
699 {
700 wxString cmd = wxGetTextFromUser(_T("Enter the command to launch: "),
701 DIALOG_TITLE,
702 m_cmdLast);
703 if ( cmd.empty() )
704 return;
705
706 wxProcess *process = wxProcess::Open(cmd);
707 if ( !process )
708 {
709 wxLogError(_T("Failed to launch the command."));
710 return;
711 }
712
713 wxOutputStream *out = process->GetOutputStream();
714 if ( !out )
715 {
716 wxLogError(_T("Failed to connect to child stdin"));
717 return;
718 }
719
720 wxInputStream *in = process->GetInputStream();
721 if ( !in )
722 {
723 wxLogError(_T("Failed to connect to child stdout"));
724 return;
725 }
726
727 new MyPipeFrame(this, cmd, process);
728 }
729
730 void MyFrame::OnFileExec(wxCommandEvent& event)
731 {
732 static wxString s_filename;
733
734 wxString filename = wxLoadFileSelector(_T(""), _T(""), s_filename);
735 if ( !filename )
736 return;
737
738 s_filename = filename;
739
740 wxString ext = filename.AfterFirst(_T('.'));
741 wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(ext);
742 if ( !ft )
743 {
744 wxLogError(_T("Impossible to determine the file type for extension '%s'"),
745 ext.c_str());
746 return;
747 }
748
749 wxString cmd;
750 bool ok = ft->GetOpenCommand(&cmd,
751 wxFileType::MessageParameters(filename, _T("")));
752 delete ft;
753 if ( !ok )
754 {
755 wxLogError(_T("Impossible to find out how to open files of extension '%s'"),
756 ext.c_str());
757 return;
758 }
759
760 DoAsyncExec(cmd);
761 }
762
763 // ----------------------------------------------------------------------------
764 // DDE stuff
765 // ----------------------------------------------------------------------------
766
767 #ifdef __WINDOWS__
768
769 bool MyFrame::GetDDEServer()
770 {
771 wxString server = wxGetTextFromUser(_T("Server to connect to:"),
772 DIALOG_TITLE, m_server);
773 if ( !server )
774 return FALSE;
775
776 m_server = server;
777
778 wxString topic = wxGetTextFromUser(_T("DDE topic:"), DIALOG_TITLE, m_topic);
779 if ( !topic )
780 return FALSE;
781
782 m_topic = topic;
783
784 wxString cmd = wxGetTextFromUser(_T("DDE command:"), DIALOG_TITLE, m_cmdDde);
785 if ( !cmd )
786 return FALSE;
787
788 m_cmdDde = cmd;
789
790 return TRUE;
791 }
792
793 void MyFrame::OnDDEExec(wxCommandEvent& WXUNUSED(event))
794 {
795 if ( !GetDDEServer() )
796 return;
797
798 wxDDEClient client;
799 wxConnectionBase *conn = client.MakeConnection("", m_server, m_topic);
800 if ( !conn )
801 {
802 wxLogError(_T("Failed to connect to the DDE server '%s'."),
803 m_server.c_str());
804 }
805 else
806 {
807 if ( !conn->Execute(m_cmdDde) )
808 {
809 wxLogError(_T("Failed to execute command '%s' via DDE."),
810 m_cmdDde.c_str());
811 }
812 else
813 {
814 wxLogStatus(_T("Successfully executed DDE command"));
815 }
816 }
817 }
818
819 void MyFrame::OnDDERequest(wxCommandEvent& WXUNUSED(event))
820 {
821 if ( !GetDDEServer() )
822 return;
823
824 wxDDEClient client;
825 wxConnectionBase *conn = client.MakeConnection("", m_server, m_topic);
826 if ( !conn )
827 {
828 wxLogError(_T("Failed to connect to the DDE server '%s'."),
829 m_server.c_str());
830 }
831 else
832 {
833 if ( !conn->Request(m_cmdDde) )
834 {
835 wxLogError(_T("Failed to send request '%s' via DDE."),
836 m_cmdDde.c_str());
837 }
838 else
839 {
840 wxLogStatus(_T("Successfully sent DDE request."));
841 }
842 }
843 }
844
845 #endif // __WINDOWS__
846
847 // ----------------------------------------------------------------------------
848 // various helpers
849 // ----------------------------------------------------------------------------
850
851 // input polling
852 void MyFrame::OnIdle(wxIdleEvent& event)
853 {
854 size_t count = m_running.GetCount();
855 for ( size_t n = 0; n < count; n++ )
856 {
857 if ( m_running[n]->HasInput() )
858 {
859 event.RequestMore();
860 }
861 }
862 }
863
864 void MyFrame::OnProcessTerminated(MyPipedProcess *process)
865 {
866 m_running.Remove(process);
867 }
868
869
870 void MyFrame::ShowOutput(const wxString& cmd,
871 const wxArrayString& output,
872 const wxString& title)
873 {
874 size_t count = output.GetCount();
875 if ( !count )
876 return;
877
878 m_lbox->Append(wxString::Format(_T("--- %s of '%s' ---"),
879 title.c_str(), cmd.c_str()));
880
881 for ( size_t n = 0; n < count; n++ )
882 {
883 m_lbox->Append(output[n]);
884 }
885
886 m_lbox->Append(wxString::Format(_T("--- End of %s ---"),
887 title.Lower().c_str()));
888 }
889
890 // ----------------------------------------------------------------------------
891 // MyProcess
892 // ----------------------------------------------------------------------------
893
894 void MyProcess::OnTerminate(int pid, int status)
895 {
896 wxLogStatus(m_parent, _T("Process %u ('%s') terminated with exit code %d."),
897 pid, m_cmd.c_str(), status);
898
899 // we're not needed any more
900 delete this;
901 }
902
903 // ----------------------------------------------------------------------------
904 // MyPipedProcess
905 // ----------------------------------------------------------------------------
906
907 bool MyPipedProcess::HasInput()
908 {
909 bool hasInput = FALSE;
910
911 wxInputStream& is = *GetInputStream();
912 if ( !is.Eof() )
913 {
914 wxTextInputStream tis(is);
915
916 // this assumes that the output is always line buffered
917 wxString msg;
918 msg << m_cmd << _T(" (stdout): ") << tis.ReadLine();
919
920 m_parent->GetLogListBox()->Append(msg);
921
922 hasInput = TRUE;
923 }
924
925 wxInputStream& es = *GetErrorStream();
926 if ( !es.Eof() )
927 {
928 wxTextInputStream tis(es);
929
930 // this assumes that the output is always line buffered
931 wxString msg;
932 msg << m_cmd << _T(" (stderr): ") << tis.ReadLine();
933
934 m_parent->GetLogListBox()->Append(msg);
935
936 hasInput = TRUE;
937 }
938
939 return hasInput;
940 }
941
942 void MyPipedProcess::OnTerminate(int pid, int status)
943 {
944 // show the rest of the output
945 while ( HasInput() )
946 ;
947
948 m_parent->OnProcessTerminated(this);
949
950 MyProcess::OnTerminate(pid, status);
951 }
952
953 // ----------------------------------------------------------------------------
954 // MyPipedProcess2
955 // ----------------------------------------------------------------------------
956
957 bool MyPipedProcess2::HasInput()
958 {
959 if ( !!m_input )
960 {
961 wxTextOutputStream os(*GetOutputStream());
962 os.WriteString(m_input);
963
964 CloseOutput();
965 m_input.clear();
966
967 // call us once again - may be we'll have output
968 return TRUE;
969 }
970
971 return MyPipedProcess::HasInput();
972 }
973
974 // ============================================================================
975 // MyPipeFrame implementation
976 // ============================================================================
977
978 MyPipeFrame::MyPipeFrame(wxFrame *parent,
979 const wxString& cmd,
980 wxProcess *process)
981 : wxFrame(parent, -1, cmd),
982 m_process(process),
983 // in a real program we'd check that the streams are !NULL here
984 m_in(*process->GetInputStream()),
985 m_out(*process->GetOutputStream())
986 {
987 m_textIn = new wxTextCtrl(this, -1, _T(""),
988 wxDefaultPosition, wxDefaultSize,
989 wxTE_PROCESS_ENTER);
990 m_textOut = new wxTextCtrl(this, -1, _T(""));
991 m_textOut->SetEditable(FALSE);
992
993 wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL);
994 sizerTop->Add(m_textIn, 0, wxGROW | wxALL, 5);
995
996 wxSizer *sizerBtns = new wxBoxSizer(wxHORIZONTAL);
997 sizerBtns->Add(new wxButton(this, Exec_Btn_Send, _T("&Send")), 0,
998 wxALL, 10);
999 sizerBtns->Add(new wxButton(this, Exec_Btn_Get, _T("&Get")), 0,
1000 wxALL, 10);
1001
1002 sizerTop->Add(sizerBtns, 0, wxCENTRE | wxALL, 5);
1003 sizerTop->Add(m_textOut, 0, wxGROW | wxALL, 5);
1004
1005 SetSizer(sizerTop);
1006 sizerTop->Fit(this);
1007
1008 Show();
1009 }
1010
1011 void MyPipeFrame::DoGet()
1012 {
1013 m_textOut->SetValue(m_in.ReadLine());
1014 }
1015
1016 void MyPipeFrame::OnClose(wxCloseEvent& event)
1017 {
1018 m_process->CloseOutput();
1019
1020 event.Skip();
1021 }
1022