home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / samples / exec / exec.cpp next >
C/C++ Source or Header  |  2002-12-16  |  32KB  |  1,108 lines

  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: exec.cpp,v 1.21.2.2 2002/12/14 18:19:48 MBN Exp $
  8. // Copyright:   (c) Vadim Zeitlin
  9. // Licence:     wxWindows licence
  10. /////////////////////////////////////////////////////////////////////////////
  11.  
  12. // ============================================================================
  13. // declarations
  14. // ============================================================================
  15.  
  16. // ----------------------------------------------------------------------------
  17. // headers
  18. // ----------------------------------------------------------------------------
  19.  
  20. #if defined(__GNUG__) && !defined(__APPLE__)
  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/log.h"
  37.     #include "wx/frame.h"
  38.     #include "wx/panel.h"
  39.  
  40.     #include "wx/timer.h"
  41.  
  42.     #include "wx/utils.h"
  43.     #include "wx/menu.h"
  44.  
  45.     #include "wx/msgdlg.h"
  46.     #include "wx/textdlg.h"
  47.     #include "wx/filedlg.h"
  48.     #include "wx/choicdlg.h"
  49.  
  50.     #include "wx/button.h"
  51.     #include "wx/textctrl.h"
  52.     #include "wx/listbox.h"
  53.  
  54.     #include "wx/sizer.h"
  55. #endif
  56.  
  57. #include "wx/txtstrm.h"
  58.  
  59. #include "wx/process.h"
  60.  
  61. #include "wx/mimetype.h"
  62.  
  63. #ifdef __WINDOWS__
  64.     #include "wx/dde.h"
  65. #endif // __WINDOWS__
  66.  
  67. // ----------------------------------------------------------------------------
  68. // the usual application and main frame classes
  69. // ----------------------------------------------------------------------------
  70.  
  71. // Define a new application type, each program should derive a class from wxApp
  72. class MyApp : public wxApp
  73. {
  74. public:
  75.     // override base class virtuals
  76.     // ----------------------------
  77.  
  78.     // this one is called on application startup and is a good place for the app
  79.     // initialization (doing it here and not in the ctor allows to have an error
  80.     // return: if OnInit() returns false, the application terminates)
  81.     virtual bool OnInit();
  82. };
  83.  
  84. // Define an array of process pointers used by MyFrame
  85. class MyPipedProcess;
  86. WX_DEFINE_ARRAY(MyPipedProcess *, MyProcessesArray);
  87.  
  88. // Define a new frame type: this is going to be our main frame
  89. class MyFrame : public wxFrame
  90. {
  91. public:
  92.     // ctor(s)
  93.     MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size);
  94.  
  95.     // event handlers (these functions should _not_ be virtual)
  96.     void OnQuit(wxCommandEvent& event);
  97.  
  98.     void OnKill(wxCommandEvent& event);
  99.  
  100.     void OnClear(wxCommandEvent& event);
  101.  
  102.     void OnSyncExec(wxCommandEvent& event);
  103.     void OnAsyncExec(wxCommandEvent& event);
  104.     void OnShell(wxCommandEvent& event);
  105.     void OnExecWithRedirect(wxCommandEvent& event);
  106.     void OnExecWithPipe(wxCommandEvent& event);
  107.  
  108.     void OnPOpen(wxCommandEvent& event);
  109.  
  110.     void OnFileExec(wxCommandEvent& event);
  111.  
  112.     void OnAbout(wxCommandEvent& event);
  113.  
  114.     // polling output of async processes
  115.     void OnTimer(wxTimerEvent& event);
  116.     void OnIdle(wxIdleEvent& event);
  117.  
  118.     // for MyPipedProcess
  119.     void OnProcessTerminated(MyPipedProcess *process);
  120.     wxListBox *GetLogListBox() const { return m_lbox; }
  121.  
  122. private:
  123.     void ShowOutput(const wxString& cmd,
  124.                     const wxArrayString& output,
  125.                     const wxString& title);
  126.  
  127.     void DoAsyncExec(const wxString& cmd);
  128.  
  129.     void AddAsyncProcess(MyPipedProcess *process)
  130.     {
  131.         if ( m_running.IsEmpty() )
  132.         {
  133.             // we want to start getting the timer events to ensure that a
  134.             // steady stream of idle events comes in -- otherwise we
  135.             // wouldn't be able to poll the child process input
  136.             m_timerIdleWakeUp.Start(100);
  137.         }
  138.         //else: the timer is already running
  139.  
  140.         m_running.Add(process);
  141.     }
  142.  
  143.     void RemoveAsyncProcess(MyPipedProcess *process)
  144.     {
  145.         m_running.Remove(process);
  146.  
  147.         if ( m_running.IsEmpty() )
  148.         {
  149.             // we don't need to get idle events all the time any more
  150.             m_timerIdleWakeUp.Stop();
  151.         }
  152.     }
  153.  
  154.     // the PID of the last process we launched asynchronously
  155.     long m_pidLast;
  156.  
  157.     // last command we executed
  158.     wxString m_cmdLast;
  159.  
  160. #ifdef __WINDOWS__
  161.     void OnDDEExec(wxCommandEvent& event);
  162.     void OnDDERequest(wxCommandEvent& event);
  163.  
  164.     bool GetDDEServer();
  165.  
  166.     // last params of a DDE transaction
  167.     wxString m_server,
  168.              m_topic,
  169.              m_cmdDde;
  170. #endif // __WINDOWS__
  171.  
  172.     wxListBox *m_lbox;
  173.  
  174.     MyProcessesArray m_running;
  175.  
  176.     // the idle event wake up timer
  177.     wxTimer m_timerIdleWakeUp;
  178.  
  179.     // any class wishing to process wxWindows events must use this macro
  180.     DECLARE_EVENT_TABLE()
  181. };
  182.  
  183. // ----------------------------------------------------------------------------
  184. // MyPipeFrame: allows the user to communicate with the child process
  185. // ----------------------------------------------------------------------------
  186.  
  187. class MyPipeFrame : public wxFrame
  188. {
  189. public:
  190.     MyPipeFrame(wxFrame *parent,
  191.                 const wxString& cmd,
  192.                 wxProcess *process);
  193.  
  194. protected:
  195.     void OnTextEnter(wxCommandEvent& event) { DoSend(); }
  196.     void OnBtnSend(wxCommandEvent& event) { DoSend(); }
  197.     void OnBtnGet(wxCommandEvent& event) { DoGet(); }
  198.  
  199.     void OnClose(wxCloseEvent& event);
  200.  
  201.     void OnProcessTerm(wxProcessEvent& event);
  202.  
  203.     void DoSend()
  204.     {
  205.         m_out.WriteString(m_textIn->GetValue() + '\n');
  206.         m_textIn->Clear();
  207.  
  208.         DoGet();
  209.     }
  210.  
  211.     void DoGet();
  212.  
  213. private:
  214.     wxProcess *m_process;
  215.  
  216.     wxTextInputStream m_in;
  217.     wxTextOutputStream m_out;
  218.  
  219.     wxTextCtrl *m_textIn,
  220.                *m_textOut;
  221.  
  222.     DECLARE_EVENT_TABLE()
  223. };
  224.  
  225. // ----------------------------------------------------------------------------
  226. // wxProcess-derived classes
  227. // ----------------------------------------------------------------------------
  228.  
  229. // This is the handler for process termination events
  230. class MyProcess : public wxProcess
  231. {
  232. public:
  233.     MyProcess(MyFrame *parent, const wxString& cmd)
  234.         : wxProcess(parent), m_cmd(cmd)
  235.     {
  236.         m_parent = parent;
  237.     }
  238.  
  239.     // instead of overriding this virtual function we might as well process the
  240.     // event from it in the frame class - this might be more convenient in some
  241.     // cases
  242.     virtual void OnTerminate(int pid, int status);
  243.  
  244. protected:
  245.     MyFrame *m_parent;
  246.     wxString m_cmd;
  247. };
  248.  
  249. // A specialization of MyProcess for redirecting the output
  250. class MyPipedProcess : public MyProcess
  251. {
  252. public:
  253.     MyPipedProcess(MyFrame *parent, const wxString& cmd)
  254.         : MyProcess(parent, cmd)
  255.         {
  256.             Redirect();
  257.         }
  258.  
  259.     virtual void OnTerminate(int pid, int status);
  260.  
  261.     virtual bool HasInput();
  262. };
  263.  
  264. // A version of MyPipedProcess which also sends input to the stdin of the
  265. // child process
  266. class MyPipedProcess2 : public MyPipedProcess
  267. {
  268. public:
  269.     MyPipedProcess2(MyFrame *parent, const wxString& cmd, const wxString& input)
  270.         : MyPipedProcess(parent, cmd), m_input(input)
  271.         {
  272.         }
  273.  
  274.     virtual bool HasInput();
  275.  
  276. private:
  277.     wxString m_input;
  278. };
  279.  
  280. // ----------------------------------------------------------------------------
  281. // constants
  282. // ----------------------------------------------------------------------------
  283.  
  284. // IDs for the controls and the menu commands
  285. enum
  286. {
  287.     // menu items
  288.     Exec_Quit = 100,
  289.     Exec_Kill,
  290.     Exec_ClearLog,
  291.     Exec_SyncExec = 200,
  292.     Exec_AsyncExec,
  293.     Exec_Shell,
  294.     Exec_POpen,
  295.     Exec_OpenFile,
  296.     Exec_DDEExec,
  297.     Exec_DDERequest,
  298.     Exec_Redirect,
  299.     Exec_Pipe,
  300.     Exec_About = 300,
  301.  
  302.     // control ids
  303.     Exec_Btn_Send = 1000,
  304.     Exec_Btn_Get
  305. };
  306.  
  307. static const wxChar *DIALOG_TITLE = _T("Exec sample");
  308.  
  309. // ----------------------------------------------------------------------------
  310. // event tables and other macros for wxWindows
  311. // ----------------------------------------------------------------------------
  312.  
  313. // the event tables connect the wxWindows events with the functions (event
  314. // handlers) which process them. It can be also done at run-time, but for the
  315. // simple menu events like this the static method is much simpler.
  316. BEGIN_EVENT_TABLE(MyFrame, wxFrame)
  317.     EVT_MENU(Exec_Quit,  MyFrame::OnQuit)
  318.     EVT_MENU(Exec_Kill,  MyFrame::OnKill)
  319.     EVT_MENU(Exec_ClearLog,  MyFrame::OnClear)
  320.  
  321.     EVT_MENU(Exec_SyncExec, MyFrame::OnSyncExec)
  322.     EVT_MENU(Exec_AsyncExec, MyFrame::OnAsyncExec)
  323.     EVT_MENU(Exec_Shell, MyFrame::OnShell)
  324.     EVT_MENU(Exec_Redirect, MyFrame::OnExecWithRedirect)
  325.     EVT_MENU(Exec_Pipe, MyFrame::OnExecWithPipe)
  326.  
  327.     EVT_MENU(Exec_POpen, MyFrame::OnPOpen)
  328.  
  329.     EVT_MENU(Exec_OpenFile, MyFrame::OnFileExec)
  330.  
  331. #ifdef __WINDOWS__
  332.     EVT_MENU(Exec_DDEExec, MyFrame::OnDDEExec)
  333.     EVT_MENU(Exec_DDERequest, MyFrame::OnDDERequest)
  334. #endif // __WINDOWS__
  335.  
  336.     EVT_MENU(Exec_About, MyFrame::OnAbout)
  337.  
  338.     EVT_IDLE(MyFrame::OnIdle)
  339.  
  340.     EVT_TIMER(-1, MyFrame::OnTimer)
  341. END_EVENT_TABLE()
  342.  
  343. BEGIN_EVENT_TABLE(MyPipeFrame, wxFrame)
  344.     EVT_BUTTON(Exec_Btn_Send, MyPipeFrame::OnBtnSend)
  345.     EVT_BUTTON(Exec_Btn_Get, MyPipeFrame::OnBtnGet)
  346.  
  347.     EVT_TEXT_ENTER(-1, MyPipeFrame::OnTextEnter)
  348.  
  349.     EVT_CLOSE(MyPipeFrame::OnClose)
  350.  
  351.     EVT_END_PROCESS(-1, MyPipeFrame::OnProcessTerm)
  352. END_EVENT_TABLE()
  353.  
  354. // Create a new application object: this macro will allow wxWindows to create
  355. // the application object during program execution (it's better than using a
  356. // static object for many reasons) and also declares the accessor function
  357. // wxGetApp() which will return the reference of the right type (i.e. MyApp and
  358. // not wxApp)
  359. IMPLEMENT_APP(MyApp)
  360.  
  361. // ============================================================================
  362. // implementation
  363. // ============================================================================
  364.  
  365. // ----------------------------------------------------------------------------
  366. // the application class
  367. // ----------------------------------------------------------------------------
  368.  
  369. // `Main program' equivalent: the program execution "starts" here
  370. bool MyApp::OnInit()
  371. {
  372.     // Create the main application window
  373.     MyFrame *frame = new MyFrame(_T("Exec wxWindows sample"),
  374.                                  wxDefaultPosition, wxSize(500, 140));
  375.  
  376.     // Show it and tell the application that it's our main window
  377.     frame->Show(TRUE);
  378.     SetTopWindow(frame);
  379.  
  380.     // success: wxApp::OnRun() will be called which will enter the main message
  381.     // loop and the application will run. If we returned FALSE here, the
  382.     // application would exit immediately.
  383.     return TRUE;
  384. }
  385.  
  386. // ----------------------------------------------------------------------------
  387. // main frame
  388. // ----------------------------------------------------------------------------
  389.  
  390. #ifdef __VISUALC__
  391. #pragma warning(disable: 4355) // this used in base member initializer list
  392. #endif
  393.  
  394. // frame constructor
  395. MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
  396.        : wxFrame((wxFrame *)NULL, -1, title, pos, size),
  397.          m_timerIdleWakeUp(this)
  398. {
  399.     m_pidLast = 0;
  400.  
  401. #ifdef __WXMAC__
  402.     // we need this in order to allow the about menu relocation, since ABOUT is
  403.     // not the default id of the about menu
  404.     wxApp::s_macAboutMenuItemId = Exec_About;
  405. #endif
  406.  
  407.     // create a menu bar
  408.     wxMenu *menuFile = new wxMenu(_T(""), wxMENU_TEAROFF);
  409.     menuFile->Append(Exec_Kill, _T("&Kill process...\tCtrl-K"),
  410.                      _T("Kill a process by PID"));
  411.     menuFile->AppendSeparator();
  412.     menuFile->Append(Exec_ClearLog, _T("&Clear log\tCtrl-C"),
  413.                      _T("Clear the log window"));
  414.     menuFile->AppendSeparator();
  415.     menuFile->Append(Exec_Quit, _T("E&xit\tAlt-X"), _T("Quit this program"));
  416.  
  417.     wxMenu *execMenu = new wxMenu;
  418.     execMenu->Append(Exec_SyncExec, _T("Sync &execution...\tCtrl-E"),
  419.                      _T("Launch a program and return when it terminates"));
  420.     execMenu->Append(Exec_AsyncExec, _T("&Async execution...\tCtrl-A"),
  421.                      _T("Launch a program and return immediately"));
  422.     execMenu->Append(Exec_Shell, _T("Execute &shell command...\tCtrl-S"),
  423.                      _T("Launch a shell and execute a command in it"));
  424.     execMenu->AppendSeparator();
  425.     execMenu->Append(Exec_Redirect, _T("Capture command &output...\tCtrl-O"),
  426.                      _T("Launch a program and capture its output"));
  427.     execMenu->Append(Exec_Pipe, _T("&Pipe through command..."),
  428.                      _T("Pipe a string through a filter"));
  429.     execMenu->Append(Exec_POpen, _T("&Open a pipe to a command...\tCtrl-P"),
  430.                      _T("Open a pipe to and from another program"));
  431.  
  432.     execMenu->AppendSeparator();
  433.     execMenu->Append(Exec_OpenFile, _T("Open &file...\tCtrl-F"),
  434.                      _T("Launch the command to open this kind of files"));
  435. #ifdef __WINDOWS__
  436.     execMenu->AppendSeparator();
  437.     execMenu->Append(Exec_DDEExec, _T("Execute command via &DDE...\tCtrl-D"));
  438.     execMenu->Append(Exec_DDERequest, _T("Send DDE &request...\tCtrl-R"));
  439. #endif
  440.  
  441.     wxMenu *helpMenu = new wxMenu(_T(""), wxMENU_TEAROFF);
  442.     helpMenu->Append(Exec_About, _T("&About...\tF1"), _T("Show about dialog"));
  443.  
  444.     // now append the freshly created menu to the menu bar...
  445.     wxMenuBar *menuBar = new wxMenuBar();
  446.     menuBar->Append(menuFile, _T("&File"));
  447.     menuBar->Append(execMenu, _T("&Exec"));
  448.     menuBar->Append(helpMenu, _T("&Help"));
  449.  
  450.     // ... and attach this menu bar to the frame
  451.     SetMenuBar(menuBar);
  452.  
  453.     // create the listbox in which we will show misc messages as they come
  454.     m_lbox = new wxListBox(this, -1);
  455.     wxFont font(12, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL,
  456.                 wxFONTWEIGHT_NORMAL);
  457.     if ( font.Ok() )
  458.         m_lbox->SetFont(font);
  459.  
  460. #if wxUSE_STATUSBAR
  461.     // create a status bar just for fun (by default with 1 pane only)
  462.     CreateStatusBar();
  463.     SetStatusText(_T("Welcome to wxWindows exec sample!"));
  464. #endif // wxUSE_STATUSBAR
  465. }
  466.  
  467. // ----------------------------------------------------------------------------
  468. // event handlers: file and help menu
  469. // ----------------------------------------------------------------------------
  470.  
  471. void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
  472. {
  473.     // TRUE is to force the frame to close
  474.     Close(TRUE);
  475. }
  476.  
  477. void MyFrame::OnClear(wxCommandEvent& WXUNUSED(event))
  478. {
  479.     m_lbox->Clear();
  480. }
  481.  
  482. void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
  483. {
  484.     wxMessageBox(_T("Exec wxWindows Sample\n⌐ 2000-2002 Vadim Zeitlin"),
  485.                  _T("About Exec"), wxOK | wxICON_INFORMATION, this);
  486. }
  487.  
  488. void MyFrame::OnKill(wxCommandEvent& WXUNUSED(event))
  489. {
  490.     long pid = wxGetNumberFromUser(_T("Please specify the process to kill"),
  491.                                    _T("Enter PID:"),
  492.                                    _T("Exec question"),
  493.                                    m_pidLast,
  494.                                    // we need the full unsigned int range
  495.                                    -INT_MAX, INT_MAX,
  496.                                    this);
  497.     if ( pid == -1 )
  498.     {
  499.         // cancelled
  500.         return;
  501.     }
  502.  
  503.     static const wxString signalNames[] =
  504.     {
  505.         _T("Just test (SIGNONE)"),
  506.         _T("Hangup (SIGHUP)"),
  507.         _T("Interrupt (SIGINT)"),
  508.         _T("Quit (SIGQUIT)"),
  509.         _T("Illegal instruction (SIGILL)"),
  510.         _T("Trap (SIGTRAP)"),
  511.         _T("Abort (SIGABRT)"),
  512.         _T("Emulated trap (SIGEMT)"),
  513.         _T("FP exception (SIGFPE)"),
  514.         _T("Kill (SIGKILL)"),
  515.         _T("Bus (SIGBUS)"),
  516.         _T("Segment violation (SIGSEGV)"),
  517.         _T("System (SIGSYS)"),
  518.         _T("Broken pipe (SIGPIPE)"),
  519.         _T("Alarm (SIGALRM)"),
  520.         _T("Terminate (SIGTERM)"),
  521.     };
  522.  
  523.     int sig = wxGetSingleChoiceIndex(_T("How to kill the process?"),
  524.                                      _T("Exec question"),
  525.                                      WXSIZEOF(signalNames), signalNames,
  526.                                      this);
  527.     switch ( sig )
  528.     {
  529.         default:
  530.             wxFAIL_MSG( _T("unexpected return value") );
  531.             // fall through
  532.  
  533.         case -1:
  534.             // cancelled
  535.             return;
  536.  
  537.         case wxSIGNONE:
  538.         case wxSIGHUP:
  539.         case wxSIGINT:
  540.         case wxSIGQUIT:
  541.         case wxSIGILL:
  542.         case wxSIGTRAP:
  543.         case wxSIGABRT:
  544.         case wxSIGEMT:
  545.         case wxSIGFPE:
  546.         case wxSIGKILL:
  547.         case wxSIGBUS:
  548.         case wxSIGSEGV:
  549.         case wxSIGSYS:
  550.         case wxSIGPIPE:
  551.         case wxSIGALRM:
  552.         case wxSIGTERM:
  553.             break;
  554.     }
  555.  
  556.     if ( sig == 0 )
  557.     {
  558.         if ( wxProcess::Exists(pid) )
  559.             wxLogStatus(_T("Process %ld is running."), pid);
  560.         else
  561.             wxLogStatus(_T("No process with pid = %ld."), pid);
  562.     }
  563.     else // not SIGNONE
  564.     {
  565.         wxKillError rc = wxProcess::Kill(pid, (wxSignal)sig);
  566.         if ( rc == wxKILL_OK )
  567.         {
  568.             wxLogStatus(_T("Process %ld killed with signal %d."), pid, sig);
  569.         }
  570.         else
  571.         {
  572.             static const wxChar *errorText[] =
  573.             {
  574.                 _T(""), // no error
  575.                 _T("signal not supported"),
  576.                 _T("permission denied"),
  577.                 _T("no such process"),
  578.                 _T("unspecified error"),
  579.             };
  580.  
  581.             wxLogStatus(_T("Failed to kill process %ld with signal %d: %s"),
  582.                         pid, sig, errorText[rc]);
  583.         }
  584.     }
  585. }
  586.  
  587. // ----------------------------------------------------------------------------
  588. // event handlers: exec menu
  589. // ----------------------------------------------------------------------------
  590.  
  591. void MyFrame::DoAsyncExec(const wxString& cmd)
  592. {
  593.     wxProcess *process = new MyProcess(this, cmd);
  594.     m_pidLast = wxExecute(cmd, wxEXEC_ASYNC, process);
  595.     if ( !m_pidLast )
  596.     {
  597.         wxLogError( _T("Execution of '%s' failed."), cmd.c_str() );
  598.  
  599.         delete process;
  600.     }
  601.     else
  602.     {
  603.         wxLogStatus( _T("Process %ld (%s) launched."),
  604.             m_pidLast, cmd.c_str() );
  605.  
  606.         m_cmdLast = cmd;
  607.     }
  608. }
  609.  
  610. void MyFrame::OnSyncExec(wxCommandEvent& WXUNUSED(event))
  611. {
  612.     wxString cmd = wxGetTextFromUser(_T("Enter the command: "),
  613.                                      DIALOG_TITLE,
  614.                                      m_cmdLast);
  615.  
  616.     if ( !cmd )
  617.         return;
  618.  
  619.     wxLogStatus( _T("'%s' is running please wait..."), cmd.c_str() );
  620.  
  621.     int code = wxExecute(cmd, wxEXEC_SYNC);
  622.  
  623.     wxLogStatus(_T("Process '%s' terminated with exit code %d."),
  624.         cmd.c_str(), code);
  625.  
  626.     m_cmdLast = cmd;
  627. }
  628.  
  629. void MyFrame::OnAsyncExec(wxCommandEvent& WXUNUSED(event))
  630. {
  631.     wxString cmd = wxGetTextFromUser(_T("Enter the command: "),
  632.                                      DIALOG_TITLE,
  633.                                      m_cmdLast);
  634.  
  635.     if ( !cmd )
  636.         return;
  637.  
  638.     DoAsyncExec(cmd);
  639. }
  640.  
  641. void MyFrame::OnShell(wxCommandEvent& WXUNUSED(event))
  642. {
  643.     wxString cmd = wxGetTextFromUser(_T("Enter the command: "),
  644.                                      DIALOG_TITLE,
  645.                                      m_cmdLast);
  646.  
  647.     if ( !cmd )
  648.         return;
  649.  
  650.     int code = wxShell(cmd);
  651.     wxLogStatus(_T("Shell command '%s' terminated with exit code %d."),
  652.                 cmd.c_str(), code);
  653.     m_cmdLast = cmd;
  654. }
  655.  
  656. void MyFrame::OnExecWithRedirect(wxCommandEvent& WXUNUSED(event))
  657. {
  658.     wxString cmd = wxGetTextFromUser(_T("Enter the command: "),
  659.                                      DIALOG_TITLE,
  660.                                      m_cmdLast);
  661.  
  662.     if ( !cmd )
  663.         return;
  664.  
  665.     bool sync;
  666.     switch ( wxMessageBox(_T("Execute it synchronously?"),
  667.                           _T("Exec question"),
  668.                           wxYES_NO | wxCANCEL | wxICON_QUESTION, this) )
  669.     {
  670.         case wxYES:
  671.             sync = TRUE;
  672.             break;
  673.  
  674.         case wxNO:
  675.             sync = FALSE;
  676.             break;
  677.  
  678.         default:
  679.             return;
  680.     }
  681.  
  682.     if ( sync )
  683.     {
  684.         wxArrayString output, errors;
  685.         int code = wxExecute(cmd, output, errors);
  686.         wxLogStatus(_T("command '%s' terminated with exit code %d."),
  687.                     cmd.c_str(), code);
  688.  
  689.         if ( code != -1 )
  690.         {
  691.             ShowOutput(cmd, output, _T("Output"));
  692.             ShowOutput(cmd, errors, _T("Errors"));
  693.         }
  694.     }
  695.     else // async exec
  696.     {
  697.         MyPipedProcess *process = new MyPipedProcess(this, cmd);
  698.         if ( !wxExecute(cmd, wxEXEC_ASYNC, process) )
  699.         {
  700.             wxLogError(_T("Execution of '%s' failed."), cmd.c_str());
  701.  
  702.             delete process;
  703.         }
  704.         else
  705.         {
  706.             AddAsyncProcess(process);
  707.         }
  708.     }
  709.  
  710.     m_cmdLast = cmd;
  711. }
  712.  
  713. void MyFrame::OnExecWithPipe(wxCommandEvent& WXUNUSED(event))
  714. {
  715.     if ( !m_cmdLast )
  716.         m_cmdLast = _T("tr [a-z] [A-Z]");
  717.  
  718.     wxString cmd = wxGetTextFromUser(_T("Enter the command: "),
  719.                                      DIALOG_TITLE,
  720.                                      m_cmdLast);
  721.  
  722.     if ( !cmd )
  723.         return;
  724.  
  725.     wxString input = wxGetTextFromUser(_T("Enter the string to send to it: "),
  726.                                        DIALOG_TITLE);
  727.     if ( !input )
  728.         return;
  729.  
  730.     // always execute the filter asynchronously
  731.     MyPipedProcess2 *process = new MyPipedProcess2(this, cmd, input);
  732.     long pid = wxExecute(cmd, wxEXEC_ASYNC, process);
  733.     if ( pid )
  734.     {
  735.         wxLogStatus( _T("Process %ld (%s) launched."), pid, cmd.c_str() );
  736.  
  737.         AddAsyncProcess(process);
  738.     }
  739.     else
  740.     {
  741.         wxLogError(_T("Execution of '%s' failed."), cmd.c_str());
  742.  
  743.         delete process;
  744.     }
  745.  
  746.     m_cmdLast = cmd;
  747. }
  748.  
  749. void MyFrame::OnPOpen(wxCommandEvent& event)
  750. {
  751.     wxString cmd = wxGetTextFromUser(_T("Enter the command to launch: "),
  752.                                      DIALOG_TITLE,
  753.                                      m_cmdLast);
  754.     if ( cmd.empty() )
  755.         return;
  756.  
  757.     wxProcess *process = wxProcess::Open(cmd);
  758.     if ( !process )
  759.     {
  760.         wxLogError(_T("Failed to launch the command."));
  761.         return;
  762.     }
  763.  
  764.     wxOutputStream *out = process->GetOutputStream();
  765.     if ( !out )
  766.     {
  767.         wxLogError(_T("Failed to connect to child stdin"));
  768.         return;
  769.     }
  770.  
  771.     wxInputStream *in = process->GetInputStream();
  772.     if ( !in )
  773.     {
  774.         wxLogError(_T("Failed to connect to child stdout"));
  775.         return;
  776.     }
  777.  
  778.     new MyPipeFrame(this, cmd, process);
  779. }
  780.  
  781. void MyFrame::OnFileExec(wxCommandEvent& event)
  782. {
  783.     static wxString s_filename;
  784.  
  785.     wxString filename = wxLoadFileSelector(_T(""), _T(""), s_filename);
  786.     if ( !filename )
  787.         return;
  788.  
  789.     s_filename = filename;
  790.  
  791.     wxString ext = filename.AfterFirst(_T('.'));
  792.     wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(ext);
  793.     if ( !ft )
  794.     {
  795.         wxLogError(_T("Impossible to determine the file type for extension '%s'"),
  796.                    ext.c_str());
  797.         return;
  798.     }
  799.  
  800.     wxString cmd;
  801.     bool ok = ft->GetOpenCommand(&cmd,
  802.                                  wxFileType::MessageParameters(filename, _T("")));
  803.     delete ft;
  804.     if ( !ok )
  805.     {
  806.         wxLogError(_T("Impossible to find out how to open files of extension '%s'"),
  807.                    ext.c_str());
  808.         return;
  809.     }
  810.  
  811.     DoAsyncExec(cmd);
  812. }
  813.  
  814. // ----------------------------------------------------------------------------
  815. // DDE stuff
  816. // ----------------------------------------------------------------------------
  817.  
  818. #ifdef __WINDOWS__
  819.  
  820. bool MyFrame::GetDDEServer()
  821. {
  822.     wxString server = wxGetTextFromUser(_T("Server to connect to:"),
  823.                                         DIALOG_TITLE, m_server);
  824.     if ( !server )
  825.         return FALSE;
  826.  
  827.     m_server = server;
  828.  
  829.     wxString topic = wxGetTextFromUser(_T("DDE topic:"), DIALOG_TITLE, m_topic);
  830.     if ( !topic )
  831.         return FALSE;
  832.  
  833.     m_topic = topic;
  834.  
  835.     wxString cmd = wxGetTextFromUser(_T("DDE command:"), DIALOG_TITLE, m_cmdDde);
  836.     if ( !cmd )
  837.         return FALSE;
  838.  
  839.     m_cmdDde = cmd;
  840.  
  841.     return TRUE;
  842. }
  843.  
  844. void MyFrame::OnDDEExec(wxCommandEvent& WXUNUSED(event))
  845. {
  846.     if ( !GetDDEServer() )
  847.         return;
  848.  
  849.     wxDDEClient client;
  850.     wxConnectionBase *conn = client.MakeConnection(_T(""), m_server, m_topic);
  851.     if ( !conn )
  852.     {
  853.         wxLogError(_T("Failed to connect to the DDE server '%s'."),
  854.                    m_server.c_str());
  855.     }
  856.     else
  857.     {
  858.         if ( !conn->Execute(m_cmdDde) )
  859.         {
  860.             wxLogError(_T("Failed to execute command '%s' via DDE."),
  861.                        m_cmdDde.c_str());
  862.         }
  863.         else
  864.         {
  865.             wxLogStatus(_T("Successfully executed DDE command"));
  866.         }
  867.     }
  868. }
  869.  
  870. void MyFrame::OnDDERequest(wxCommandEvent& WXUNUSED(event))
  871. {
  872.     if ( !GetDDEServer() )
  873.         return;
  874.  
  875.     wxDDEClient client;
  876.     wxConnectionBase *conn = client.MakeConnection(_T(""), m_server, m_topic);
  877.     if ( !conn )
  878.     {
  879.         wxLogError(_T("Failed to connect to the DDE server '%s'."),
  880.                    m_server.c_str());
  881.     }
  882.     else
  883.     {
  884.         if ( !conn->Request(m_cmdDde) )
  885.         {
  886.             wxLogError(_T("Failed to  send request '%s' via DDE."),
  887.                        m_cmdDde.c_str());
  888.         }
  889.         else
  890.         {
  891.             wxLogStatus(_T("Successfully sent DDE request."));
  892.         }
  893.     }
  894. }
  895.  
  896. #endif // __WINDOWS__
  897.  
  898. // ----------------------------------------------------------------------------
  899. // various helpers
  900. // ----------------------------------------------------------------------------
  901.  
  902. // input polling
  903. void MyFrame::OnIdle(wxIdleEvent& event)
  904. {
  905.     size_t count = m_running.GetCount();
  906.     for ( size_t n = 0; n < count; n++ )
  907.     {
  908.         if ( m_running[n]->HasInput() )
  909.         {
  910.             event.RequestMore();
  911.         }
  912.     }
  913. }
  914.  
  915. void MyFrame::OnTimer(wxTimerEvent& WXUNUSED(event))
  916. {
  917.     wxWakeUpIdle();
  918. }
  919.  
  920. void MyFrame::OnProcessTerminated(MyPipedProcess *process)
  921. {
  922.     RemoveAsyncProcess(process);
  923. }
  924.  
  925.  
  926. void MyFrame::ShowOutput(const wxString& cmd,
  927.                          const wxArrayString& output,
  928.                          const wxString& title)
  929. {
  930.     size_t count = output.GetCount();
  931.     if ( !count )
  932.         return;
  933.  
  934.     m_lbox->Append(wxString::Format(_T("--- %s of '%s' ---"),
  935.                                     title.c_str(), cmd.c_str()));
  936.  
  937.     for ( size_t n = 0; n < count; n++ )
  938.     {
  939.         m_lbox->Append(output[n]);
  940.     }
  941.  
  942.     m_lbox->Append(wxString::Format(_T("--- End of %s ---"),
  943.                                     title.Lower().c_str()));
  944. }
  945.  
  946. // ----------------------------------------------------------------------------
  947. // MyProcess
  948. // ----------------------------------------------------------------------------
  949.  
  950. void MyProcess::OnTerminate(int pid, int status)
  951. {
  952.     wxLogStatus(m_parent, _T("Process %u ('%s') terminated with exit code %d."),
  953.                 pid, m_cmd.c_str(), status);
  954.  
  955.     // we're not needed any more
  956.     delete this;
  957. }
  958.  
  959. // ----------------------------------------------------------------------------
  960. // MyPipedProcess
  961. // ----------------------------------------------------------------------------
  962.  
  963. bool MyPipedProcess::HasInput()
  964. {
  965.     bool hasInput = FALSE;
  966.  
  967.     if ( IsInputAvailable() )
  968.     {
  969.         wxTextInputStream tis(*GetInputStream());
  970.  
  971.         // this assumes that the output is always line buffered
  972.         wxString msg;
  973.         msg << m_cmd << _T(" (stdout): ") << tis.ReadLine();
  974.  
  975.         m_parent->GetLogListBox()->Append(msg);
  976.  
  977.         hasInput = TRUE;
  978.     }
  979.  
  980.     if ( IsErrorAvailable() )
  981.     {
  982.         wxTextInputStream tis(*GetErrorStream());
  983.  
  984.         // this assumes that the output is always line buffered
  985.         wxString msg;
  986.         msg << m_cmd << _T(" (stderr): ") << tis.ReadLine();
  987.  
  988.         m_parent->GetLogListBox()->Append(msg);
  989.  
  990.         hasInput = TRUE;
  991.     }
  992.  
  993.     return hasInput;
  994. }
  995.  
  996. void MyPipedProcess::OnTerminate(int pid, int status)
  997. {
  998.     // show the rest of the output
  999.     while ( HasInput() )
  1000.         ;
  1001.  
  1002.     m_parent->OnProcessTerminated(this);
  1003.  
  1004.     MyProcess::OnTerminate(pid, status);
  1005. }
  1006.  
  1007. // ----------------------------------------------------------------------------
  1008. // MyPipedProcess2
  1009. // ----------------------------------------------------------------------------
  1010.  
  1011. bool MyPipedProcess2::HasInput()
  1012. {
  1013.     if ( !!m_input )
  1014.     {
  1015.         wxTextOutputStream os(*GetOutputStream());
  1016.         os.WriteString(m_input);
  1017.  
  1018.         CloseOutput();
  1019.         m_input.clear();
  1020.  
  1021.         // call us once again - may be we'll have output
  1022.         return TRUE;
  1023.     }
  1024.  
  1025.     return MyPipedProcess::HasInput();
  1026. }
  1027.  
  1028. // ============================================================================
  1029. // MyPipeFrame implementation
  1030. // ============================================================================
  1031.  
  1032. MyPipeFrame::MyPipeFrame(wxFrame *parent,
  1033.                          const wxString& cmd,
  1034.                          wxProcess *process)
  1035.            : wxFrame(parent, -1, cmd),
  1036.              m_process(process),
  1037.              // in a real program we'd check that the streams are !NULL here
  1038.              m_in(*process->GetInputStream()),
  1039.              m_out(*process->GetOutputStream())
  1040. {
  1041.     m_process->SetNextHandler(this);
  1042.  
  1043.     wxPanel *panel = new wxPanel(this, -1);
  1044.  
  1045.     m_textIn = new wxTextCtrl(panel, -1, _T(""),
  1046.                               wxDefaultPosition, wxDefaultSize,
  1047.                               wxTE_PROCESS_ENTER);
  1048.     m_textOut = new wxTextCtrl(panel, -1, _T(""));
  1049.     m_textOut->SetEditable(FALSE);
  1050.  
  1051.     wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL);
  1052.     sizerTop->Add(m_textIn, 0, wxGROW | wxALL, 5);
  1053.  
  1054.     wxSizer *sizerBtns = new wxBoxSizer(wxHORIZONTAL);
  1055.     sizerBtns->Add(new wxButton(panel, Exec_Btn_Send, _T("&Send")), 0,
  1056.                    wxALL, 10);
  1057.     sizerBtns->Add(new wxButton(panel, Exec_Btn_Get, _T("&Get")), 0,
  1058.                    wxALL, 10);
  1059.  
  1060.     sizerTop->Add(sizerBtns, 0, wxCENTRE | wxALL, 5);
  1061.     sizerTop->Add(m_textOut, 0, wxGROW | wxALL, 5);
  1062.  
  1063.     panel->SetSizer(sizerTop);
  1064.     sizerTop->Fit(this);
  1065.  
  1066.     Show();
  1067. }
  1068.  
  1069. void MyPipeFrame::DoGet()
  1070. {
  1071.     // we don't have any way to be notified when any input appears on the
  1072.     // stream so we have to poll it :-(
  1073.     //
  1074.     // NB: this really must be done because otherwise the other program might
  1075.     //     not have enough time to receive or process our data and we'd read
  1076.     //     an empty string
  1077.     while ( !m_process->IsInputAvailable() && m_process->IsInputOpened() )
  1078.         ;
  1079.  
  1080.     m_textOut->SetValue(m_in.ReadLine());
  1081. }
  1082.  
  1083. void MyPipeFrame::OnClose(wxCloseEvent& event)
  1084. {
  1085.     if ( m_process )
  1086.     {
  1087.         // we're not interested in getting the process termination notification
  1088.         // if we are closing it ourselves
  1089.         wxProcess *process = m_process;
  1090.         m_process = NULL;
  1091.         process->SetNextHandler(NULL);
  1092.  
  1093.         process->CloseOutput();
  1094.     }
  1095.  
  1096.     event.Skip();
  1097. }
  1098.  
  1099. void MyPipeFrame::OnProcessTerm(wxProcessEvent& event)
  1100. {
  1101.     delete m_process;
  1102.     m_process = NULL;
  1103.  
  1104.     wxLogWarning(_T("The other process has terminated, closing"));
  1105.  
  1106.     Close();
  1107. }
  1108.