1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: exec sample demonstrates wxExecute and related functions
4 // Author: Vadim Zeitlin
8 // Copyright: (c) Vadim Zeitlin
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
21 #pragma implementation "exec.cpp"
22 #pragma interface "exec.cpp"
25 // For compilers that support precompilation, includes "wx/wx.h".
26 #include "wx/wxprec.h"
32 // for all others, include the necessary headers (this file is usually all you
33 // need because it includes almost all "standard" wxWindows headers
39 #include "wx/msgdlg.h"
40 #include "wx/textdlg.h"
41 #include "wx/listbox.h"
42 #include "wx/filedlg.h"
45 #include "wx/txtstrm.h"
47 #include "wx/process.h"
49 #include "wx/mimetype.h"
55 // ----------------------------------------------------------------------------
57 // ----------------------------------------------------------------------------
59 // Define a new application type, each program should derive a class from wxApp
60 class MyApp
: public wxApp
63 // override base class virtuals
64 // ----------------------------
66 // this one is called on application startup and is a good place for the app
67 // initialization (doing it here and not in the ctor allows to have an error
68 // return: if OnInit() returns false, the application terminates)
69 virtual bool OnInit();
72 // Define an array of process pointers used by MyFrame
74 WX_DEFINE_ARRAY(MyPipedProcess
*, MyProcessesArray
);
76 // Define a new frame type: this is going to be our main frame
77 class MyFrame
: public wxFrame
81 MyFrame(const wxString
& title
, const wxPoint
& pos
, const wxSize
& size
);
83 // event handlers (these functions should _not_ be virtual)
84 void OnQuit(wxCommandEvent
& event
);
86 void OnClear(wxCommandEvent
& event
);
88 void OnSyncExec(wxCommandEvent
& event
);
89 void OnAsyncExec(wxCommandEvent
& event
);
90 void OnShell(wxCommandEvent
& event
);
91 void OnExecWithRedirect(wxCommandEvent
& event
);
92 void OnExecWithPipe(wxCommandEvent
& event
);
94 void OnFileExec(wxCommandEvent
& event
);
96 void OnAbout(wxCommandEvent
& event
);
98 // polling output of async processes
99 void OnIdle(wxIdleEvent
& event
);
101 // for MyPipedProcess
102 void OnProcessTerminated(MyPipedProcess
*process
);
103 wxListBox
*GetLogListBox() const { return m_lbox
; }
106 void ShowOutput(const wxString
& cmd
,
107 const wxArrayString
& output
,
108 const wxString
& title
);
110 void DoAsyncExec(const wxString
& cmd
);
112 // last command we executed
116 void OnDDEExec(wxCommandEvent
& event
);
117 void OnDDERequest(wxCommandEvent
& event
);
121 // last params of a DDE transaction
125 #endif // __WINDOWS__
129 MyProcessesArray m_running
;
131 // any class wishing to process wxWindows events must use this macro
132 DECLARE_EVENT_TABLE()
135 // This is the handler for process termination events
136 class MyProcess
: public wxProcess
139 MyProcess(MyFrame
*parent
, const wxString
& cmd
)
140 : wxProcess(parent
), m_cmd(cmd
)
145 // instead of overriding this virtual function we might as well process the
146 // event from it in the frame class - this might be more convenient in some
148 virtual void OnTerminate(int pid
, int status
);
155 // A specialization of MyProcess for redirecting the output
156 class MyPipedProcess
: public MyProcess
159 MyPipedProcess(MyFrame
*parent
, const wxString
& cmd
)
160 : MyProcess(parent
, cmd
)
165 virtual void OnTerminate(int pid
, int status
);
167 virtual bool HasInput();
170 // A version of MyPipedProcess which also sends input to the stdin of the
172 class MyPipedProcess2
: public MyPipedProcess
175 MyPipedProcess2(MyFrame
*parent
, const wxString
& cmd
, const wxString
& input
)
176 : MyPipedProcess(parent
, cmd
), m_input(input
)
180 virtual bool HasInput();
186 // ----------------------------------------------------------------------------
188 // ----------------------------------------------------------------------------
190 // IDs for the controls and the menu commands
207 static const wxChar
*DIALOG_TITLE
= _T("Exec sample");
209 // ----------------------------------------------------------------------------
210 // event tables and other macros for wxWindows
211 // ----------------------------------------------------------------------------
213 // the event tables connect the wxWindows events with the functions (event
214 // handlers) which process them. It can be also done at run-time, but for the
215 // simple menu events like this the static method is much simpler.
216 BEGIN_EVENT_TABLE(MyFrame
, wxFrame
)
217 EVT_MENU(Exec_Quit
, MyFrame::OnQuit
)
218 EVT_MENU(Exec_ClearLog
, MyFrame::OnClear
)
220 EVT_MENU(Exec_SyncExec
, MyFrame::OnSyncExec
)
221 EVT_MENU(Exec_AsyncExec
, MyFrame::OnAsyncExec
)
222 EVT_MENU(Exec_Shell
, MyFrame::OnShell
)
223 EVT_MENU(Exec_Redirect
, MyFrame::OnExecWithRedirect
)
224 EVT_MENU(Exec_Pipe
, MyFrame::OnExecWithPipe
)
226 EVT_MENU(Exec_OpenFile
, MyFrame::OnFileExec
)
228 EVT_MENU(Exec_DDEExec
, MyFrame::OnDDEExec
)
229 EVT_MENU(Exec_DDERequest
, MyFrame::OnDDERequest
)
231 EVT_MENU(Exec_About
, MyFrame::OnAbout
)
233 EVT_IDLE(MyFrame::OnIdle
)
236 // Create a new application object: this macro will allow wxWindows to create
237 // the application object during program execution (it's better than using a
238 // static object for many reasons) and also declares the accessor function
239 // wxGetApp() which will return the reference of the right type (i.e. MyApp and
243 // ============================================================================
245 // ============================================================================
247 // ----------------------------------------------------------------------------
248 // the application class
249 // ----------------------------------------------------------------------------
251 // `Main program' equivalent: the program execution "starts" here
254 // Create the main application window
255 MyFrame
*frame
= new MyFrame(_T("Exec wxWindows sample"),
256 wxDefaultPosition
, wxSize(500, 140));
258 // Show it and tell the application that it's our main window
262 // success: wxApp::OnRun() will be called which will enter the main message
263 // loop and the application will run. If we returned FALSE here, the
264 // application would exit immediately.
268 // ----------------------------------------------------------------------------
270 // ----------------------------------------------------------------------------
273 MyFrame::MyFrame(const wxString
& title
, const wxPoint
& pos
, const wxSize
& size
)
274 : wxFrame((wxFrame
*)NULL
, -1, title
, pos
, size
)
277 // we need this in order to allow the about menu relocation, since ABOUT is
278 // not the default id of the about menu
279 wxApp::s_macAboutMenuItemId
= Exec_About
;
283 wxMenu
*menuFile
= new wxMenu(_T(""), wxMENU_TEAROFF
);
284 menuFile
->Append(Exec_ClearLog
, _T("&Clear log\tCtrl-C"),
285 _T("Clear the log window"));
286 menuFile
->AppendSeparator();
287 menuFile
->Append(Exec_Quit
, _T("E&xit\tAlt-X"), _T("Quit this program"));
289 wxMenu
*execMenu
= new wxMenu
;
290 execMenu
->Append(Exec_SyncExec
, _T("Sync &execution...\tCtrl-E"),
291 _T("Launch a program and return when it terminates"));
292 execMenu
->Append(Exec_AsyncExec
, _T("&Async execution...\tCtrl-A"),
293 _T("Launch a program and return immediately"));
294 execMenu
->Append(Exec_Shell
, _T("Execute &shell command...\tCtrl-S"),
295 _T("Launch a shell and execute a command in it"));
296 execMenu
->AppendSeparator();
297 execMenu
->Append(Exec_Redirect
, _T("Capture command &output...\tCtrl-O"),
298 _T("Launch a program and capture its output"));
299 execMenu
->Append(Exec_Pipe
, _T("&Pipe through command...\tCtrl-P"),
300 _T("Pipe a string through a filter"));
302 execMenu
->AppendSeparator();
303 execMenu
->Append(Exec_OpenFile
, _T("Open &file...\tCtrl-F"),
304 _T("Launch the command to open this kind of files"));
306 execMenu
->AppendSeparator();
307 execMenu
->Append(Exec_DDEExec
, _T("Execute command via &DDE...\tCtrl-D"));
308 execMenu
->Append(Exec_DDERequest
, _T("Send DDE &request...\tCtrl-R"));
311 wxMenu
*helpMenu
= new wxMenu(_T(""), wxMENU_TEAROFF
);
312 helpMenu
->Append(Exec_About
, _T("&About...\tF1"), _T("Show about dialog"));
314 // now append the freshly created menu to the menu bar...
315 wxMenuBar
*menuBar
= new wxMenuBar();
316 menuBar
->Append(menuFile
, _T("&File"));
317 menuBar
->Append(execMenu
, _T("&Exec"));
318 menuBar
->Append(helpMenu
, _T("&Help"));
320 // ... and attach this menu bar to the frame
323 // create the listbox in which we will show misc messages as they come
324 m_lbox
= new wxListBox(this, -1);
325 wxFont
font(12, wxFONTFAMILY_TELETYPE
, wxFONTSTYLE_NORMAL
,
326 wxFONTWEIGHT_NORMAL
);
328 m_lbox
->SetFont(font
);
331 // create a status bar just for fun (by default with 1 pane only)
333 SetStatusText(_T("Welcome to wxWindows exec sample!"));
334 #endif // wxUSE_STATUSBAR
340 void MyFrame::OnQuit(wxCommandEvent
& WXUNUSED(event
))
342 // TRUE is to force the frame to close
346 void MyFrame::OnClear(wxCommandEvent
& WXUNUSED(event
))
351 void MyFrame::OnAbout(wxCommandEvent
& WXUNUSED(event
))
353 wxMessageBox(_T("Exec sample\n© 2000 Vadim Zeitlin"),
354 _T("About Exec"), wxOK
| wxICON_INFORMATION
, this);
357 void MyFrame::DoAsyncExec(const wxString
& cmd
)
359 wxProcess
*process
= new MyProcess(this, cmd
);
360 long pid
= wxExecute(cmd
, FALSE
/* async */, process
);
363 wxLogError(_T("Execution of '%s' failed."), cmd
.c_str());
369 wxLogStatus(_T("Process %ld (%s) launched."), pid
, cmd
.c_str());
375 void MyFrame::OnSyncExec(wxCommandEvent
& WXUNUSED(event
))
377 wxString cmd
= wxGetTextFromUser(_T("Enter the command: "),
384 wxLogStatus(_T("'%s' is running please wait..."), cmd
.c_str());
386 int code
= wxExecute(cmd
, TRUE
/* sync */);
388 wxLogStatus(_T("Process '%s' terminated with exit code %d."),
393 void MyFrame::OnAsyncExec(wxCommandEvent
& WXUNUSED(event
))
395 wxString cmd
= wxGetTextFromUser(_T("Enter the command: "),
405 void MyFrame::OnShell(wxCommandEvent
& WXUNUSED(event
))
407 wxString cmd
= wxGetTextFromUser(_T("Enter the command: "),
414 int code
= wxShell(cmd
);
415 wxLogStatus(_T("Shell command '%s' terminated with exit code %d."),
420 void MyFrame::OnExecWithRedirect(wxCommandEvent
& WXUNUSED(event
))
422 wxString cmd
= wxGetTextFromUser(_T("Enter the command: "),
430 switch ( wxMessageBox(_T("Execute it synchronously?"),
432 wxYES_NO
| wxCANCEL
| wxICON_QUESTION
, this) )
448 wxArrayString output
, errors
;
449 int code
= wxExecute(cmd
, output
, errors
);
450 wxLogStatus(_T("command '%s' terminated with exit code %d."),
455 ShowOutput(cmd
, output
, _T("Output"));
456 ShowOutput(cmd
, errors
, _T("Errors"));
461 MyPipedProcess
*process
= new MyPipedProcess(this, cmd
);
462 if ( !wxExecute(cmd
, FALSE
/* async */, process
) )
464 wxLogError(_T("Execution of '%s' failed."), cmd
.c_str());
470 m_running
.Add(process
);
477 void MyFrame::OnExecWithPipe(wxCommandEvent
& WXUNUSED(event
))
480 m_cmdLast
= _T("tr [a-z] [A-Z]");
482 wxString cmd
= wxGetTextFromUser(_T("Enter the command: "),
489 wxString input
= wxGetTextFromUser(_T("Enter the string to send to it: "),
494 // always execute the filter asynchronously
495 MyPipedProcess2
*process
= new MyPipedProcess2(this, cmd
, input
);
496 int pid
= wxExecute(cmd
, FALSE
/* async */, process
);
499 wxLogStatus(_T("Process %ld (%s) launched."), pid
, cmd
.c_str());
501 m_running
.Add(process
);
505 wxLogError(_T("Execution of '%s' failed."), cmd
.c_str());
513 void MyFrame::OnFileExec(wxCommandEvent
& event
)
515 static wxString s_filename
;
517 wxString filename
= wxLoadFileSelector(_T("file"), _T(""), s_filename
);
521 s_filename
= filename
;
523 wxString ext
= filename
.AfterFirst(_T('.'));
524 wxFileType
*ft
= wxTheMimeTypesManager
->GetFileTypeFromExtension(ext
);
527 wxLogError(_T("Impossible to determine the file type for extension '%s'"),
533 bool ok
= ft
->GetOpenCommand(&cmd
,
534 wxFileType::MessageParameters(filename
, _T("")));
538 wxLogError(_T("Impossible to find out how to open files of extension '%s'"),
548 bool MyFrame::GetDDEServer()
550 wxString server
= wxGetTextFromUser(_T("Server to connect to:"),
551 DIALOG_TITLE
, m_server
);
557 wxString topic
= wxGetTextFromUser(_T("DDE topic:"), DIALOG_TITLE
, m_topic
);
563 wxString cmd
= wxGetTextFromUser(_T("DDE command:"), DIALOG_TITLE
, m_cmdDde
);
572 void MyFrame::OnDDEExec(wxCommandEvent
& WXUNUSED(event
))
574 if ( !GetDDEServer() )
578 wxConnectionBase
*conn
= client
.MakeConnection("", m_server
, m_topic
);
581 wxLogError(_T("Failed to connect to the DDE server '%s'."),
586 if ( !conn
->Execute(m_cmdDde
) )
588 wxLogError(_T("Failed to execute command '%s' via DDE."),
593 wxLogStatus(_T("Successfully executed DDE command"));
598 void MyFrame::OnDDERequest(wxCommandEvent
& WXUNUSED(event
))
600 if ( !GetDDEServer() )
604 wxConnectionBase
*conn
= client
.MakeConnection("", m_server
, m_topic
);
607 wxLogError(_T("Failed to connect to the DDE server '%s'."),
612 if ( !conn
->Request(m_cmdDde
) )
614 wxLogError(_T("Failed to send request '%s' via DDE."),
619 wxLogStatus(_T("Successfully sent DDE request."));
624 #endif // __WINDOWS__
627 void MyFrame::OnIdle(wxIdleEvent
& event
)
629 size_t count
= m_running
.GetCount();
630 for ( size_t n
= 0; n
< count
; n
++ )
632 if ( m_running
[n
]->HasInput() )
639 void MyFrame::OnProcessTerminated(MyPipedProcess
*process
)
641 m_running
.Remove(process
);
645 void MyFrame::ShowOutput(const wxString
& cmd
,
646 const wxArrayString
& output
,
647 const wxString
& title
)
649 size_t count
= output
.GetCount();
653 m_lbox
->Append(wxString::Format(_T("--- %s of '%s' ---"),
654 title
.c_str(), cmd
.c_str()));
656 for ( size_t n
= 0; n
< count
; n
++ )
658 m_lbox
->Append(output
[n
]);
661 m_lbox
->Append(_T("--- End of output ---"));
664 // ----------------------------------------------------------------------------
666 // ----------------------------------------------------------------------------
668 void MyProcess::OnTerminate(int pid
, int status
)
670 wxLogStatus(m_parent
, _T("Process %u ('%s') terminated with exit code %d."),
671 pid
, m_cmd
.c_str(), status
);
673 // we're not needed any more
677 // ----------------------------------------------------------------------------
679 // ----------------------------------------------------------------------------
681 bool MyPipedProcess::HasInput()
683 bool hasInput
= FALSE
;
685 wxInputStream
& is
= *GetInputStream();
688 wxTextInputStream
tis(is
);
690 // this assumes that the output is always line buffered
692 msg
<< m_cmd
<< _T(" (stdout): ") << tis
.ReadLine();
694 m_parent
->GetLogListBox()->Append(msg
);
699 wxInputStream
& es
= *GetErrorStream();
702 wxTextInputStream
tis(es
);
704 // this assumes that the output is always line buffered
706 msg
<< m_cmd
<< _T(" (stderr): ") << tis
.ReadLine();
708 m_parent
->GetLogListBox()->Append(msg
);
716 void MyPipedProcess::OnTerminate(int pid
, int status
)
718 // show the rest of the output
722 m_parent
->OnProcessTerminated(this);
724 MyProcess::OnTerminate(pid
, status
);
727 // ----------------------------------------------------------------------------
729 // ----------------------------------------------------------------------------
731 bool MyPipedProcess2::HasInput()
735 wxTextOutputStream
os(*GetOutputStream());
736 os
.WriteString(m_input
);
741 // call us once again - may be we'll have output
745 return MyPipedProcess::HasInput();