]> git.saurik.com Git - wxWidgets.git/blob - samples/exec/exec.cpp
1. some more tests in console
[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 #endif
43
44 #include "wx/txtstrm.h"
45
46 #include "wx/process.h"
47
48 #include "wx/mimetype.h"
49
50 #ifdef __WINDOWS__
51 #include "wx/dde.h"
52 #endif // __WINDOWS__
53
54 // ----------------------------------------------------------------------------
55 // private classes
56 // ----------------------------------------------------------------------------
57
58 // Define a new application type, each program should derive a class from wxApp
59 class MyApp : public wxApp
60 {
61 public:
62 // override base class virtuals
63 // ----------------------------
64
65 // this one is called on application startup and is a good place for the app
66 // initialization (doing it here and not in the ctor allows to have an error
67 // return: if OnInit() returns false, the application terminates)
68 virtual bool OnInit();
69 };
70
71 // Define an array of process pointers used by MyFrame
72 class MyPipedProcess;
73 WX_DEFINE_ARRAY(MyPipedProcess *, MyProcessesArray);
74
75 // Define a new frame type: this is going to be our main frame
76 class MyFrame : public wxFrame
77 {
78 public:
79 // ctor(s)
80 MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size);
81
82 // event handlers (these functions should _not_ be virtual)
83 void OnQuit(wxCommandEvent& event);
84
85 void OnClear(wxCommandEvent& event);
86
87 void OnSyncExec(wxCommandEvent& event);
88 void OnAsyncExec(wxCommandEvent& event);
89 void OnShell(wxCommandEvent& event);
90 void OnExecWithRedirect(wxCommandEvent& event);
91 void OnExecWithPipe(wxCommandEvent& event);
92
93 void OnFileExec(wxCommandEvent& event);
94
95 void OnDDEExec(wxCommandEvent& event);
96
97 void OnAbout(wxCommandEvent& event);
98
99 // polling output of async processes
100 void OnIdle(wxIdleEvent& event);
101
102 // for MyPipedProcess
103 void OnProcessTerminated(MyPipedProcess *process);
104 wxListBox *GetLogListBox() const { return m_lbox; }
105
106 private:
107 void ShowOutput(const wxString& cmd,
108 const wxArrayString& output,
109 const wxString& title);
110
111 void DoAsyncExec(const wxString& cmd);
112
113 wxString m_cmdLast;
114
115 wxListBox *m_lbox;
116
117 MyProcessesArray m_running;
118
119 // any class wishing to process wxWindows events must use this macro
120 DECLARE_EVENT_TABLE()
121 };
122
123 // This is the handler for process termination events
124 class MyProcess : public wxProcess
125 {
126 public:
127 MyProcess(MyFrame *parent, const wxString& cmd)
128 : wxProcess(parent), m_cmd(cmd)
129 {
130 m_parent = parent;
131 }
132
133 // instead of overriding this virtual function we might as well process the
134 // event from it in the frame class - this might be more convenient in some
135 // cases
136 virtual void OnTerminate(int pid, int status);
137
138 protected:
139 MyFrame *m_parent;
140 wxString m_cmd;
141 };
142
143 // A specialization of MyProcess for redirecting the output
144 class MyPipedProcess : public MyProcess
145 {
146 public:
147 MyPipedProcess(MyFrame *parent, const wxString& cmd)
148 : MyProcess(parent, cmd)
149 {
150 Redirect();
151 }
152
153 virtual void OnTerminate(int pid, int status);
154
155 virtual bool HasInput();
156 };
157
158 // A version of MyPipedProcess which also sends input to the stdin of the
159 // child process
160 class MyPipedProcess2 : public MyPipedProcess
161 {
162 public:
163 MyPipedProcess2(MyFrame *parent, const wxString& cmd, const wxString& input)
164 : MyPipedProcess(parent, cmd), m_input(input)
165 {
166 }
167
168 virtual bool HasInput();
169
170 private:
171 wxString m_input;
172 };
173
174 // ----------------------------------------------------------------------------
175 // constants
176 // ----------------------------------------------------------------------------
177
178 // IDs for the controls and the menu commands
179 enum
180 {
181 // menu items
182 Exec_Quit = 100,
183 Exec_ClearLog,
184 Exec_SyncExec = 200,
185 Exec_AsyncExec,
186 Exec_Shell,
187 Exec_OpenFile,
188 Exec_DDEExec,
189 Exec_Redirect,
190 Exec_Pipe,
191 Exec_About = 300
192 };
193
194 static const wxChar *DIALOG_TITLE = _T("Exec sample");
195
196 // ----------------------------------------------------------------------------
197 // event tables and other macros for wxWindows
198 // ----------------------------------------------------------------------------
199
200 // the event tables connect the wxWindows events with the functions (event
201 // handlers) which process them. It can be also done at run-time, but for the
202 // simple menu events like this the static method is much simpler.
203 BEGIN_EVENT_TABLE(MyFrame, wxFrame)
204 EVT_MENU(Exec_Quit, MyFrame::OnQuit)
205 EVT_MENU(Exec_ClearLog, MyFrame::OnClear)
206
207 EVT_MENU(Exec_SyncExec, MyFrame::OnSyncExec)
208 EVT_MENU(Exec_AsyncExec, MyFrame::OnAsyncExec)
209 EVT_MENU(Exec_Shell, MyFrame::OnShell)
210 EVT_MENU(Exec_Redirect, MyFrame::OnExecWithRedirect)
211 EVT_MENU(Exec_Pipe, MyFrame::OnExecWithPipe)
212
213 EVT_MENU(Exec_OpenFile, MyFrame::OnFileExec)
214
215 EVT_MENU(Exec_DDEExec, MyFrame::OnDDEExec)
216
217 EVT_MENU(Exec_About, MyFrame::OnAbout)
218
219 EVT_IDLE(MyFrame::OnIdle)
220 END_EVENT_TABLE()
221
222 // Create a new application object: this macro will allow wxWindows to create
223 // the application object during program execution (it's better than using a
224 // static object for many reasons) and also declares the accessor function
225 // wxGetApp() which will return the reference of the right type (i.e. MyApp and
226 // not wxApp)
227 IMPLEMENT_APP(MyApp)
228
229 // ============================================================================
230 // implementation
231 // ============================================================================
232
233 // ----------------------------------------------------------------------------
234 // the application class
235 // ----------------------------------------------------------------------------
236
237 // `Main program' equivalent: the program execution "starts" here
238 bool MyApp::OnInit()
239 {
240 // Create the main application window
241 MyFrame *frame = new MyFrame(_T("Exec wxWindows sample"),
242 wxDefaultPosition, wxSize(500, 140));
243
244 // Show it and tell the application that it's our main window
245 frame->Show(TRUE);
246 SetTopWindow(frame);
247
248 // success: wxApp::OnRun() will be called which will enter the main message
249 // loop and the application will run. If we returned FALSE here, the
250 // application would exit immediately.
251 return TRUE;
252 }
253
254 // ----------------------------------------------------------------------------
255 // main frame
256 // ----------------------------------------------------------------------------
257
258 // frame constructor
259 MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
260 : wxFrame((wxFrame *)NULL, -1, title, pos, size)
261 {
262 #ifdef __WXMAC__
263 // we need this in order to allow the about menu relocation, since ABOUT is
264 // not the default id of the about menu
265 wxApp::s_macAboutMenuItemId = Exec_About;
266 #endif
267
268 // create a menu bar
269 wxMenu *menuFile = new wxMenu(_T(""), wxMENU_TEAROFF);
270 menuFile->Append(Exec_ClearLog, _T("&Clear log\tCtrl-C"),
271 _T("Clear the log window"));
272 menuFile->AppendSeparator();
273 menuFile->Append(Exec_Quit, _T("E&xit\tAlt-X"), _T("Quit this program"));
274
275 wxMenu *execMenu = new wxMenu;
276 execMenu->Append(Exec_SyncExec, _T("Sync &execution...\tCtrl-E"),
277 _T("Launch a program and return when it terminates"));
278 execMenu->Append(Exec_AsyncExec, _T("&Async execution...\tCtrl-A"),
279 _T("Launch a program and return immediately"));
280 execMenu->Append(Exec_Shell, _T("Execute &shell command...\tCtrl-S"),
281 _T("Launch a shell and execute a command in it"));
282 execMenu->AppendSeparator();
283 execMenu->Append(Exec_Redirect, _T("Capture command &output...\tCtrl-O"),
284 _T("Launch a program and capture its output"));
285 execMenu->Append(Exec_Pipe, _T("&Pipe through command...\tCtrl-P"),
286 _T("Pipe a string through a filter"));
287
288 execMenu->AppendSeparator();
289 execMenu->Append(Exec_OpenFile, _T("Open &file...\tCtrl-F"),
290 _T("Launch the command to open this kind of files"));
291 #ifdef __WINDOWS__
292 execMenu->AppendSeparator();
293 execMenu->Append(Exec_DDEExec, _T("Execute command via &DDE...\tCtrl-D"));
294 #endif
295
296 wxMenu *helpMenu = new wxMenu(_T(""), wxMENU_TEAROFF);
297 helpMenu->Append(Exec_About, _T("&About...\tF1"), _T("Show about dialog"));
298
299 // now append the freshly created menu to the menu bar...
300 wxMenuBar *menuBar = new wxMenuBar();
301 menuBar->Append(menuFile, _T("&File"));
302 menuBar->Append(execMenu, _T("&Exec"));
303 menuBar->Append(helpMenu, _T("&Help"));
304
305 // ... and attach this menu bar to the frame
306 SetMenuBar(menuBar);
307
308 // create the listbox in which we will show misc messages as they come
309 m_lbox = new wxListBox(this, -1);
310
311 #if wxUSE_STATUSBAR
312 // create a status bar just for fun (by default with 1 pane only)
313 CreateStatusBar();
314 SetStatusText(_T("Welcome to wxWindows exec sample!"));
315 #endif // wxUSE_STATUSBAR
316 }
317
318
319 // event handlers
320
321 void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
322 {
323 // TRUE is to force the frame to close
324 Close(TRUE);
325 }
326
327 void MyFrame::OnClear(wxCommandEvent& WXUNUSED(event))
328 {
329 m_lbox->Clear();
330 }
331
332 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
333 {
334 wxMessageBox(_T("Exec sample\n© 2000 Vadim Zeitlin"),
335 _T("About Exec"), wxOK | wxICON_INFORMATION, this);
336 }
337
338 void MyFrame::DoAsyncExec(const wxString& cmd)
339 {
340 wxProcess *process = new MyProcess(this, cmd);
341 long pid = wxExecute(cmd, FALSE /* async */, process);
342 if ( !pid )
343 {
344 wxLogError(_T("Execution of '%s' failed."), cmd.c_str());
345
346 delete process;
347 }
348 else
349 {
350 wxLogStatus(_T("Process %ld (%s) launched."), pid, cmd.c_str());
351
352 m_cmdLast = cmd;
353 }
354 }
355
356 void MyFrame::OnSyncExec(wxCommandEvent& WXUNUSED(event))
357 {
358 wxString cmd = wxGetTextFromUser(_T("Enter the command: "),
359 DIALOG_TITLE,
360 m_cmdLast);
361
362 if ( !cmd )
363 return;
364
365 wxLogStatus(_T("'%s' is running please wait..."), cmd.c_str());
366
367 int code = wxExecute(cmd, TRUE /* sync */);
368
369 wxLogStatus(_T("Process '%s' terminated with exit code %d."),
370 cmd.c_str(), code);
371 m_cmdLast = cmd;
372 }
373
374 void MyFrame::OnAsyncExec(wxCommandEvent& WXUNUSED(event))
375 {
376 wxString cmd = wxGetTextFromUser(_T("Enter the command: "),
377 DIALOG_TITLE,
378 m_cmdLast);
379
380 if ( !cmd )
381 return;
382
383 DoAsyncExec(cmd);
384 }
385
386 void MyFrame::OnShell(wxCommandEvent& WXUNUSED(event))
387 {
388 wxString cmd = wxGetTextFromUser(_T("Enter the command: "),
389 DIALOG_TITLE,
390 m_cmdLast);
391
392 if ( !cmd )
393 return;
394
395 int code = wxShell(cmd);
396 wxLogStatus(_T("Shell command '%s' terminated with exit code %d."),
397 cmd.c_str(), code);
398 m_cmdLast = cmd;
399 }
400
401 void MyFrame::OnExecWithRedirect(wxCommandEvent& WXUNUSED(event))
402 {
403 wxString cmd = wxGetTextFromUser(_T("Enter the command: "),
404 DIALOG_TITLE,
405 m_cmdLast);
406
407 if ( !cmd )
408 return;
409
410 bool sync;
411 switch ( wxMessageBox(_T("Execute it synchronously?"),
412 _T("Exec question"),
413 wxYES_NO | wxCANCEL | wxICON_QUESTION, this) )
414 {
415 case wxYES:
416 sync = TRUE;
417 break;
418
419 case wxNO:
420 sync = FALSE;
421 break;
422
423 default:
424 return;
425 }
426
427 if ( sync )
428 {
429 wxArrayString output, errors;
430 int code = wxExecute(cmd, output, errors);
431 wxLogStatus(_T("command '%s' terminated with exit code %d."),
432 cmd.c_str(), code);
433
434 if ( code != -1 )
435 {
436 ShowOutput(cmd, output, _T("Output"));
437 ShowOutput(cmd, errors, _T("Errors"));
438 }
439 }
440 else // async exec
441 {
442 MyPipedProcess *process = new MyPipedProcess(this, cmd);
443 if ( !wxExecute(cmd, FALSE /* async */, process) )
444 {
445 wxLogError(_T("Execution of '%s' failed."), cmd.c_str());
446
447 delete process;
448 }
449 else
450 {
451 m_running.Add(process);
452 }
453 }
454
455 m_cmdLast = cmd;
456 }
457
458 void MyFrame::OnExecWithPipe(wxCommandEvent& WXUNUSED(event))
459 {
460 if ( !m_cmdLast )
461 m_cmdLast = _T("tr [a-z] [A-Z]");
462
463 wxString cmd = wxGetTextFromUser(_T("Enter the command: "),
464 DIALOG_TITLE,
465 m_cmdLast);
466
467 if ( !cmd )
468 return;
469
470 wxString input = wxGetTextFromUser(_T("Enter the string to send to it: "),
471 DIALOG_TITLE);
472 if ( !input )
473 return;
474
475 // always execute the filter asynchronously
476 MyPipedProcess2 *process = new MyPipedProcess2(this, cmd, input);
477 int pid = wxExecute(cmd, FALSE /* async */, process);
478 if ( pid )
479 {
480 wxLogStatus(_T("Process %ld (%s) launched."), pid, cmd.c_str());
481
482 m_running.Add(process);
483 }
484 else
485 {
486 wxLogError(_T("Execution of '%s' failed."), cmd.c_str());
487
488 delete process;
489 }
490
491 m_cmdLast = cmd;
492 }
493
494 void MyFrame::OnFileExec(wxCommandEvent& event)
495 {
496 static wxString s_filename;
497
498 wxString filename = wxLoadFileSelector(_T("file"), _T(""), s_filename);
499 if ( !filename )
500 return;
501
502 s_filename = filename;
503
504 wxString ext = filename.AfterFirst(_T('.'));
505 wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(ext);
506 if ( !ft )
507 {
508 wxLogError(_T("Impossible to determine the file type for extension '%s'"),
509 ext.c_str());
510 return;
511 }
512
513 wxString cmd;
514 bool ok = ft->GetOpenCommand(&cmd,
515 wxFileType::MessageParameters(filename, _T("")));
516 delete ft;
517 if ( !ok )
518 {
519 wxLogError(_T("Impossible to find out how to open files of extension '%s'"),
520 ext.c_str());
521 return;
522 }
523
524 DoAsyncExec(cmd);
525 }
526
527 void MyFrame::OnDDEExec(wxCommandEvent& WXUNUSED(event))
528 {
529 #ifdef __WINDOWS__
530 wxString server = wxGetTextFromUser(_T("Server to connect to:"),
531 DIALOG_TITLE, _T("IExplore"));
532 if ( !server )
533 return;
534
535 wxString topic = wxGetTextFromUser(_T("DDE topic:"),
536 DIALOG_TITLE, _T("WWW_OpenURL"));
537 if ( !topic )
538 return;
539
540 wxString cmd = wxGetTextFromUser(_T("DDE command:"),
541 DIALOG_TITLE,
542 _T("\"file:F:\\wxWindows\\samples\\"
543 "image\\horse.gif\",,-1,,,,,"));
544 if ( !cmd )
545 return;
546
547 wxDDEClient client;
548 wxConnectionBase *conn = client.MakeConnection("", server, topic);
549 if ( !conn )
550 {
551 wxLogError(_T("Failed to connect to the DDE server '%s'."),
552 server.c_str());
553 }
554 else
555 {
556 if ( !conn->Execute(cmd) )
557 {
558 wxLogError(_T("Failed to execute command '%s' via DDE."),
559 cmd.c_str());
560 }
561 else
562 {
563 wxLogStatus(_T("Successfully executed DDE command"));
564 }
565 }
566 #endif // __WINDOWS__
567 }
568
569 // input polling
570 void MyFrame::OnIdle(wxIdleEvent& event)
571 {
572 size_t count = m_running.GetCount();
573 for ( size_t n = 0; n < count; n++ )
574 {
575 if ( m_running[n]->HasInput() )
576 {
577 event.RequestMore();
578 }
579 }
580 }
581
582 void MyFrame::OnProcessTerminated(MyPipedProcess *process)
583 {
584 m_running.Remove(process);
585 }
586
587
588 void MyFrame::ShowOutput(const wxString& cmd,
589 const wxArrayString& output,
590 const wxString& title)
591 {
592 size_t count = output.GetCount();
593 if ( !count )
594 return;
595
596 m_lbox->Append(wxString::Format(_T("--- %s of '%s' ---"),
597 title.c_str(), cmd.c_str()));
598
599 for ( size_t n = 0; n < count; n++ )
600 {
601 m_lbox->Append(output[n]);
602 }
603
604 m_lbox->Append(_T("--- End of output ---"));
605 }
606
607 // ----------------------------------------------------------------------------
608 // MyProcess
609 // ----------------------------------------------------------------------------
610
611 void MyProcess::OnTerminate(int pid, int status)
612 {
613 wxLogStatus(m_parent, _T("Process %u ('%s') terminated with exit code %d."),
614 pid, m_cmd.c_str(), status);
615
616 // we're not needed any more
617 delete this;
618 }
619
620 // ----------------------------------------------------------------------------
621 // MyPipedProcess
622 // ----------------------------------------------------------------------------
623
624 bool MyPipedProcess::HasInput()
625 {
626 bool hasInput = FALSE;
627
628 wxInputStream& is = *GetInputStream();
629 if ( !is.Eof() )
630 {
631 wxTextInputStream tis(is);
632
633 // this assumes that the output is always line buffered
634 wxString msg;
635 msg << m_cmd << _T(" (stdout): ") << tis.ReadLine();
636
637 m_parent->GetLogListBox()->Append(msg);
638
639 hasInput = TRUE;
640 }
641
642 wxInputStream& es = *GetErrorStream();
643 if ( !es.Eof() )
644 {
645 wxTextInputStream tis(es);
646
647 // this assumes that the output is always line buffered
648 wxString msg;
649 msg << m_cmd << _T(" (stderr): ") << tis.ReadLine();
650
651 m_parent->GetLogListBox()->Append(msg);
652
653 hasInput = TRUE;
654 }
655
656 return hasInput;
657 }
658
659 void MyPipedProcess::OnTerminate(int pid, int status)
660 {
661 // show the rest of the output
662 while ( HasInput() )
663 ;
664
665 m_parent->OnProcessTerminated(this);
666
667 MyProcess::OnTerminate(pid, status);
668 }
669
670 // ----------------------------------------------------------------------------
671 // MyPipedProcess2
672 // ----------------------------------------------------------------------------
673
674 bool MyPipedProcess2::HasInput()
675 {
676 if ( !!m_input )
677 {
678 wxTextOutputStream os(*GetOutputStream());
679 os.WriteString(m_input);
680
681 CloseOutput();
682 m_input.clear();
683
684 // call us once again - may be we'll have output
685 return TRUE;
686 }
687
688 return MyPipedProcess::HasInput();
689 }