exec.cpp 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575
  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. // Copyright: (c) Vadim Zeitlin
  8. // Licence: wxWindows licence
  9. /////////////////////////////////////////////////////////////////////////////
  10. // ============================================================================
  11. // declarations
  12. // ============================================================================
  13. // ----------------------------------------------------------------------------
  14. // headers
  15. // ----------------------------------------------------------------------------
  16. // For compilers that support precompilation, includes "wx/wx.h".
  17. #include "wx/wxprec.h"
  18. #ifdef __BORLANDC__
  19. #pragma hdrstop
  20. #endif
  21. // for all others, include the necessary headers (this file is usually all you
  22. // need because it includes almost all "standard" wxWidgets headers
  23. #ifndef WX_PRECOMP
  24. #include "wx/app.h"
  25. #include "wx/log.h"
  26. #include "wx/frame.h"
  27. #include "wx/panel.h"
  28. #include "wx/timer.h"
  29. #include "wx/utils.h"
  30. #include "wx/menu.h"
  31. #include "wx/msgdlg.h"
  32. #include "wx/textdlg.h"
  33. #include "wx/filedlg.h"
  34. #include "wx/choicdlg.h"
  35. #include "wx/button.h"
  36. #include "wx/checkbox.h"
  37. #include "wx/stattext.h"
  38. #include "wx/textctrl.h"
  39. #include "wx/listbox.h"
  40. #include "wx/sizer.h"
  41. #endif
  42. #include "wx/txtstrm.h"
  43. #include "wx/numdlg.h"
  44. #include "wx/textdlg.h"
  45. #include "wx/ffile.h"
  46. #include "wx/scopedptr.h"
  47. #include "wx/stopwatch.h"
  48. #include "wx/process.h"
  49. #include "wx/mimetype.h"
  50. #ifdef __WINDOWS__
  51. #include "wx/dde.h"
  52. #endif // __WINDOWS__
  53. #ifndef wxHAS_IMAGES_IN_RESOURCES
  54. #include "../sample.xpm"
  55. #endif
  56. // ----------------------------------------------------------------------------
  57. // the usual application and main frame classes
  58. // ----------------------------------------------------------------------------
  59. // Define a new application type, each program should derive a class from wxApp
  60. class MyApp : public wxApp
  61. {
  62. public:
  63. // override base class virtuals
  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. // Define an array of process pointers used by MyFrame
  71. class MyPipedProcess;
  72. WX_DEFINE_ARRAY_PTR(MyPipedProcess *, MyPipedProcessesArray);
  73. class MyProcess;
  74. WX_DEFINE_ARRAY_PTR(MyProcess *, MyProcessesArray);
  75. // Define a new frame type: this is going to be our main frame
  76. class MyFrame : public wxFrame
  77. {
  78. public:
  79. // ctor and dtor
  80. MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size);
  81. virtual ~MyFrame();
  82. // event handlers (these functions should _not_ be virtual)
  83. void OnQuit(wxCommandEvent& event);
  84. void OnKill(wxCommandEvent& event);
  85. void OnClear(wxCommandEvent& event);
  86. void OnBeginBusyCursor(wxCommandEvent& event);
  87. void OnEndBusyCursor(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);
  93. void OnPOpen(wxCommandEvent& event);
  94. void OnFileExec(wxCommandEvent& event);
  95. void OnFileLaunch(wxCommandEvent& event);
  96. void OnOpenURL(wxCommandEvent& event);
  97. void OnShowCommandForExt(wxCommandEvent& event);
  98. void OnAbout(wxCommandEvent& event);
  99. // polling output of async processes
  100. void OnIdleTimer(wxTimerEvent& event);
  101. void OnIdle(wxIdleEvent& event);
  102. // for MyPipedProcess
  103. void OnProcessTerminated(MyPipedProcess *process);
  104. wxListBox *GetLogListBox() const { return m_lbox; }
  105. // for MyProcess
  106. void OnAsyncTermination(MyProcess *process);
  107. // timer updating a counter in the background
  108. void OnBgTimer(wxTimerEvent& event);
  109. private:
  110. void ShowOutput(const wxString& cmd,
  111. const wxArrayString& output,
  112. const wxString& title);
  113. int GetExecFlags() const;
  114. void DoAsyncExec(const wxString& cmd);
  115. void AddAsyncProcess(MyProcess *process) { m_allAsync.push_back(process); }
  116. void AddPipedProcess(MyPipedProcess *process);
  117. void RemovePipedProcess(MyPipedProcess *process);
  118. // the PID of the last process we launched asynchronously
  119. long m_pidLast;
  120. // last command we executed
  121. wxString m_cmdLast;
  122. #ifdef __WINDOWS__
  123. void OnDDEExec(wxCommandEvent& event);
  124. void OnDDERequest(wxCommandEvent& event);
  125. bool GetDDEServer();
  126. // last params of a DDE transaction
  127. wxString m_server,
  128. m_topic,
  129. m_cmdDde;
  130. #endif // __WINDOWS__
  131. wxListBox *m_lbox;
  132. // array of running processes with redirected IO
  133. MyPipedProcessesArray m_running;
  134. // array of all asynchrously running processes
  135. MyProcessesArray m_allAsync;
  136. // the idle event wake up timer
  137. wxTimer m_timerIdleWakeUp;
  138. // a background timer allowing to easily check visually whether the
  139. // messages are processed or not
  140. wxTimer m_timerBg;
  141. // any class wishing to process wxWidgets events must use this macro
  142. wxDECLARE_EVENT_TABLE();
  143. };
  144. // ----------------------------------------------------------------------------
  145. // MyPipeFrame: allows the user to communicate with the child process
  146. // ----------------------------------------------------------------------------
  147. class MyPipeFrame : public wxFrame
  148. {
  149. public:
  150. MyPipeFrame(wxFrame *parent,
  151. const wxString& cmd,
  152. wxProcess *process);
  153. protected:
  154. void OnTextEnter(wxCommandEvent& WXUNUSED(event)) { DoSend(); }
  155. void OnBtnSend(wxCommandEvent& WXUNUSED(event)) { DoSend(); }
  156. void OnBtnSendFile(wxCommandEvent& WXUNUSED(event));
  157. void OnBtnGet(wxCommandEvent& WXUNUSED(event)) { DoGet(); }
  158. void OnBtnClose(wxCommandEvent& WXUNUSED(event)) { DoClose(); }
  159. void OnClose(wxCloseEvent& event);
  160. void OnProcessTerm(wxProcessEvent& event);
  161. void DoSend()
  162. {
  163. wxString s(m_textOut->GetValue());
  164. s += wxT('\n');
  165. m_out.Write(s.c_str(), s.length());
  166. m_textOut->Clear();
  167. DoGet();
  168. }
  169. void DoGet();
  170. void DoClose();
  171. private:
  172. void DoGetFromStream(wxTextCtrl *text, wxInputStream& in);
  173. void DisableInput();
  174. void DisableOutput();
  175. wxProcess *m_process;
  176. wxOutputStream &m_out;
  177. wxInputStream &m_in,
  178. &m_err;
  179. wxTextCtrl *m_textOut,
  180. *m_textIn,
  181. *m_textErr;
  182. wxDECLARE_EVENT_TABLE();
  183. };
  184. // ----------------------------------------------------------------------------
  185. // wxProcess-derived classes
  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. // instead of overriding this virtual function we might as well process the
  197. // event from it in the frame class - this might be more convenient in some
  198. // cases
  199. virtual void OnTerminate(int pid, int status);
  200. protected:
  201. MyFrame *m_parent;
  202. wxString m_cmd;
  203. };
  204. // A specialization of MyProcess for redirecting the output
  205. class MyPipedProcess : public MyProcess
  206. {
  207. public:
  208. MyPipedProcess(MyFrame *parent, const wxString& cmd)
  209. : MyProcess(parent, cmd)
  210. {
  211. Redirect();
  212. }
  213. virtual void OnTerminate(int pid, int status);
  214. virtual bool HasInput();
  215. };
  216. // A version of MyPipedProcess which also sends input to the stdin of the
  217. // child process
  218. class MyPipedProcess2 : public MyPipedProcess
  219. {
  220. public:
  221. MyPipedProcess2(MyFrame *parent, const wxString& cmd, const wxString& input)
  222. : MyPipedProcess(parent, cmd), m_input(input)
  223. {
  224. }
  225. virtual bool HasInput();
  226. private:
  227. wxString m_input;
  228. };
  229. // ----------------------------------------------------------------------------
  230. // constants
  231. // ----------------------------------------------------------------------------
  232. // IDs for the controls and the menu commands
  233. enum
  234. {
  235. // timer ids
  236. Exec_TimerIdle = 10,
  237. Exec_TimerBg,
  238. // menu items
  239. Exec_Kill = 100,
  240. Exec_ClearLog,
  241. Exec_BeginBusyCursor,
  242. Exec_EndBusyCursor,
  243. Exec_SyncExec = 200,
  244. Exec_AsyncExec,
  245. Exec_Shell,
  246. Exec_POpen,
  247. Exec_OpenFile,
  248. Exec_ShowCommandForExt,
  249. Exec_LaunchFile,
  250. Exec_OpenURL,
  251. Exec_DDEExec,
  252. Exec_DDERequest,
  253. Exec_Redirect,
  254. Exec_Pipe,
  255. Exec_Flags_HideConsole,
  256. Exec_Flags_ShowConsole,
  257. Exec_Flags_NoEvents,
  258. Exec_About = wxID_ABOUT,
  259. Exec_Quit = wxID_EXIT,
  260. // control ids
  261. Exec_Btn_Send = 1000,
  262. Exec_Btn_SendFile,
  263. Exec_Btn_Get,
  264. Exec_Btn_Close
  265. };
  266. static const wxChar *DIALOG_TITLE = wxT("Exec sample");
  267. // ----------------------------------------------------------------------------
  268. // event tables and other macros for wxWidgets
  269. // ----------------------------------------------------------------------------
  270. // the event tables connect the wxWidgets events with the functions (event
  271. // handlers) which process them. It can be also done at run-time, but for the
  272. // simple menu events like this the static method is much simpler.
  273. wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
  274. EVT_MENU(Exec_Quit, MyFrame::OnQuit)
  275. EVT_MENU(Exec_Kill, MyFrame::OnKill)
  276. EVT_MENU(Exec_ClearLog, MyFrame::OnClear)
  277. EVT_MENU(Exec_BeginBusyCursor, MyFrame::OnBeginBusyCursor)
  278. EVT_MENU(Exec_EndBusyCursor, MyFrame::OnEndBusyCursor)
  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. EVT_MENU(Exec_POpen, MyFrame::OnPOpen)
  285. EVT_MENU(Exec_OpenFile, MyFrame::OnFileExec)
  286. EVT_MENU(Exec_ShowCommandForExt, MyFrame::OnShowCommandForExt)
  287. EVT_MENU(Exec_LaunchFile, MyFrame::OnFileLaunch)
  288. EVT_MENU(Exec_OpenURL, MyFrame::OnOpenURL)
  289. #ifdef __WINDOWS__
  290. EVT_MENU(Exec_DDEExec, MyFrame::OnDDEExec)
  291. EVT_MENU(Exec_DDERequest, MyFrame::OnDDERequest)
  292. #endif // __WINDOWS__
  293. EVT_MENU(Exec_About, MyFrame::OnAbout)
  294. EVT_IDLE(MyFrame::OnIdle)
  295. EVT_TIMER(Exec_TimerIdle, MyFrame::OnIdleTimer)
  296. EVT_TIMER(Exec_TimerBg, MyFrame::OnBgTimer)
  297. wxEND_EVENT_TABLE()
  298. wxBEGIN_EVENT_TABLE(MyPipeFrame, wxFrame)
  299. EVT_BUTTON(Exec_Btn_Send, MyPipeFrame::OnBtnSend)
  300. EVT_BUTTON(Exec_Btn_SendFile, MyPipeFrame::OnBtnSendFile)
  301. EVT_BUTTON(Exec_Btn_Get, MyPipeFrame::OnBtnGet)
  302. EVT_BUTTON(Exec_Btn_Close, MyPipeFrame::OnBtnClose)
  303. EVT_TEXT_ENTER(wxID_ANY, MyPipeFrame::OnTextEnter)
  304. EVT_CLOSE(MyPipeFrame::OnClose)
  305. EVT_END_PROCESS(wxID_ANY, MyPipeFrame::OnProcessTerm)
  306. wxEND_EVENT_TABLE()
  307. // Create a new application object: this macro will allow wxWidgets to create
  308. // the application object during program execution (it's better than using a
  309. // static object for many reasons) and also declares the accessor function
  310. // wxGetApp() which will return the reference of the right type (i.e. MyApp and
  311. // not wxApp)
  312. IMPLEMENT_APP(MyApp)
  313. // ============================================================================
  314. // implementation
  315. // ============================================================================
  316. // ----------------------------------------------------------------------------
  317. // the application class
  318. // ----------------------------------------------------------------------------
  319. // `Main program' equivalent: the program execution "starts" here
  320. bool MyApp::OnInit()
  321. {
  322. if ( !wxApp::OnInit() )
  323. return false;
  324. // Create the main application window
  325. MyFrame *frame = new MyFrame(wxT("Exec wxWidgets sample"),
  326. wxDefaultPosition, wxSize(500, 140));
  327. // Show it
  328. frame->Show(true);
  329. // success: wxApp::OnRun() will be called which will enter the main message
  330. // loop and the application will run. If we returned false here, the
  331. // application would exit immediately.
  332. return true;
  333. }
  334. // ----------------------------------------------------------------------------
  335. // main frame
  336. // ----------------------------------------------------------------------------
  337. #ifdef __VISUALC__
  338. #pragma warning(disable: 4355) // this used in base member initializer list
  339. #endif
  340. // frame constructor
  341. MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
  342. : wxFrame((wxFrame *)NULL, wxID_ANY, title, pos, size),
  343. m_timerIdleWakeUp(this, Exec_TimerIdle),
  344. m_timerBg(this, Exec_TimerBg)
  345. {
  346. SetIcon(wxICON(sample));
  347. m_pidLast = 0;
  348. #ifdef __WXMAC__
  349. // we need this in order to allow the about menu relocation, since ABOUT is
  350. // not the default id of the about menu
  351. wxApp::s_macAboutMenuItemId = Exec_About;
  352. #endif
  353. // create a menu bar
  354. wxMenu *menuFile = new wxMenu(wxEmptyString, wxMENU_TEAROFF);
  355. menuFile->Append(Exec_Kill, wxT("&Kill process...\tCtrl-K"),
  356. wxT("Kill a process by PID"));
  357. menuFile->AppendSeparator();
  358. menuFile->Append(Exec_OpenFile, wxT("Open &file...\tCtrl-F"),
  359. wxT("Launch the command to open this kind of files"));
  360. menuFile->Append(Exec_ShowCommandForExt,
  361. "Show association for extension...\tShift-Ctrl-A",
  362. "Show the command associated with the given extension");
  363. menuFile->Append(Exec_LaunchFile, wxT("La&unch file...\tShift-Ctrl-F"),
  364. wxT("Launch the default application associated with the file"));
  365. menuFile->Append(Exec_OpenURL, wxT("Open &URL...\tCtrl-U"),
  366. wxT("Launch the default browser with the given URL"));
  367. menuFile->AppendSeparator();
  368. menuFile->Append(Exec_BeginBusyCursor, wxT("Show &busy cursor\tCtrl-C"));
  369. menuFile->Append(Exec_EndBusyCursor, wxT("Show &normal cursor\tShift-Ctrl-C"));
  370. menuFile->AppendSeparator();
  371. menuFile->Append(Exec_ClearLog, wxT("&Clear log\tCtrl-L"),
  372. wxT("Clear the log window"));
  373. menuFile->AppendSeparator();
  374. menuFile->Append(Exec_Quit, wxT("E&xit\tAlt-X"), wxT("Quit this program"));
  375. wxMenu *flagsMenu = new wxMenu;
  376. flagsMenu->AppendCheckItem(Exec_Flags_HideConsole, "Always &hide console");
  377. flagsMenu->AppendCheckItem(Exec_Flags_ShowConsole, "Always &show console");
  378. flagsMenu->AppendCheckItem(Exec_Flags_NoEvents, "Disable &events",
  379. "This flag is valid for sync execution only");
  380. wxMenu *execMenu = new wxMenu;
  381. execMenu->AppendSubMenu(flagsMenu, "Execution flags");
  382. execMenu->AppendSeparator();
  383. execMenu->Append(Exec_SyncExec, wxT("Sync &execution...\tCtrl-E"),
  384. wxT("Launch a program and return when it terminates"));
  385. execMenu->Append(Exec_AsyncExec, wxT("&Async execution...\tCtrl-A"),
  386. wxT("Launch a program and return immediately"));
  387. execMenu->Append(Exec_Shell, wxT("Execute &shell command...\tCtrl-S"),
  388. wxT("Launch a shell and execute a command in it"));
  389. execMenu->AppendSeparator();
  390. execMenu->Append(Exec_Redirect, wxT("Capture command &output...\tCtrl-O"),
  391. wxT("Launch a program and capture its output"));
  392. execMenu->Append(Exec_Pipe, wxT("&Pipe through command..."),
  393. wxT("Pipe a string through a filter"));
  394. execMenu->Append(Exec_POpen, wxT("&Open a pipe to a command...\tCtrl-P"),
  395. wxT("Open a pipe to and from another program"));
  396. #ifdef __WINDOWS__
  397. execMenu->AppendSeparator();
  398. execMenu->Append(Exec_DDEExec, wxT("Execute command via &DDE...\tCtrl-D"));
  399. execMenu->Append(Exec_DDERequest, wxT("Send DDE &request...\tCtrl-R"));
  400. #endif
  401. wxMenu *helpMenu = new wxMenu(wxEmptyString, wxMENU_TEAROFF);
  402. helpMenu->Append(Exec_About, wxT("&About\tF1"), wxT("Show about dialog"));
  403. // now append the freshly created menu to the menu bar...
  404. wxMenuBar *menuBar = new wxMenuBar();
  405. menuBar->Append(menuFile, wxT("&File"));
  406. menuBar->Append(execMenu, wxT("&Exec"));
  407. menuBar->Append(helpMenu, wxT("&Help"));
  408. // ... and attach this menu bar to the frame
  409. SetMenuBar(menuBar);
  410. // create the listbox in which we will show misc messages as they come
  411. m_lbox = new wxListBox(this, wxID_ANY);
  412. wxFont font(12, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL,
  413. wxFONTWEIGHT_NORMAL);
  414. if ( font.IsOk() )
  415. m_lbox->SetFont(font);
  416. #if wxUSE_STATUSBAR
  417. // create a status bar just for fun (by default with 1 pane only)
  418. CreateStatusBar(2);
  419. SetStatusText(wxT("Welcome to wxWidgets exec sample!"));
  420. #endif // wxUSE_STATUSBAR
  421. m_timerBg.Start(1000);
  422. }
  423. MyFrame::~MyFrame()
  424. {
  425. // any processes left until now must be deleted manually: normally this is
  426. // done when the associated process terminates but it must be still running
  427. // if this didn't happen until now
  428. for ( size_t n = 0; n < m_allAsync.size(); n++ )
  429. {
  430. delete m_allAsync[n];
  431. }
  432. }
  433. // ----------------------------------------------------------------------------
  434. // event handlers: file and help menu
  435. // ----------------------------------------------------------------------------
  436. void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
  437. {
  438. // true is to force the frame to close
  439. Close(true);
  440. }
  441. void MyFrame::OnClear(wxCommandEvent& WXUNUSED(event))
  442. {
  443. m_lbox->Clear();
  444. }
  445. void MyFrame::OnBeginBusyCursor(wxCommandEvent& WXUNUSED(event))
  446. {
  447. wxBeginBusyCursor();
  448. }
  449. void MyFrame::OnEndBusyCursor(wxCommandEvent& WXUNUSED(event))
  450. {
  451. wxEndBusyCursor();
  452. }
  453. void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
  454. {
  455. wxMessageBox(wxT("Exec wxWidgets Sample\n(c) 2000-2002 Vadim Zeitlin"),
  456. wxT("About Exec"), wxOK | wxICON_INFORMATION, this);
  457. }
  458. void MyFrame::OnKill(wxCommandEvent& WXUNUSED(event))
  459. {
  460. long pid = wxGetNumberFromUser(wxT("Please specify the process to kill"),
  461. wxT("Enter PID:"),
  462. wxT("Exec question"),
  463. m_pidLast,
  464. // we need the full unsigned int range
  465. -INT_MAX, INT_MAX,
  466. this);
  467. if ( pid == -1 )
  468. {
  469. // cancelled
  470. return;
  471. }
  472. m_pidLast = pid;
  473. static const wxString signalNames[] =
  474. {
  475. wxT("Just test (SIGNONE)"),
  476. wxT("Hangup (SIGHUP)"),
  477. wxT("Interrupt (SIGINT)"),
  478. wxT("Quit (SIGQUIT)"),
  479. wxT("Illegal instruction (SIGILL)"),
  480. wxT("Trap (SIGTRAP)"),
  481. wxT("Abort (SIGABRT)"),
  482. wxT("Emulated trap (SIGEMT)"),
  483. wxT("FP exception (SIGFPE)"),
  484. wxT("Kill (SIGKILL)"),
  485. wxT("Bus (SIGBUS)"),
  486. wxT("Segment violation (SIGSEGV)"),
  487. wxT("System (SIGSYS)"),
  488. wxT("Broken pipe (SIGPIPE)"),
  489. wxT("Alarm (SIGALRM)"),
  490. wxT("Terminate (SIGTERM)"),
  491. };
  492. static int s_sigLast = wxSIGNONE;
  493. int sig = wxGetSingleChoiceIndex(wxT("How to kill the process?"),
  494. wxT("Exec question"),
  495. WXSIZEOF(signalNames), signalNames,
  496. s_sigLast,
  497. this);
  498. switch ( sig )
  499. {
  500. default:
  501. wxFAIL_MSG( wxT("unexpected return value") );
  502. // fall through
  503. case -1:
  504. // cancelled
  505. return;
  506. case wxSIGNONE:
  507. case wxSIGHUP:
  508. case wxSIGINT:
  509. case wxSIGQUIT:
  510. case wxSIGILL:
  511. case wxSIGTRAP:
  512. case wxSIGABRT:
  513. case wxSIGEMT:
  514. case wxSIGFPE:
  515. case wxSIGKILL:
  516. case wxSIGBUS:
  517. case wxSIGSEGV:
  518. case wxSIGSYS:
  519. case wxSIGPIPE:
  520. case wxSIGALRM:
  521. case wxSIGTERM:
  522. break;
  523. }
  524. s_sigLast = sig;
  525. if ( sig == wxSIGNONE )
  526. {
  527. // This simply calls Kill(wxSIGNONE) but using it is more convenient.
  528. if ( wxProcess::Exists(pid) )
  529. {
  530. wxLogStatus(wxT("Process %ld is running."), pid);
  531. }
  532. else
  533. {
  534. wxLogStatus(wxT("No process with pid = %ld."), pid);
  535. }
  536. }
  537. else // not SIGNONE
  538. {
  539. wxKillError rc = wxProcess::Kill(pid, (wxSignal)sig);
  540. if ( rc == wxKILL_OK )
  541. {
  542. wxLogStatus(wxT("Process %ld killed with signal %d."), pid, sig);
  543. }
  544. else
  545. {
  546. static const wxChar *errorText[] =
  547. {
  548. wxT(""), // no error
  549. wxT("signal not supported"),
  550. wxT("permission denied"),
  551. wxT("no such process"),
  552. wxT("unspecified error"),
  553. };
  554. wxLogStatus(wxT("Failed to kill process %ld with signal %d: %s"),
  555. pid, sig, errorText[rc]);
  556. }
  557. }
  558. }
  559. // ----------------------------------------------------------------------------
  560. // execution options dialog
  561. // ----------------------------------------------------------------------------
  562. enum ExecQueryDialogID
  563. {
  564. TEXT_EXECUTABLE,
  565. TEXT_CWD,
  566. TEXT_ENVIRONMENT
  567. };
  568. class ExecQueryDialog : public wxDialog
  569. {
  570. public:
  571. ExecQueryDialog(const wxString& cmd);
  572. wxString GetExecutable() const
  573. {
  574. return m_executable->GetValue();
  575. }
  576. wxString GetWorkDir() const
  577. {
  578. return m_useCWD->GetValue() ? m_cwdtext->GetValue() : wxString();
  579. }
  580. void GetEnvironment(wxEnvVariableHashMap& env);
  581. private:
  582. void OnUpdateWorkingDirectoryUI(wxUpdateUIEvent& event)
  583. {
  584. event.Enable(m_useCWD->GetValue());
  585. }
  586. void OnUpdateEnvironmentUI(wxUpdateUIEvent& event)
  587. {
  588. event.Enable(m_useEnv->GetValue());
  589. }
  590. wxTextCtrl* m_executable;
  591. wxTextCtrl* m_cwdtext;
  592. wxTextCtrl* m_envtext;
  593. wxCheckBox* m_useCWD;
  594. wxCheckBox* m_useEnv;
  595. wxDECLARE_EVENT_TABLE();
  596. };
  597. wxBEGIN_EVENT_TABLE(ExecQueryDialog, wxDialog)
  598. EVT_UPDATE_UI(TEXT_CWD, ExecQueryDialog::OnUpdateWorkingDirectoryUI)
  599. EVT_UPDATE_UI(TEXT_ENVIRONMENT, ExecQueryDialog::OnUpdateEnvironmentUI)
  600. wxEND_EVENT_TABLE()
  601. ExecQueryDialog::ExecQueryDialog(const wxString& cmd)
  602. : wxDialog(NULL, wxID_ANY, DIALOG_TITLE,
  603. wxDefaultPosition, wxDefaultSize,
  604. wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
  605. {
  606. wxSizer* globalSizer = new wxBoxSizer(wxVERTICAL);
  607. m_executable = new wxTextCtrl(this, TEXT_EXECUTABLE, wxString());
  608. m_cwdtext = new wxTextCtrl(this, TEXT_CWD, wxString());
  609. m_envtext = new wxTextCtrl(this, TEXT_ENVIRONMENT, wxString(),
  610. wxDefaultPosition, wxSize(300, 200),
  611. wxTE_MULTILINE|wxHSCROLL);
  612. const wxSizerFlags flagsExpand = wxSizerFlags().Expand().Border();
  613. globalSizer->Add(new wxStaticText(this, wxID_ANY, "Enter the command: "),
  614. flagsExpand);
  615. globalSizer->Add(m_executable, flagsExpand);
  616. m_useCWD = new wxCheckBox(this, wxID_ANY, "Working directory: ");
  617. globalSizer->Add(m_useCWD, flagsExpand);
  618. globalSizer->Add(m_cwdtext, flagsExpand);
  619. m_useEnv = new wxCheckBox(this, wxID_ANY, "Environment: ");
  620. globalSizer->Add(m_useEnv, flagsExpand);
  621. globalSizer->Add(m_envtext, wxSizerFlags(flagsExpand).Proportion(1));
  622. globalSizer->Add(CreateStdDialogButtonSizer(wxOK|wxCANCEL), flagsExpand);
  623. SetSizerAndFit(globalSizer);
  624. m_executable->SetValue(cmd);
  625. m_cwdtext->SetValue(wxGetCwd());
  626. wxEnvVariableHashMap env;
  627. if ( wxGetEnvMap(&env) )
  628. {
  629. for ( wxEnvVariableHashMap::iterator it = env.begin();
  630. it != env.end();
  631. ++it )
  632. {
  633. m_envtext->AppendText(it->first + '=' + it->second + '\n');
  634. }
  635. }
  636. m_useCWD->SetValue(false);
  637. m_useEnv->SetValue(false);
  638. }
  639. void ExecQueryDialog::GetEnvironment(wxEnvVariableHashMap& env)
  640. {
  641. env.clear();
  642. if ( m_useEnv->GetValue() )
  643. {
  644. wxString name,
  645. value;
  646. const int nb = m_envtext->GetNumberOfLines();
  647. for ( int l = 0; l < nb; l++ )
  648. {
  649. const wxString line = m_envtext->GetLineText(l).Trim();
  650. if ( !line.empty() )
  651. {
  652. name = line.BeforeFirst('=', &value);
  653. if ( name.empty() )
  654. {
  655. wxLogWarning("Skipping invalid environment line \"%s\".", line);
  656. continue;
  657. }
  658. env[name] = value;
  659. }
  660. }
  661. }
  662. }
  663. static bool QueryExec(wxString& cmd, wxExecuteEnv& env)
  664. {
  665. ExecQueryDialog dialog(cmd);
  666. if ( dialog.ShowModal() != wxID_OK )
  667. return false;
  668. cmd = dialog.GetExecutable();
  669. env.cwd = dialog.GetWorkDir();
  670. dialog.GetEnvironment(env.env);
  671. return true;
  672. }
  673. // ----------------------------------------------------------------------------
  674. // event handlers: exec menu
  675. // ----------------------------------------------------------------------------
  676. int MyFrame::GetExecFlags() const
  677. {
  678. wxMenuBar* const mbar = GetMenuBar();
  679. int flags = 0;
  680. if ( mbar->IsChecked(Exec_Flags_HideConsole) )
  681. flags |= wxEXEC_HIDE_CONSOLE;
  682. if ( mbar->IsChecked(Exec_Flags_ShowConsole) )
  683. flags |= wxEXEC_SHOW_CONSOLE;
  684. if ( mbar->IsChecked(Exec_Flags_NoEvents) )
  685. flags |= wxEXEC_NOEVENTS;
  686. return flags;
  687. }
  688. void MyFrame::DoAsyncExec(const wxString& cmd)
  689. {
  690. MyProcess * const process = new MyProcess(this, cmd);
  691. m_pidLast = wxExecute(cmd, wxEXEC_ASYNC | GetExecFlags(), process);
  692. if ( !m_pidLast )
  693. {
  694. wxLogError(wxT("Execution of '%s' failed."), cmd.c_str());
  695. delete process;
  696. }
  697. else
  698. {
  699. wxLogStatus(wxT("Process %ld (%s) launched."), m_pidLast, cmd.c_str());
  700. m_cmdLast = cmd;
  701. // the parent frame keeps track of all async processes as it needs to
  702. // free them if we exit before the child process terminates
  703. AddAsyncProcess(process);
  704. }
  705. }
  706. void MyFrame::OnSyncExec(wxCommandEvent& WXUNUSED(event))
  707. {
  708. wxString cmd;
  709. wxExecuteEnv env;
  710. if ( !QueryExec(cmd, env) )
  711. return;
  712. wxLogStatus( wxT("'%s' is running please wait..."), cmd.c_str() );
  713. int code = wxExecute(cmd, wxEXEC_SYNC | GetExecFlags(), NULL, &env);
  714. wxLogStatus(wxT("Process '%s' terminated with exit code %d."),
  715. cmd.c_str(), code);
  716. m_cmdLast = cmd;
  717. }
  718. void MyFrame::OnAsyncExec(wxCommandEvent& WXUNUSED(event))
  719. {
  720. wxString cmd = wxGetTextFromUser(wxT("Enter the command: "),
  721. DIALOG_TITLE,
  722. m_cmdLast);
  723. if ( !cmd )
  724. return;
  725. DoAsyncExec(cmd);
  726. }
  727. void MyFrame::OnShell(wxCommandEvent& WXUNUSED(event))
  728. {
  729. wxString cmd = wxGetTextFromUser(wxT("Enter the command: "),
  730. DIALOG_TITLE,
  731. m_cmdLast);
  732. if ( !cmd )
  733. return;
  734. int code = wxShell(cmd);
  735. wxLogStatus(wxT("Shell command '%s' terminated with exit code %d."),
  736. cmd.c_str(), code);
  737. m_cmdLast = cmd;
  738. }
  739. void MyFrame::OnExecWithRedirect(wxCommandEvent& WXUNUSED(event))
  740. {
  741. if ( !m_cmdLast )
  742. {
  743. #ifdef __WXMSW__
  744. m_cmdLast = "type Makefile.in";
  745. #else
  746. m_cmdLast = "cat -n Makefile";
  747. #endif
  748. }
  749. wxString cmd = wxGetTextFromUser(wxT("Enter the command: "),
  750. DIALOG_TITLE,
  751. m_cmdLast);
  752. if ( !cmd )
  753. return;
  754. bool sync;
  755. switch ( wxMessageBox(wxT("Execute it synchronously?"),
  756. wxT("Exec question"),
  757. wxYES_NO | wxCANCEL | wxICON_QUESTION, this) )
  758. {
  759. case wxYES:
  760. sync = true;
  761. break;
  762. case wxNO:
  763. sync = false;
  764. break;
  765. default:
  766. return;
  767. }
  768. if ( sync )
  769. {
  770. wxLogStatus("\"%s\" is running please wait...", cmd);
  771. wxStopWatch sw;
  772. wxArrayString output, errors;
  773. int code = wxExecute(cmd, output, errors);
  774. wxLogStatus("Command \"%s\" terminated after %ldms; exit code %d.",
  775. cmd, sw.Time(), code);
  776. ShowOutput(cmd, output, wxT("Output"));
  777. ShowOutput(cmd, errors, wxT("Errors"));
  778. }
  779. else // async exec
  780. {
  781. MyPipedProcess *process = new MyPipedProcess(this, cmd);
  782. if ( !wxExecute(cmd, wxEXEC_ASYNC, process) )
  783. {
  784. wxLogError(wxT("Execution of '%s' failed."), cmd.c_str());
  785. delete process;
  786. }
  787. else
  788. {
  789. AddPipedProcess(process);
  790. }
  791. }
  792. m_cmdLast = cmd;
  793. }
  794. void MyFrame::OnExecWithPipe(wxCommandEvent& WXUNUSED(event))
  795. {
  796. if ( !m_cmdLast )
  797. m_cmdLast = wxT("tr [a-z] [A-Z]");
  798. wxString cmd = wxGetTextFromUser(wxT("Enter the command: "),
  799. DIALOG_TITLE,
  800. m_cmdLast);
  801. if ( !cmd )
  802. return;
  803. wxString input = wxGetTextFromUser(wxT("Enter the string to send to it: "),
  804. DIALOG_TITLE);
  805. if ( !input )
  806. return;
  807. // always execute the filter asynchronously
  808. MyPipedProcess2 *process = new MyPipedProcess2(this, cmd, input);
  809. long pid = wxExecute(cmd, wxEXEC_ASYNC, process);
  810. if ( pid )
  811. {
  812. wxLogStatus(wxT("Process %ld (%s) launched."), pid, cmd.c_str());
  813. AddPipedProcess(process);
  814. }
  815. else
  816. {
  817. wxLogError(wxT("Execution of '%s' failed."), cmd.c_str());
  818. delete process;
  819. }
  820. m_cmdLast = cmd;
  821. }
  822. void MyFrame::OnPOpen(wxCommandEvent& WXUNUSED(event))
  823. {
  824. wxString cmd = wxGetTextFromUser(wxT("Enter the command to launch: "),
  825. DIALOG_TITLE,
  826. m_cmdLast);
  827. if ( cmd.empty() )
  828. return;
  829. wxProcess *process = wxProcess::Open(cmd);
  830. if ( !process )
  831. {
  832. wxLogError(wxT("Failed to launch the command."));
  833. return;
  834. }
  835. wxLogVerbose(wxT("PID of the new process: %ld"), process->GetPid());
  836. wxOutputStream *out = process->GetOutputStream();
  837. if ( !out )
  838. {
  839. wxLogError(wxT("Failed to connect to child stdin"));
  840. return;
  841. }
  842. wxInputStream *in = process->GetInputStream();
  843. if ( !in )
  844. {
  845. wxLogError(wxT("Failed to connect to child stdout"));
  846. return;
  847. }
  848. new MyPipeFrame(this, cmd, process);
  849. }
  850. static wxString gs_lastFile;
  851. static bool AskUserForFileName()
  852. {
  853. wxString filename;
  854. #if wxUSE_FILEDLG
  855. filename = wxLoadFileSelector(wxT("any"), wxEmptyString, gs_lastFile);
  856. #else // !wxUSE_FILEDLG
  857. filename = wxGetTextFromUser(wxT("Enter the file name"), wxT("exec sample"),
  858. gs_lastFile);
  859. #endif // wxUSE_FILEDLG/!wxUSE_FILEDLG
  860. if ( filename.empty() )
  861. return false;
  862. gs_lastFile = filename;
  863. return true;
  864. }
  865. void MyFrame::OnFileExec(wxCommandEvent& WXUNUSED(event))
  866. {
  867. if ( !AskUserForFileName() )
  868. return;
  869. wxString ext = gs_lastFile.AfterLast(wxT('.'));
  870. wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(ext);
  871. if ( !ft )
  872. {
  873. wxLogError(wxT("Impossible to determine the file type for extension '%s'"),
  874. ext.c_str());
  875. return;
  876. }
  877. wxString cmd;
  878. bool ok = ft->GetOpenCommand(&cmd,
  879. wxFileType::MessageParameters(gs_lastFile));
  880. delete ft;
  881. if ( !ok )
  882. {
  883. wxLogError(wxT("Impossible to find out how to open files of extension '%s'"),
  884. ext.c_str());
  885. return;
  886. }
  887. DoAsyncExec(cmd);
  888. }
  889. void MyFrame::OnShowCommandForExt(wxCommandEvent& WXUNUSED(event))
  890. {
  891. static wxString s_ext;
  892. wxString ext = wxGetTextFromUser
  893. (
  894. "Enter the extension without leading dot",
  895. "Exec sample",
  896. s_ext,
  897. this
  898. );
  899. if ( ext.empty() )
  900. return;
  901. s_ext = ext;
  902. wxScopedPtr<wxFileType>
  903. ft(wxTheMimeTypesManager->GetFileTypeFromExtension(ext));
  904. if ( !ft )
  905. {
  906. wxLogError("Information for extension \"%s\" not found", ext);
  907. return;
  908. }
  909. const wxString cmd = ft->GetOpenCommand("file." + ext);
  910. if ( cmd.empty() )
  911. {
  912. wxLogWarning("Open command for extension \"%s\" not defined.", ext);
  913. return;
  914. }
  915. wxLogMessage("Open command for files of extension \"%s\" is\n%s",
  916. ext, cmd);
  917. }
  918. void MyFrame::OnFileLaunch(wxCommandEvent& WXUNUSED(event))
  919. {
  920. if ( !AskUserForFileName() )
  921. return;
  922. if ( !wxLaunchDefaultApplication(gs_lastFile) )
  923. {
  924. wxLogError("Opening \"%s\" in default application failed.", gs_lastFile);
  925. }
  926. }
  927. void MyFrame::OnOpenURL(wxCommandEvent& WXUNUSED(event))
  928. {
  929. static wxString s_url(wxT("http://www.wxwidgets.org/"));
  930. wxString filename = wxGetTextFromUser
  931. (
  932. wxT("Enter the URL"),
  933. wxT("exec sample"),
  934. s_url,
  935. this
  936. );
  937. if ( filename.empty() )
  938. return;
  939. s_url = filename;
  940. if ( !wxLaunchDefaultBrowser(s_url) )
  941. {
  942. wxLogError(wxT("Failed to open URL \"%s\""), s_url.c_str());
  943. }
  944. }
  945. // ----------------------------------------------------------------------------
  946. // DDE stuff
  947. // ----------------------------------------------------------------------------
  948. #ifdef __WINDOWS__
  949. bool MyFrame::GetDDEServer()
  950. {
  951. wxString server = wxGetTextFromUser(wxT("Server to connect to:"),
  952. DIALOG_TITLE, m_server);
  953. if ( !server )
  954. return false;
  955. m_server = server;
  956. wxString topic = wxGetTextFromUser(wxT("DDE topic:"), DIALOG_TITLE, m_topic);
  957. if ( !topic )
  958. return false;
  959. m_topic = topic;
  960. wxString cmd = wxGetTextFromUser(wxT("DDE command:"), DIALOG_TITLE, m_cmdDde);
  961. if ( !cmd )
  962. return false;
  963. m_cmdDde = cmd;
  964. return true;
  965. }
  966. void MyFrame::OnDDEExec(wxCommandEvent& WXUNUSED(event))
  967. {
  968. if ( !GetDDEServer() )
  969. return;
  970. wxDDEClient client;
  971. wxConnectionBase *conn = client.MakeConnection(wxEmptyString, m_server, m_topic);
  972. if ( !conn )
  973. {
  974. wxLogError(wxT("Failed to connect to the DDE server '%s'."),
  975. m_server.c_str());
  976. }
  977. else
  978. {
  979. if ( !conn->Execute(m_cmdDde) )
  980. {
  981. wxLogError(wxT("Failed to execute command '%s' via DDE."),
  982. m_cmdDde.c_str());
  983. }
  984. else
  985. {
  986. wxLogStatus(wxT("Successfully executed DDE command"));
  987. }
  988. }
  989. }
  990. void MyFrame::OnDDERequest(wxCommandEvent& WXUNUSED(event))
  991. {
  992. if ( !GetDDEServer() )
  993. return;
  994. wxDDEClient client;
  995. wxConnectionBase *conn = client.MakeConnection(wxEmptyString, m_server, m_topic);
  996. if ( !conn )
  997. {
  998. wxLogError(wxT("Failed to connect to the DDE server '%s'."),
  999. m_server.c_str());
  1000. }
  1001. else
  1002. {
  1003. if ( !conn->Request(m_cmdDde) )
  1004. {
  1005. wxLogError(wxT("Failed to send request '%s' via DDE."),
  1006. m_cmdDde.c_str());
  1007. }
  1008. else
  1009. {
  1010. wxLogStatus(wxT("Successfully sent DDE request."));
  1011. }
  1012. }
  1013. }
  1014. #endif // __WINDOWS__
  1015. // ----------------------------------------------------------------------------
  1016. // various helpers
  1017. // ----------------------------------------------------------------------------
  1018. // input polling
  1019. void MyFrame::OnIdle(wxIdleEvent& event)
  1020. {
  1021. size_t count = m_running.GetCount();
  1022. for ( size_t n = 0; n < count; n++ )
  1023. {
  1024. if ( m_running[n]->HasInput() )
  1025. {
  1026. event.RequestMore();
  1027. }
  1028. }
  1029. }
  1030. void MyFrame::OnIdleTimer(wxTimerEvent& WXUNUSED(event))
  1031. {
  1032. wxWakeUpIdle();
  1033. }
  1034. void MyFrame::OnBgTimer(wxTimerEvent& WXUNUSED(event))
  1035. {
  1036. static unsigned long s_ticks = 0;
  1037. SetStatusText(wxString::Format("%lu ticks", s_ticks++), 1);
  1038. }
  1039. void MyFrame::OnProcessTerminated(MyPipedProcess *process)
  1040. {
  1041. RemovePipedProcess(process);
  1042. }
  1043. void MyFrame::OnAsyncTermination(MyProcess *process)
  1044. {
  1045. m_allAsync.Remove(process);
  1046. delete process;
  1047. }
  1048. void MyFrame::AddPipedProcess(MyPipedProcess *process)
  1049. {
  1050. if ( m_running.IsEmpty() )
  1051. {
  1052. // we want to start getting the timer events to ensure that a
  1053. // steady stream of idle events comes in -- otherwise we
  1054. // wouldn't be able to poll the child process input
  1055. m_timerIdleWakeUp.Start(100);
  1056. }
  1057. //else: the timer is already running
  1058. m_running.Add(process);
  1059. m_allAsync.Add(process);
  1060. }
  1061. void MyFrame::RemovePipedProcess(MyPipedProcess *process)
  1062. {
  1063. m_running.Remove(process);
  1064. if ( m_running.IsEmpty() )
  1065. {
  1066. // we don't need to get idle events all the time any more
  1067. m_timerIdleWakeUp.Stop();
  1068. }
  1069. }
  1070. void MyFrame::ShowOutput(const wxString& cmd,
  1071. const wxArrayString& output,
  1072. const wxString& title)
  1073. {
  1074. size_t count = output.GetCount();
  1075. if ( !count )
  1076. return;
  1077. m_lbox->Append(wxString::Format(wxT("--- %s of '%s' ---"),
  1078. title.c_str(), cmd.c_str()));
  1079. for ( size_t n = 0; n < count; n++ )
  1080. {
  1081. m_lbox->Append(output[n]);
  1082. }
  1083. m_lbox->Append(wxString::Format(wxT("--- End of %s ---"),
  1084. title.Lower().c_str()));
  1085. }
  1086. // ----------------------------------------------------------------------------
  1087. // MyProcess
  1088. // ----------------------------------------------------------------------------
  1089. void MyProcess::OnTerminate(int pid, int status)
  1090. {
  1091. wxLogStatus(m_parent, wxT("Process %u ('%s') terminated with exit code %d."),
  1092. pid, m_cmd.c_str(), status);
  1093. m_parent->OnAsyncTermination(this);
  1094. }
  1095. // ----------------------------------------------------------------------------
  1096. // MyPipedProcess
  1097. // ----------------------------------------------------------------------------
  1098. bool MyPipedProcess::HasInput()
  1099. {
  1100. bool hasInput = false;
  1101. if ( IsInputAvailable() )
  1102. {
  1103. wxTextInputStream tis(*GetInputStream());
  1104. // this assumes that the output is always line buffered
  1105. wxString msg;
  1106. msg << m_cmd << wxT(" (stdout): ") << tis.ReadLine();
  1107. m_parent->GetLogListBox()->Append(msg);
  1108. hasInput = true;
  1109. }
  1110. if ( IsErrorAvailable() )
  1111. {
  1112. wxTextInputStream tis(*GetErrorStream());
  1113. // this assumes that the output is always line buffered
  1114. wxString msg;
  1115. msg << m_cmd << wxT(" (stderr): ") << tis.ReadLine();
  1116. m_parent->GetLogListBox()->Append(msg);
  1117. hasInput = true;
  1118. }
  1119. return hasInput;
  1120. }
  1121. void MyPipedProcess::OnTerminate(int pid, int status)
  1122. {
  1123. // show the rest of the output
  1124. while ( HasInput() )
  1125. ;
  1126. m_parent->OnProcessTerminated(this);
  1127. MyProcess::OnTerminate(pid, status);
  1128. }
  1129. // ----------------------------------------------------------------------------
  1130. // MyPipedProcess2
  1131. // ----------------------------------------------------------------------------
  1132. bool MyPipedProcess2::HasInput()
  1133. {
  1134. if ( !m_input.empty() )
  1135. {
  1136. wxTextOutputStream os(*GetOutputStream());
  1137. os.WriteString(m_input);
  1138. CloseOutput();
  1139. m_input.clear();
  1140. // call us once again - may be we'll have output
  1141. return true;
  1142. }
  1143. return MyPipedProcess::HasInput();
  1144. }
  1145. // ============================================================================
  1146. // MyPipeFrame implementation
  1147. // ============================================================================
  1148. MyPipeFrame::MyPipeFrame(wxFrame *parent,
  1149. const wxString& cmd,
  1150. wxProcess *process)
  1151. : wxFrame(parent, wxID_ANY, cmd),
  1152. m_process(process),
  1153. // in a real program we'd check that the streams are !NULL here
  1154. m_out(*process->GetOutputStream()),
  1155. m_in(*process->GetInputStream()),
  1156. m_err(*process->GetErrorStream())
  1157. {
  1158. m_process->SetNextHandler(this);
  1159. wxPanel *panel = new wxPanel(this, wxID_ANY);
  1160. m_textOut = new wxTextCtrl(panel, wxID_ANY, wxEmptyString,
  1161. wxDefaultPosition, wxDefaultSize,
  1162. wxTE_PROCESS_ENTER);
  1163. m_textIn = new wxTextCtrl(panel, wxID_ANY, wxEmptyString,
  1164. wxDefaultPosition, wxDefaultSize,
  1165. wxTE_MULTILINE | wxTE_RICH);
  1166. m_textIn->SetEditable(false);
  1167. m_textErr = new wxTextCtrl(panel, wxID_ANY, wxEmptyString,
  1168. wxDefaultPosition, wxDefaultSize,
  1169. wxTE_MULTILINE | wxTE_RICH);
  1170. m_textErr->SetEditable(false);
  1171. wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL);
  1172. sizerTop->Add(m_textOut, 0, wxGROW | wxALL, 5);
  1173. wxSizer *sizerBtns = new wxBoxSizer(wxHORIZONTAL);
  1174. sizerBtns->
  1175. Add(new wxButton(panel, Exec_Btn_Send, wxT("&Send")), 0, wxALL, 5);
  1176. sizerBtns->
  1177. Add(new wxButton(panel, Exec_Btn_SendFile, wxT("&File...")), 0, wxALL, 5);
  1178. sizerBtns->
  1179. Add(new wxButton(panel, Exec_Btn_Get, wxT("&Get")), 0, wxALL, 5);
  1180. sizerBtns->
  1181. Add(new wxButton(panel, Exec_Btn_Close, wxT("&Close")), 0, wxALL, 5);
  1182. sizerTop->Add(sizerBtns, 0, wxCENTRE | wxALL, 5);
  1183. sizerTop->Add(m_textIn, 1, wxGROW | wxALL, 5);
  1184. sizerTop->Add(m_textErr, 1, wxGROW | wxALL, 5);
  1185. panel->SetSizer(sizerTop);
  1186. sizerTop->Fit(this);
  1187. Show();
  1188. }
  1189. void MyPipeFrame::OnBtnSendFile(wxCommandEvent& WXUNUSED(event))
  1190. {
  1191. #if wxUSE_FILEDLG
  1192. wxFileDialog filedlg(this, wxT("Select file to send"));
  1193. if ( filedlg.ShowModal() != wxID_OK )
  1194. return;
  1195. wxFFile file(filedlg.GetFilename(), wxT("r"));
  1196. wxString data;
  1197. if ( !file.IsOpened() || !file.ReadAll(&data) )
  1198. return;
  1199. // can't write the entire string at once, this risk overflowing the pipe
  1200. // and we would dead lock
  1201. size_t len = data.length();
  1202. const wxChar *pc = data.c_str();
  1203. while ( len )
  1204. {
  1205. const size_t CHUNK_SIZE = 4096;
  1206. m_out.Write(pc, len > CHUNK_SIZE ? CHUNK_SIZE : len);
  1207. // note that not all data could have been written as we don't block on
  1208. // the write end of the pipe
  1209. const size_t lenChunk = m_out.LastWrite();
  1210. pc += lenChunk;
  1211. len -= lenChunk;
  1212. DoGet();
  1213. }
  1214. #endif // wxUSE_FILEDLG
  1215. }
  1216. void MyPipeFrame::DoGet()
  1217. {
  1218. // we don't have any way to be notified when any input appears on the
  1219. // stream so we have to poll it :-(
  1220. DoGetFromStream(m_textIn, m_in);
  1221. DoGetFromStream(m_textErr, m_err);
  1222. }
  1223. void MyPipeFrame::DoGetFromStream(wxTextCtrl *text, wxInputStream& in)
  1224. {
  1225. while ( in.CanRead() )
  1226. {
  1227. char buffer[4096];
  1228. buffer[in.Read(buffer, WXSIZEOF(buffer) - 1).LastRead()] = '\0';
  1229. text->AppendText(buffer);
  1230. }
  1231. }
  1232. void MyPipeFrame::DoClose()
  1233. {
  1234. m_process->CloseOutput();
  1235. DisableInput();
  1236. }
  1237. void MyPipeFrame::DisableInput()
  1238. {
  1239. m_textOut->SetEditable(false);
  1240. FindWindow(Exec_Btn_Send)->Disable();
  1241. FindWindow(Exec_Btn_SendFile)->Disable();
  1242. FindWindow(Exec_Btn_Close)->Disable();
  1243. }
  1244. void MyPipeFrame::DisableOutput()
  1245. {
  1246. FindWindow(Exec_Btn_Get)->Disable();
  1247. }
  1248. void MyPipeFrame::OnClose(wxCloseEvent& event)
  1249. {
  1250. if ( m_process )
  1251. {
  1252. // we're not interested in getting the process termination notification
  1253. // if we are closing it ourselves
  1254. wxProcess *process = m_process;
  1255. m_process = NULL;
  1256. process->SetNextHandler(NULL);
  1257. process->CloseOutput();
  1258. }
  1259. event.Skip();
  1260. }
  1261. void MyPipeFrame::OnProcessTerm(wxProcessEvent& WXUNUSED(event))
  1262. {
  1263. DoGet();
  1264. wxDELETE(m_process);
  1265. wxLogWarning(wxT("The other process has terminated, closing"));
  1266. DisableInput();
  1267. DisableOutput();
  1268. }