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