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