X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/a8f0faf389b39b614e401a7e16a1f1cc5a955ada..90da75e673f51b30e04629035d8bf7501fd00e30:/samples/exec/exec.cpp diff --git a/samples/exec/exec.cpp b/samples/exec/exec.cpp index 65957f0d44..06e51aa59d 100644 --- a/samples/exec/exec.cpp +++ b/samples/exec/exec.cpp @@ -38,10 +38,17 @@ #include "wx/menu.h" #include "wx/msgdlg.h" #include "wx/textdlg.h" + #include "wx/listbox.h" #endif +#include "wx/txtstrm.h" + #include "wx/process.h" +#ifdef __WINDOWS__ + #include "wx/dde.h" +#endif // __WINDOWS__ + // ---------------------------------------------------------------------------- // private classes // ---------------------------------------------------------------------------- @@ -59,6 +66,10 @@ public: virtual bool OnInit(); }; +// Define an array of process pointers used by MyFrame +class MyPipedProcess; +WX_DEFINE_ARRAY(MyPipedProcess *, MyProcessesArray); + // Define a new frame type: this is going to be our main frame class MyFrame : public wxFrame { @@ -69,15 +80,31 @@ public: // event handlers (these functions should _not_ be virtual) void OnQuit(wxCommandEvent& event); + void OnClear(wxCommandEvent& event); + void OnSyncExec(wxCommandEvent& event); void OnAsyncExec(wxCommandEvent& event); void OnShell(wxCommandEvent& event); + void OnExecWithRedirect(wxCommandEvent& event); + void OnDDEExec(wxCommandEvent& event); void OnAbout(wxCommandEvent& event); + // polling output of async processes + void OnIdle(wxIdleEvent& event); + + // for MyPipedProcess + void OnProcessTerminated(MyPipedProcess *process) + { m_running.Remove(process); } + wxListBox *GetLogListBox() const { return m_lbox; } + private: wxString m_cmdLast; + wxListBox *m_lbox; + + MyProcessesArray m_running; + // any class wishing to process wxWindows events must use this macro DECLARE_EVENT_TABLE() }; @@ -86,7 +113,7 @@ private: class MyProcess : public wxProcess { public: - MyProcess(wxFrame *parent, const wxString& cmd) + MyProcess(MyFrame *parent, const wxString& cmd) : wxProcess(parent), m_cmd(cmd) { m_parent = parent; @@ -97,11 +124,26 @@ public: // cases virtual void OnTerminate(int pid, int status); -private: - wxFrame *m_parent; +protected: + MyFrame *m_parent; wxString m_cmd; }; +// A specialization of MyProcess for redirecting the output +class MyPipedProcess : public MyProcess +{ +public: + MyPipedProcess(MyFrame *parent, const wxString& cmd) + : MyProcess(parent, cmd) + { + Redirect(); + } + + virtual void OnTerminate(int pid, int status); + + bool HasInput(); +}; + // ---------------------------------------------------------------------------- // constants // ---------------------------------------------------------------------------- @@ -111,12 +153,17 @@ enum { // menu items Exec_Quit = 100, + Exec_ClearLog, Exec_SyncExec = 200, Exec_AsyncExec, Exec_Shell, + Exec_DDEExec, + Exec_Redirect, Exec_About = 300 }; +static const wxChar *DIALOG_TITLE = _T("Exec sample"); + // ---------------------------------------------------------------------------- // event tables and other macros for wxWindows // ---------------------------------------------------------------------------- @@ -126,12 +173,17 @@ enum // simple menu events like this the static method is much simpler. BEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU(Exec_Quit, MyFrame::OnQuit) + EVT_MENU(Exec_ClearLog, MyFrame::OnClear) EVT_MENU(Exec_SyncExec, MyFrame::OnSyncExec) EVT_MENU(Exec_AsyncExec, MyFrame::OnAsyncExec) EVT_MENU(Exec_Shell, MyFrame::OnShell) + EVT_MENU(Exec_Redirect, MyFrame::OnExecWithRedirect) + EVT_MENU(Exec_DDEExec, MyFrame::OnDDEExec) EVT_MENU(Exec_About, MyFrame::OnAbout) + + EVT_IDLE(MyFrame::OnIdle) END_EVENT_TABLE() // Create a new application object: this macro will allow wxWindows to create @@ -181,10 +233,15 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) #endif // set the frame icon +#ifndef __WXGTK__ SetIcon(wxICON(mondrian)); +#endif // create a menu bar wxMenu *menuFile = new wxMenu(_T(""), wxMENU_TEAROFF); + menuFile->Append(Exec_ClearLog, _T("&Clear log\tCtrl-C"), + _T("Clear the log window")); + menuFile->AppendSeparator(); menuFile->Append(Exec_Quit, _T("E&xit\tAlt-X"), _T("Quit this program")); wxMenu *execMenu = new wxMenu; @@ -194,6 +251,13 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) _T("Launch a program and return immediately")); execMenu->Append(Exec_Shell, _T("Execute &shell command...\tCtrl-S"), _T("Launch a shell and execute a command in it")); + execMenu->Append(Exec_Redirect, _T("Capture command &output...\tCtrl-O"), + _T("Launch a program and capture its output")); + +#ifdef __WINDOWS__ + execMenu->AppendSeparator(); + execMenu->Append(Exec_DDEExec, _T("Execute command via &DDE...\tCtrl-D")); +#endif wxMenu *helpMenu = new wxMenu(_T(""), wxMENU_TEAROFF); helpMenu->Append(Exec_About, _T("&About...\tF1"), _T("Show about dialog")); @@ -207,10 +271,13 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) // ... and attach this menu bar to the frame SetMenuBar(menuBar); + // create the listbox in which we will show misc messages as they come + m_lbox = new wxListBox(this, -1); + #if wxUSE_STATUSBAR // create a status bar just for fun (by default with 1 pane only) - CreateStatusBar(2); - SetStatusText(_T("Welcome to wxWindows!")); + CreateStatusBar(); + SetStatusText(_T("Welcome to wxWindows exec sample!")); #endif // wxUSE_STATUSBAR } @@ -223,6 +290,11 @@ void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) Close(TRUE); } +void MyFrame::OnClear(wxCommandEvent& WXUNUSED(event)) +{ + m_lbox->Clear(); +} + void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) { wxMessageBox(_T("Exec sample\n© 2000 Vadim Zeitlin"), @@ -232,13 +304,16 @@ void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) void MyFrame::OnSyncExec(wxCommandEvent& WXUNUSED(event)) { wxString cmd = wxGetTextFromUser(_T("Enter the command: "), - _T("Exec sample"), + DIALOG_TITLE, m_cmdLast); if ( !cmd ) return; + wxLogStatus(_T("'%s' is running please wait..."), cmd.c_str()); + int code = wxExecute(cmd, TRUE /* sync */); + wxLogStatus(_T("Process '%s' terminated with exit code %d."), cmd.c_str(), code); m_cmdLast = cmd; @@ -247,14 +322,15 @@ void MyFrame::OnSyncExec(wxCommandEvent& WXUNUSED(event)) void MyFrame::OnAsyncExec(wxCommandEvent& WXUNUSED(event)) { wxString cmd = wxGetTextFromUser(_T("Enter the command: "), - _T("Exec sample"), + DIALOG_TITLE, m_cmdLast); if ( !cmd ) return; wxProcess *process = new MyProcess(this, cmd); - if ( !wxExecute(cmd, FALSE /* async */, process) ) + long pid = wxExecute(cmd, FALSE /* async */, process); + if ( !pid ) { wxLogError(_T("Execution of '%s' failed."), cmd.c_str()); @@ -262,6 +338,8 @@ void MyFrame::OnAsyncExec(wxCommandEvent& WXUNUSED(event)) } else { + wxLogStatus(_T("Process %ld (%s) launched."), pid, cmd.c_str()); + m_cmdLast = cmd; } } @@ -269,7 +347,7 @@ void MyFrame::OnAsyncExec(wxCommandEvent& WXUNUSED(event)) void MyFrame::OnShell(wxCommandEvent& WXUNUSED(event)) { wxString cmd = wxGetTextFromUser(_T("Enter the command: "), - _T("Exec sample"), + DIALOG_TITLE, m_cmdLast); if ( !cmd ) @@ -281,6 +359,124 @@ void MyFrame::OnShell(wxCommandEvent& WXUNUSED(event)) m_cmdLast = cmd; } +void MyFrame::OnExecWithRedirect(wxCommandEvent& WXUNUSED(event)) +{ + wxString cmd = wxGetTextFromUser(_T("Enter the command: "), + DIALOG_TITLE, + m_cmdLast); + + if ( !cmd ) + return; + + bool sync; + switch ( wxMessageBox(_T("Execute it synchronously?"), + _T("Exec question"), + wxYES_NO | wxCANCEL | wxICON_QUESTION, this) ) + { + case wxYES: + sync = TRUE; + break; + + case wxNO: + sync = FALSE; + break; + + default: + return; + } + + if ( sync ) + { + wxArrayString output; + int code = wxExecute(cmd, output); + wxLogStatus(_T("command '%s' terminated with exit code %d."), + cmd.c_str(), code); + + if ( code != -1 ) + { + m_lbox->Append(wxString::Format(_T("--- Output of '%s' ---"), + cmd.c_str())); + + size_t count = output.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + m_lbox->Append(output[n]); + } + } + } + else // async exec + { + MyPipedProcess *process = new MyPipedProcess(this, cmd); + if ( !wxExecute(cmd, FALSE /* async */, process) ) + { + wxLogError(_T("Execution of '%s' failed."), cmd.c_str()); + + delete process; + } + else + { + m_running.Add(process); + } + } + + m_cmdLast = cmd; +} + +void MyFrame::OnDDEExec(wxCommandEvent& WXUNUSED(event)) +{ +#ifdef __WINDOWS__ + wxString server = wxGetTextFromUser(_T("Server to connect to:"), + DIALOG_TITLE, _T("IExplore")); + if ( !server ) + return; + + wxString topic = wxGetTextFromUser(_T("DDE topic:"), + DIALOG_TITLE, _T("WWW_OpenURL")); + if ( !topic ) + return; + + wxString cmd = wxGetTextFromUser(_T("DDE command:"), + DIALOG_TITLE, + _T("\"file:F:\\wxWindows\\samples\\" + "image\\horse.gif\",,-1,,,,,")); + if ( !cmd ) + return; + + wxDDEClient client; + wxConnectionBase *conn = client.MakeConnection("", server, topic); + if ( !conn ) + { + wxLogError(_T("Failed to connect to the DDE server '%s'."), + server.c_str()); + } + else + { + if ( !conn->Execute(cmd) ) + { + wxLogError(_T("Failed to execute command '%s' via DDE."), + cmd.c_str()); + } + else + { + wxLogStatus(_T("Successfully executed DDE command")); + } + } +#endif // __WINDOWS__ +} + +// input polling +void MyFrame::OnIdle(wxIdleEvent& event) +{ + size_t count = m_running.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + if ( m_running[n]->HasInput() ) + { + event.RequestMore(); + } + } +} + // ---------------------------------------------------------------------------- // MyProcess // ---------------------------------------------------------------------------- @@ -293,3 +489,39 @@ void MyProcess::OnTerminate(int pid, int status) // we're not needed any more delete this; } + +// ---------------------------------------------------------------------------- +// MyPipedProcess +// ---------------------------------------------------------------------------- + +bool MyPipedProcess::HasInput() +{ + wxInputStream& is = *GetInputStream(); + if ( !is.Eof() ) + { + wxTextInputStream tis(is); + + // this assumes that the output is always line buffered + wxString msg; + msg << m_cmd << _T(": ") << tis.ReadLine(); + + m_parent->GetLogListBox()->Append(msg); + + return TRUE; + } + else + { + return FALSE; + } +} + +void MyPipedProcess::OnTerminate(int pid, int status) +{ + // show the rest of the output + while ( HasInput() ) + ; + + m_parent->OnProcessTerminated(this); + + MyProcess::OnTerminate(pid, status); +}