added a stupid wxProcess::Open() test -- it can't be really used for now though
[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 int 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 %d is running."), pid);
509 else
510 wxLogStatus(_T("No process with pid = %d."), 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 %d 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 %d 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."), m_pidLast, cmd.c_str());
553
554 m_cmdLast = cmd;
555 }
556 }
557
558 void MyFrame::OnSyncExec(wxCommandEvent& WXUNUSED(event))
559 {
560 wxString cmd = wxGetTextFromUser(_T("Enter the command: "),
561 DIALOG_TITLE,
562 m_cmdLast);
563
564 if ( !cmd )
565 return;
566
567 wxLogStatus(_T("'%s' is running please wait..."), cmd.c_str());
568
569 int code = wxExecute(cmd, wxEXEC_SYNC);
570
571 wxLogStatus(_T("Process '%s' terminated with exit code %d."),
572 cmd.c_str(), code);
573 m_cmdLast = cmd;
574 }
575
576 void MyFrame::OnAsyncExec(wxCommandEvent& WXUNUSED(event))
577 {
578 wxString cmd = wxGetTextFromUser(_T("Enter the command: "),
579 DIALOG_TITLE,
580 m_cmdLast);
581
582 if ( !cmd )
583 return;
584
585 DoAsyncExec(cmd);
586 }
587
588 void MyFrame::OnShell(wxCommandEvent& WXUNUSED(event))
589 {
590 wxString cmd = wxGetTextFromUser(_T("Enter the command: "),
591 DIALOG_TITLE,
592 m_cmdLast);
593
594 if ( !cmd )
595 return;
596
597 int code = wxShell(cmd);
598 wxLogStatus(_T("Shell command '%s' terminated with exit code %d."),
599 cmd.c_str(), code);
600 m_cmdLast = cmd;
601 }
602
603 void MyFrame::OnExecWithRedirect(wxCommandEvent& WXUNUSED(event))
604 {
605 wxString cmd = wxGetTextFromUser(_T("Enter the command: "),
606 DIALOG_TITLE,
607 m_cmdLast);
608
609 if ( !cmd )
610 return;
611
612 bool sync;
613 switch ( wxMessageBox(_T("Execute it synchronously?"),
614 _T("Exec question"),
615 wxYES_NO | wxCANCEL | wxICON_QUESTION, this) )
616 {
617 case wxYES:
618 sync = TRUE;
619 break;
620
621 case wxNO:
622 sync = FALSE;
623 break;
624
625 default:
626 return;
627 }
628
629 if ( sync )
630 {
631 wxArrayString output, errors;
632 int code = wxExecute(cmd, output, errors);
633 wxLogStatus(_T("command '%s' terminated with exit code %d."),
634 cmd.c_str(), code);
635
636 if ( code != -1 )
637 {
638 ShowOutput(cmd, output, _T("Output"));
639 ShowOutput(cmd, errors, _T("Errors"));
640 }
641 }
642 else // async exec
643 {
644 MyPipedProcess *process = new MyPipedProcess(this, cmd);
645 if ( !wxExecute(cmd, wxEXEC_ASYNC, process) )
646 {
647 wxLogError(_T("Execution of '%s' failed."), cmd.c_str());
648
649 delete process;
650 }
651 else
652 {
653 m_running.Add(process);
654 }
655 }
656
657 m_cmdLast = cmd;
658 }
659
660 void MyFrame::OnExecWithPipe(wxCommandEvent& WXUNUSED(event))
661 {
662 if ( !m_cmdLast )
663 m_cmdLast = _T("tr [a-z] [A-Z]");
664
665 wxString cmd = wxGetTextFromUser(_T("Enter the command: "),
666 DIALOG_TITLE,
667 m_cmdLast);
668
669 if ( !cmd )
670 return;
671
672 wxString input = wxGetTextFromUser(_T("Enter the string to send to it: "),
673 DIALOG_TITLE);
674 if ( !input )
675 return;
676
677 // always execute the filter asynchronously
678 MyPipedProcess2 *process = new MyPipedProcess2(this, cmd, input);
679 int pid = wxExecute(cmd, wxEXEC_ASYNC, process);
680 if ( pid )
681 {
682 wxLogStatus(_T("Process %ld (%s) launched."), pid, cmd.c_str());
683
684 m_running.Add(process);
685 }
686 else
687 {
688 wxLogError(_T("Execution of '%s' failed."), cmd.c_str());
689
690 delete process;
691 }
692
693 m_cmdLast = cmd;
694 }
695
696 void MyFrame::OnPOpen(wxCommandEvent& event)
697 {
698 wxString cmd = wxGetTextFromUser(_T("Enter the command to launch: "),
699 DIALOG_TITLE,
700 m_cmdLast);
701 if ( cmd.empty() )
702 return;
703
704 wxProcess *process = wxProcess::Open(cmd);
705 if ( !process )
706 {
707 wxLogError(_T("Failed to launch the command."));
708 return;
709 }
710
711 wxOutputStream *out = process->GetOutputStream();
712 if ( !out )
713 {
714 wxLogError(_T("Failed to connect to child stdin"));
715 return;
716 }
717
718 wxInputStream *in = process->GetInputStream();
719 if ( !in )
720 {
721 wxLogError(_T("Failed to connect to child stdout"));
722 return;
723 }
724
725 new MyPipeFrame(this, cmd, process);
726 }
727
728 void MyFrame::OnFileExec(wxCommandEvent& event)
729 {
730 static wxString s_filename;
731
732 wxString filename = wxLoadFileSelector(_T(""), _T(""), s_filename);
733 if ( !filename )
734 return;
735
736 s_filename = filename;
737
738 wxString ext = filename.AfterFirst(_T('.'));
739 wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(ext);
740 if ( !ft )
741 {
742 wxLogError(_T("Impossible to determine the file type for extension '%s'"),
743 ext.c_str());
744 return;
745 }
746
747 wxString cmd;
748 bool ok = ft->GetOpenCommand(&cmd,
749 wxFileType::MessageParameters(filename, _T("")));
750 delete ft;
751 if ( !ok )
752 {
753 wxLogError(_T("Impossible to find out how to open files of extension '%s'"),
754 ext.c_str());
755 return;
756 }
757
758 DoAsyncExec(cmd);
759 }
760
761 // ----------------------------------------------------------------------------
762 // DDE stuff
763 // ----------------------------------------------------------------------------
764
765 #ifdef __WINDOWS__
766
767 bool MyFrame::GetDDEServer()
768 {
769 wxString server = wxGetTextFromUser(_T("Server to connect to:"),
770 DIALOG_TITLE, m_server);
771 if ( !server )
772 return FALSE;
773
774 m_server = server;
775
776 wxString topic = wxGetTextFromUser(_T("DDE topic:"), DIALOG_TITLE, m_topic);
777 if ( !topic )
778 return FALSE;
779
780 m_topic = topic;
781
782 wxString cmd = wxGetTextFromUser(_T("DDE command:"), DIALOG_TITLE, m_cmdDde);
783 if ( !cmd )
784 return FALSE;
785
786 m_cmdDde = cmd;
787
788 return TRUE;
789 }
790
791 void MyFrame::OnDDEExec(wxCommandEvent& WXUNUSED(event))
792 {
793 if ( !GetDDEServer() )
794 return;
795
796 wxDDEClient client;
797 wxConnectionBase *conn = client.MakeConnection("", m_server, m_topic);
798 if ( !conn )
799 {
800 wxLogError(_T("Failed to connect to the DDE server '%s'."),
801 m_server.c_str());
802 }
803 else
804 {
805 if ( !conn->Execute(m_cmdDde) )
806 {
807 wxLogError(_T("Failed to execute command '%s' via DDE."),
808 m_cmdDde.c_str());
809 }
810 else
811 {
812 wxLogStatus(_T("Successfully executed DDE command"));
813 }
814 }
815 }
816
817 void MyFrame::OnDDERequest(wxCommandEvent& WXUNUSED(event))
818 {
819 if ( !GetDDEServer() )
820 return;
821
822 wxDDEClient client;
823 wxConnectionBase *conn = client.MakeConnection("", m_server, m_topic);
824 if ( !conn )
825 {
826 wxLogError(_T("Failed to connect to the DDE server '%s'."),
827 m_server.c_str());
828 }
829 else
830 {
831 if ( !conn->Request(m_cmdDde) )
832 {
833 wxLogError(_T("Failed to send request '%s' via DDE."),
834 m_cmdDde.c_str());
835 }
836 else
837 {
838 wxLogStatus(_T("Successfully sent DDE request."));
839 }
840 }
841 }
842
843 #endif // __WINDOWS__
844
845 // ----------------------------------------------------------------------------
846 // various helpers
847 // ----------------------------------------------------------------------------
848
849 // input polling
850 void MyFrame::OnIdle(wxIdleEvent& event)
851 {
852 size_t count = m_running.GetCount();
853 for ( size_t n = 0; n < count; n++ )
854 {
855 if ( m_running[n]->HasInput() )
856 {
857 event.RequestMore();
858 }
859 }
860 }
861
862 void MyFrame::OnProcessTerminated(MyPipedProcess *process)
863 {
864 m_running.Remove(process);
865 }
866
867
868 void MyFrame::ShowOutput(const wxString& cmd,
869 const wxArrayString& output,
870 const wxString& title)
871 {
872 size_t count = output.GetCount();
873 if ( !count )
874 return;
875
876 m_lbox->Append(wxString::Format(_T("--- %s of '%s' ---"),
877 title.c_str(), cmd.c_str()));
878
879 for ( size_t n = 0; n < count; n++ )
880 {
881 m_lbox->Append(output[n]);
882 }
883
884 m_lbox->Append(wxString::Format(_T("--- End of %s ---"),
885 title.Lower().c_str()));
886 }
887
888 // ----------------------------------------------------------------------------
889 // MyProcess
890 // ----------------------------------------------------------------------------
891
892 void MyProcess::OnTerminate(int pid, int status)
893 {
894 wxLogStatus(m_parent, _T("Process %u ('%s') terminated with exit code %d."),
895 pid, m_cmd.c_str(), status);
896
897 // we're not needed any more
898 delete this;
899 }
900
901 // ----------------------------------------------------------------------------
902 // MyPipedProcess
903 // ----------------------------------------------------------------------------
904
905 bool MyPipedProcess::HasInput()
906 {
907 bool hasInput = FALSE;
908
909 wxInputStream& is = *GetInputStream();
910 if ( !is.Eof() )
911 {
912 wxTextInputStream tis(is);
913
914 // this assumes that the output is always line buffered
915 wxString msg;
916 msg << m_cmd << _T(" (stdout): ") << tis.ReadLine();
917
918 m_parent->GetLogListBox()->Append(msg);
919
920 hasInput = TRUE;
921 }
922
923 wxInputStream& es = *GetErrorStream();
924 if ( !es.Eof() )
925 {
926 wxTextInputStream tis(es);
927
928 // this assumes that the output is always line buffered
929 wxString msg;
930 msg << m_cmd << _T(" (stderr): ") << tis.ReadLine();
931
932 m_parent->GetLogListBox()->Append(msg);
933
934 hasInput = TRUE;
935 }
936
937 return hasInput;
938 }
939
940 void MyPipedProcess::OnTerminate(int pid, int status)
941 {
942 // show the rest of the output
943 while ( HasInput() )
944 ;
945
946 m_parent->OnProcessTerminated(this);
947
948 MyProcess::OnTerminate(pid, status);
949 }
950
951 // ----------------------------------------------------------------------------
952 // MyPipedProcess2
953 // ----------------------------------------------------------------------------
954
955 bool MyPipedProcess2::HasInput()
956 {
957 if ( !!m_input )
958 {
959 wxTextOutputStream os(*GetOutputStream());
960 os.WriteString(m_input);
961
962 CloseOutput();
963 m_input.clear();
964
965 // call us once again - may be we'll have output
966 return TRUE;
967 }
968
969 return MyPipedProcess::HasInput();
970 }
971
972 // ============================================================================
973 // MyPipeFrame implementation
974 // ============================================================================
975
976 MyPipeFrame::MyPipeFrame(wxFrame *parent,
977 const wxString& cmd,
978 wxProcess *process)
979 : wxFrame(parent, -1, cmd),
980 m_process(process),
981 // in a real program we'd check that the streams are !NULL here
982 m_in(*process->GetInputStream()),
983 m_out(*process->GetOutputStream())
984 {
985 m_textIn = new wxTextCtrl(this, -1, _T(""),
986 wxDefaultPosition, wxDefaultSize,
987 wxTE_PROCESS_ENTER);
988 m_textOut = new wxTextCtrl(this, -1, _T(""));
989 m_textOut->SetEditable(FALSE);
990
991 wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL);
992 sizerTop->Add(m_textIn, 0, wxGROW | wxALL, 5);
993
994 wxSizer *sizerBtns = new wxBoxSizer(wxHORIZONTAL);
995 sizerBtns->Add(new wxButton(this, Exec_Btn_Send, _T("&Send")), 0,
996 wxALL, 10);
997 sizerBtns->Add(new wxButton(this, Exec_Btn_Get, _T("&Get")), 0,
998 wxALL, 10);
999
1000 sizerTop->Add(sizerBtns, 0, wxCENTRE | wxALL, 5);
1001 sizerTop->Add(m_textOut, 0, wxGROW | wxALL, 5);
1002
1003 SetSizer(sizerTop);
1004 sizerTop->Fit(this);
1005
1006 Show();
1007 }
1008
1009 void MyPipeFrame::DoGet()
1010 {
1011 m_textOut->SetValue(m_in.ReadLine());
1012 }
1013
1014 void MyPipeFrame::OnClose(wxCloseEvent& event)
1015 {
1016 m_process->CloseOutput();
1017
1018 event.Skip();
1019 }
1020