~brian-sidebotham/wxwidgets-cmake/wxpython-2.9.4

« back to all changes in this revision

Viewing changes to samples/exec/exec.cpp

  • Committer: Brian Sidebotham
  • Date: 2013-08-03 14:30:08 UTC
  • Revision ID: brian.sidebotham@gmail.com-20130803143008-c7806tkych1tp6fc
Initial import into Bazaar

Show diffs side-by-side

added added

removed removed

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