1/////////////////////////////////////////////////////////////////////////////
2// Name:        src/msw/utilsexc.cpp
3// Purpose:     wxExecute implementation for MSW
4// Author:      Julian Smart
5// Modified by:
6// Created:     04/01/98
7// RCS-ID:      $Id: utilsexc.cpp 54695 2008-07-18 22:22:16Z VZ $
8// Copyright:   (c) 1998-2002 wxWidgets dev team
9// Licence:     wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24    #pragma hdrstop
25#endif
26
27#ifndef WX_PRECOMP
28    #include "wx/utils.h"
29    #include "wx/app.h"
30    #include "wx/intl.h"
31    #include "wx/log.h"
32    #if wxUSE_STREAMS
33        #include "wx/stream.h"
34    #endif
35    #include "wx/module.h"
36#endif
37
38#include "wx/process.h"
39
40#include "wx/apptrait.h"
41
42
43#include "wx/msw/private.h"
44
45#include <ctype.h>
46
47#if !defined(__GNUWIN32__) && !defined(__SALFORDC__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
48    #include <direct.h>
49#ifndef __MWERKS__
50    #include <dos.h>
51#endif
52#endif
53
54#if defined(__GNUWIN32__)
55    #include <sys/unistd.h>
56    #include <sys/stat.h>
57#endif
58
59#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
60    #ifndef __UNIX__
61        #include <io.h>
62    #endif
63
64    #ifndef __GNUWIN32__
65        #include <shellapi.h>
66    #endif
67#endif
68
69#include <stdio.h>
70#include <stdlib.h>
71#include <string.h>
72#ifndef __WATCOMC__
73    #if !(defined(_MSC_VER) && (_MSC_VER > 800))
74        #include <errno.h>
75    #endif
76#endif
77#include <stdarg.h>
78
79#if wxUSE_IPC
80    #include "wx/dde.h"         // for WX_DDE hack in wxExecute
81#endif // wxUSE_IPC
82
83// implemented in utils.cpp
84extern "C" WXDLLIMPEXP_BASE HWND
85wxCreateHiddenWindow(LPCTSTR *pclassname, LPCTSTR classname, WNDPROC wndproc);
86
87// ----------------------------------------------------------------------------
88// constants
89// ----------------------------------------------------------------------------
90
91// this message is sent when the process we're waiting for terminates
92#define wxWM_PROC_TERMINATED (WM_USER + 10000)
93
94// ----------------------------------------------------------------------------
95// this module globals
96// ----------------------------------------------------------------------------
97
98// we need to create a hidden window to receive the process termination
99// notifications and for this we need a (Win) class name for it which we will
100// register the first time it's needed
101static const wxChar *wxMSWEXEC_WNDCLASSNAME = wxT("_wxExecute_Internal_Class");
102static const wxChar *gs_classForHiddenWindow = NULL;
103
104// ----------------------------------------------------------------------------
105// private types
106// ----------------------------------------------------------------------------
107
108// structure describing the process we're being waiting for
109struct wxExecuteData
110{
111public:
112    ~wxExecuteData()
113    {
114        if ( !::CloseHandle(hProcess) )
115        {
116            wxLogLastError(wxT("CloseHandle(hProcess)"));
117        }
118    }
119
120    HWND       hWnd;          // window to send wxWM_PROC_TERMINATED to
121    HANDLE     hProcess;      // handle of the process
122    DWORD      dwProcessId;   // pid of the process
123    wxProcess *handler;
124    DWORD      dwExitCode;    // the exit code of the process
125    bool       state;         // set to false when the process finishes
126};
127
128class wxExecuteModule : public wxModule
129{
130public:
131    virtual bool OnInit() { return true; }
132    virtual void OnExit()
133    {
134        if ( *gs_classForHiddenWindow )
135        {
136            if ( !::UnregisterClass(wxMSWEXEC_WNDCLASSNAME, wxGetInstance()) )
137            {
138                wxLogLastError(_T("UnregisterClass(wxExecClass)"));
139            }
140
141            gs_classForHiddenWindow = NULL;
142        }
143    }
144
145private:
146    DECLARE_DYNAMIC_CLASS(wxExecuteModule)
147};
148
149#if wxUSE_STREAMS && !defined(__WXWINCE__)
150
151// ----------------------------------------------------------------------------
152// wxPipeStreams
153// ----------------------------------------------------------------------------
154
155class wxPipeInputStream: public wxInputStream
156{
157public:
158    wxPipeInputStream(HANDLE hInput);
159    virtual ~wxPipeInputStream();
160
161    // returns true if the pipe is still opened
162    bool IsOpened() const { return m_hInput != INVALID_HANDLE_VALUE; }
163
164    // returns true if there is any data to be read from the pipe
165    virtual bool CanRead() const;
166
167protected:
168    size_t OnSysRead(void *buffer, size_t len);
169
170protected:
171    HANDLE m_hInput;
172
173    DECLARE_NO_COPY_CLASS(wxPipeInputStream)
174};
175
176class wxPipeOutputStream: public wxOutputStream
177{
178public:
179    wxPipeOutputStream(HANDLE hOutput);
180    virtual ~wxPipeOutputStream() { Close(); }
181    bool Close();
182
183protected:
184    size_t OnSysWrite(const void *buffer, size_t len);
185
186protected:
187    HANDLE m_hOutput;
188
189    DECLARE_NO_COPY_CLASS(wxPipeOutputStream)
190};
191
192// define this to let wxexec.cpp know that we know what we're doing
193#define _WX_USED_BY_WXEXECUTE_
194#include "../common/execcmn.cpp"
195
196// ----------------------------------------------------------------------------
197// wxPipe represents a Win32 anonymous pipe
198// ----------------------------------------------------------------------------
199
200class wxPipe
201{
202public:
203    // the symbolic names for the pipe ends
204    enum Direction
205    {
206        Read,
207        Write
208    };
209
210    // default ctor doesn't do anything
211    wxPipe() { m_handles[Read] = m_handles[Write] = INVALID_HANDLE_VALUE; }
212
213    // create the pipe, return true if ok, false on error
214    bool Create()
215    {
216        // default secutiry attributes
217        SECURITY_ATTRIBUTES security;
218
219        security.nLength              = sizeof(security);
220        security.lpSecurityDescriptor = NULL;
221        security.bInheritHandle       = TRUE; // to pass it to the child
222
223        if ( !::CreatePipe(&m_handles[0], &m_handles[1], &security, 0) )
224        {
225            wxLogSysError(_("Failed to create an anonymous pipe"));
226
227            return false;
228        }
229
230        return true;
231    }
232
233    // return true if we were created successfully
234    bool IsOk() const { return m_handles[Read] != INVALID_HANDLE_VALUE; }
235
236    // return the descriptor for one of the pipe ends
237    HANDLE operator[](Direction which) const { return m_handles[which]; }
238
239    // detach a descriptor, meaning that the pipe dtor won't close it, and
240    // return it
241    HANDLE Detach(Direction which)
242    {
243        HANDLE handle = m_handles[which];
244        m_handles[which] = INVALID_HANDLE_VALUE;
245
246        return handle;
247    }
248
249    // close the pipe descriptors
250    void Close()
251    {
252        for ( size_t n = 0; n < WXSIZEOF(m_handles); n++ )
253        {
254            if ( m_handles[n] != INVALID_HANDLE_VALUE )
255            {
256                ::CloseHandle(m_handles[n]);
257                m_handles[n] = INVALID_HANDLE_VALUE;
258            }
259        }
260    }
261
262    // dtor closes the pipe descriptors
263    ~wxPipe() { Close(); }
264
265private:
266    HANDLE m_handles[2];
267};
268
269#endif // wxUSE_STREAMS
270
271// ============================================================================
272// implementation
273// ============================================================================
274
275// ----------------------------------------------------------------------------
276// process termination detecting support
277// ----------------------------------------------------------------------------
278
279// thread function for the thread monitoring the process termination
280static DWORD __stdcall wxExecuteThread(void *arg)
281{
282    wxExecuteData * const data = (wxExecuteData *)arg;
283
284    if ( ::WaitForSingleObject(data->hProcess, INFINITE) != WAIT_OBJECT_0 )
285    {
286        wxLogDebug(_T("Waiting for the process termination failed!"));
287    }
288
289    // get the exit code
290    if ( !::GetExitCodeProcess(data->hProcess, &data->dwExitCode) )
291    {
292        wxLogLastError(wxT("GetExitCodeProcess"));
293    }
294
295    wxASSERT_MSG( data->dwExitCode != STILL_ACTIVE,
296                  wxT("process should have terminated") );
297
298    // send a message indicating process termination to the window
299    ::SendMessage(data->hWnd, wxWM_PROC_TERMINATED, 0, (LPARAM)data);
300
301    return 0;
302}
303
304// window procedure of a hidden window which is created just to receive
305// the notification message when a process exits
306LRESULT APIENTRY _EXPORT wxExecuteWindowCbk(HWND hWnd, UINT message,
307                                            WPARAM wParam, LPARAM lParam)
308{
309    if ( message == wxWM_PROC_TERMINATED )
310    {
311        DestroyWindow(hWnd);    // we don't need it any more
312
313        wxExecuteData * const data = (wxExecuteData *)lParam;
314        if ( data->handler )
315        {
316            data->handler->OnTerminate((int)data->dwProcessId,
317                                       (int)data->dwExitCode);
318        }
319
320        if ( data->state )
321        {
322            // we're executing synchronously, tell the waiting thread
323            // that the process finished
324            data->state = 0;
325        }
326        else
327        {
328            // asynchronous execution - we should do the clean up
329            delete data;
330        }
331
332        return 0;
333    }
334    else
335    {
336        return ::DefWindowProc(hWnd, message, wParam, lParam);
337    }
338}
339
340// ============================================================================
341// implementation of IO redirection support classes
342// ============================================================================
343
344#if wxUSE_STREAMS && !defined(__WXWINCE__)
345
346// ----------------------------------------------------------------------------
347// wxPipeInputStreams
348// ----------------------------------------------------------------------------
349
350wxPipeInputStream::wxPipeInputStream(HANDLE hInput)
351{
352    m_hInput = hInput;
353}
354
355wxPipeInputStream::~wxPipeInputStream()
356{
357    if ( m_hInput != INVALID_HANDLE_VALUE )
358        ::CloseHandle(m_hInput);
359}
360
361bool wxPipeInputStream::CanRead() const
362{
363    // we can read if there's something in the put back buffer
364    // even pipe is closed
365    if ( m_wbacksize > m_wbackcur )
366        return true;
367
368    wxPipeInputStream * const self = wxConstCast(this, wxPipeInputStream);
369
370    if ( !IsOpened() )
371    {
372        // set back to mark Eof as it may have been unset by Ungetch()
373        self->m_lasterror = wxSTREAM_EOF;
374        return false;
375    }
376
377    DWORD nAvailable;
378
379    // function name is misleading, it works with anon pipes as well
380    DWORD rc = ::PeekNamedPipe
381                    (
382                      m_hInput,     // handle
383                      NULL, 0,      // ptr to buffer and its size
384                      NULL,         // [out] bytes read
385                      &nAvailable,  // [out] bytes available
386                      NULL          // [out] bytes left
387                    );
388
389    if ( !rc )
390    {
391        if ( ::GetLastError() != ERROR_BROKEN_PIPE )
392        {
393            // unexpected error
394            wxLogLastError(_T("PeekNamedPipe"));
395        }
396
397        // don't try to continue reading from a pipe if an error occurred or if
398        // it had been closed
399        ::CloseHandle(m_hInput);
400
401        self->m_hInput = INVALID_HANDLE_VALUE;
402        self->m_lasterror = wxSTREAM_EOF;
403
404        nAvailable = 0;
405    }
406
407    return nAvailable != 0;
408}
409
410size_t wxPipeInputStream::OnSysRead(void *buffer, size_t len)
411{
412    if ( !IsOpened() )
413    {
414        m_lasterror = wxSTREAM_EOF;
415
416        return 0;
417    }
418
419    DWORD bytesRead;
420    if ( !::ReadFile(m_hInput, buffer, len, &bytesRead, NULL) )
421    {
422        m_lasterror = ::GetLastError() == ERROR_BROKEN_PIPE
423                        ? wxSTREAM_EOF
424                        : wxSTREAM_READ_ERROR;
425    }
426
427    // bytesRead is set to 0, as desired, if an error occurred
428    return bytesRead;
429}
430
431// ----------------------------------------------------------------------------
432// wxPipeOutputStream
433// ----------------------------------------------------------------------------
434
435wxPipeOutputStream::wxPipeOutputStream(HANDLE hOutput)
436{
437    m_hOutput = hOutput;
438
439    // unblock the pipe to prevent deadlocks when we're writing to the pipe
440    // from which the child process can't read because it is writing in its own
441    // end of it
442    DWORD mode = PIPE_READMODE_BYTE | PIPE_NOWAIT;
443    if ( !::SetNamedPipeHandleState
444            (
445                m_hOutput,
446                &mode,
447                NULL,       // collection count (we don't set it)
448                NULL        // timeout (we don't set it neither)
449            ) )
450    {
451        wxLogLastError(_T("SetNamedPipeHandleState(PIPE_NOWAIT)"));
452    }
453}
454
455bool wxPipeOutputStream::Close()
456{
457   return ::CloseHandle(m_hOutput) != 0;
458}
459
460
461size_t wxPipeOutputStream::OnSysWrite(const void *buffer, size_t len)
462{
463    m_lasterror = wxSTREAM_NO_ERROR;
464
465    DWORD totalWritten = 0;
466    while ( len > 0 )
467    {
468        DWORD chunkWritten;
469        if ( !::WriteFile(m_hOutput, buffer, len, &chunkWritten, NULL) )
470        {
471            m_lasterror = ::GetLastError() == ERROR_BROKEN_PIPE
472                                ? wxSTREAM_EOF
473                                : wxSTREAM_WRITE_ERROR;
474            break;
475        }
476
477        if ( !chunkWritten )
478            break;
479
480        buffer = (char *)buffer + chunkWritten;
481        totalWritten += chunkWritten;
482        len -= chunkWritten;
483    }
484
485    return totalWritten;
486}
487
488#endif // wxUSE_STREAMS
489
490// ============================================================================
491// wxExecute functions family
492// ============================================================================
493
494#if wxUSE_IPC
495
496// connect to the given server via DDE and ask it to execute the command
497bool
498wxExecuteDDE(const wxString& ddeServer,
499             const wxString& ddeTopic,
500             const wxString& ddeCommand)
501{
502    bool ok wxDUMMY_INITIALIZE(false);
503
504    wxDDEClient client;
505    wxConnectionBase *
506        conn = client.MakeConnection(wxEmptyString, ddeServer, ddeTopic);
507    if ( !conn )
508    {
509        ok = false;
510    }
511    else // connected to DDE server
512    {
513        // the added complication here is that although most programs use
514        // XTYP_EXECUTE for their DDE API, some important ones -- like Word
515        // and other MS stuff - use XTYP_REQUEST!
516        //
517        // moreover, anotheri mportant program (IE) understands both but
518        // returns an error from Execute() so we must try Request() first
519        // to avoid doing it twice
520        {
521            // we're prepared for this one to fail, so don't show errors
522            wxLogNull noErrors;
523
524            ok = conn->Request(ddeCommand) != NULL;
525        }
526
527        if ( !ok )
528        {
529            // now try execute -- but show the errors
530            ok = conn->Execute(ddeCommand);
531        }
532    }
533
534    return ok;
535}
536
537#endif // wxUSE_IPC
538
539long wxExecute(const wxString& cmd, int flags, wxProcess *handler)
540{
541    wxCHECK_MSG( !cmd.empty(), 0, wxT("empty command in wxExecute") );
542
543#if wxUSE_THREADS
544    // for many reasons, the code below breaks down if it's called from another
545    // thread -- this could be fixed, but as Unix versions don't support this
546    // neither I don't want to waste time on this now
547    wxASSERT_MSG( wxThread::IsMain(),
548                    _T("wxExecute() can be called only from the main thread") );
549#endif // wxUSE_THREADS
550
551    wxString command;
552
553#if wxUSE_IPC
554    // DDE hack: this is really not pretty, but we need to allow this for
555    // transparent handling of DDE servers in wxMimeTypesManager. Usually it
556    // returns the command which should be run to view/open/... a file of the
557    // given type. Sometimes, however, this command just launches the server
558    // and an additional DDE request must be made to really open the file. To
559    // keep all this well hidden from the application, we allow a special form
560    // of command: WX_DDE#<command>#DDE_SERVER#DDE_TOPIC#DDE_COMMAND in which
561    // case we execute just <command> and process the rest below
562    wxString ddeServer, ddeTopic, ddeCommand;
563    static const size_t lenDdePrefix = 7;   // strlen("WX_DDE:")
564    if ( cmd.Left(lenDdePrefix) == _T("WX_DDE#") )
565    {
566        // speed up the concatenations below
567        ddeServer.reserve(256);
568        ddeTopic.reserve(256);
569        ddeCommand.reserve(256);
570
571        const wxChar *p = cmd.c_str() + 7;
572        while ( *p && *p != _T('#') )
573        {
574            command += *p++;
575        }
576
577        if ( *p )
578        {
579            // skip '#'
580            p++;
581        }
582        else
583        {
584            wxFAIL_MSG(_T("invalid WX_DDE command in wxExecute"));
585        }
586
587        while ( *p && *p != _T('#') )
588        {
589            ddeServer += *p++;
590        }
591
592        if ( *p )
593        {
594            // skip '#'
595            p++;
596        }
597        else
598        {
599            wxFAIL_MSG(_T("invalid WX_DDE command in wxExecute"));
600        }
601
602        while ( *p && *p != _T('#') )
603        {
604            ddeTopic += *p++;
605        }
606
607        if ( *p )
608        {
609            // skip '#'
610            p++;
611        }
612        else
613        {
614            wxFAIL_MSG(_T("invalid WX_DDE command in wxExecute"));
615        }
616
617        while ( *p )
618        {
619            ddeCommand += *p++;
620        }
621
622        // if we want to just launch the program and not wait for its
623        // termination, try to execute DDE command right now, it can succeed if
624        // the process is already running - but as it fails if it's not
625        // running, suppress any errors it might generate
626        if ( !(flags & wxEXEC_SYNC) )
627        {
628            wxLogNull noErrors;
629            if ( wxExecuteDDE(ddeServer, ddeTopic, ddeCommand) )
630            {
631                // a dummy PID - this is a hack, of course, but it's well worth
632                // it as we don't open a new server each time we're called
633                // which would be quite bad
634                return -1;
635            }
636        }
637    }
638    else
639#endif // wxUSE_IPC
640    {
641        // no DDE
642        command = cmd;
643    }
644
645    // the IO redirection is only supported with wxUSE_STREAMS
646    BOOL redirect = FALSE;
647
648#if wxUSE_STREAMS && !defined(__WXWINCE__)
649    wxPipe pipeIn, pipeOut, pipeErr;
650
651    // we'll save here the copy of pipeIn[Write]
652    HANDLE hpipeStdinWrite = INVALID_HANDLE_VALUE;
653
654    // open the pipes to which child process IO will be redirected if needed
655    if ( handler && handler->IsRedirected() )
656    {
657        // create pipes for redirecting stdin, stdout and stderr
658        if ( !pipeIn.Create() || !pipeOut.Create() || !pipeErr.Create() )
659        {
660            wxLogSysError(_("Failed to redirect the child process IO"));
661
662            // indicate failure: we need to return different error code
663            // depending on the sync flag
664            return flags & wxEXEC_SYNC ? -1 : 0;
665        }
666
667        redirect = TRUE;
668    }
669#endif // wxUSE_STREAMS
670
671    // create the process
672    STARTUPINFO si;
673    wxZeroMemory(si);
674    si.cb = sizeof(si);
675
676#if wxUSE_STREAMS && !defined(__WXWINCE__)
677    if ( redirect )
678    {
679        si.dwFlags = STARTF_USESTDHANDLES;
680
681        si.hStdInput = pipeIn[wxPipe::Read];
682        si.hStdOutput = pipeOut[wxPipe::Write];
683        si.hStdError = pipeErr[wxPipe::Write];
684
685        // when the std IO is redirected, we don't show the (console) process
686        // window by default, but this can be overridden by the caller by
687        // specifying wxEXEC_NOHIDE flag
688        if ( !(flags & wxEXEC_NOHIDE) )
689        {
690            si.dwFlags |= STARTF_USESHOWWINDOW;
691            si.wShowWindow = SW_HIDE;
692        }
693
694        // we must duplicate the handle to the write side of stdin pipe to make
695        // it non inheritable: indeed, we must close the writing end of pipeIn
696        // before launching the child process as otherwise this handle will be
697        // inherited by the child which will never close it and so the pipe
698        // will never be closed and the child will be left stuck in ReadFile()
699        HANDLE pipeInWrite = pipeIn.Detach(wxPipe::Write);
700        if ( !::DuplicateHandle
701                (
702                    ::GetCurrentProcess(),
703                    pipeInWrite,
704                    ::GetCurrentProcess(),
705                    &hpipeStdinWrite,
706                    0,                      // desired access: unused here
707                    FALSE,                  // not inherited
708                    DUPLICATE_SAME_ACCESS   // same access as for src handle
709                ) )
710        {
711            wxLogLastError(_T("DuplicateHandle"));
712        }
713
714        ::CloseHandle(pipeInWrite);
715    }
716#endif // wxUSE_STREAMS
717
718    PROCESS_INFORMATION pi;
719    DWORD dwFlags = CREATE_SUSPENDED;
720
721#ifndef __WXWINCE__
722    dwFlags |= CREATE_DEFAULT_ERROR_MODE ;
723#else
724    // we are assuming commands without spaces for now
725    wxString moduleName = command.BeforeFirst(wxT(' '));
726    wxString arguments = command.AfterFirst(wxT(' '));
727#endif
728
729    bool ok = ::CreateProcess
730                (
731                    // WinCE requires appname to be non null
732                    // Win32 allows for null
733#ifdef __WXWINCE__
734                 (wxChar *)
735                 moduleName.c_str(), // application name
736                 (wxChar *)
737                 arguments.c_str(),  // arguments
738#else
739                 NULL,               // application name (use only cmd line)
740                 (wxChar *)
741                 command.c_str(),    // full command line
742#endif
743                 NULL,               // security attributes: defaults for both
744                 NULL,               //   the process and its main thread
745                 redirect,           // inherit handles if we use pipes
746                 dwFlags,            // process creation flags
747                 NULL,               // environment (use the same)
748                 NULL,               // current directory (use the same)
749                 &si,                // startup info (unused here)
750                 &pi                 // process info
751                ) != 0;
752
753#if wxUSE_STREAMS && !defined(__WXWINCE__)
754    // we can close the pipe ends used by child anyhow
755    if ( redirect )
756    {
757        ::CloseHandle(pipeIn.Detach(wxPipe::Read));
758        ::CloseHandle(pipeOut.Detach(wxPipe::Write));
759        ::CloseHandle(pipeErr.Detach(wxPipe::Write));
760    }
761#endif // wxUSE_STREAMS
762
763    if ( !ok )
764    {
765#if wxUSE_STREAMS && !defined(__WXWINCE__)
766        // close the other handles too
767        if ( redirect )
768        {
769            ::CloseHandle(pipeOut.Detach(wxPipe::Read));
770            ::CloseHandle(pipeErr.Detach(wxPipe::Read));
771        }
772#endif // wxUSE_STREAMS
773
774        wxLogSysError(_("Execution of command '%s' failed"), command.c_str());
775
776        return flags & wxEXEC_SYNC ? -1 : 0;
777    }
778
779#if wxUSE_STREAMS && !defined(__WXWINCE__)
780    // the input buffer bufOut is connected to stdout, this is why it is
781    // called bufOut and not bufIn
782    wxStreamTempInputBuffer bufOut,
783                            bufErr;
784
785    if ( redirect )
786    {
787        // We can now initialize the wxStreams
788        wxPipeInputStream *
789            outStream = new wxPipeInputStream(pipeOut.Detach(wxPipe::Read));
790        wxPipeInputStream *
791            errStream = new wxPipeInputStream(pipeErr.Detach(wxPipe::Read));
792        wxPipeOutputStream *
793            inStream = new wxPipeOutputStream(hpipeStdinWrite);
794
795        handler->SetPipeStreams(outStream, inStream, errStream);
796
797        bufOut.Init(outStream);
798        bufErr.Init(errStream);
799    }
800#endif // wxUSE_STREAMS
801
802    // create a hidden window to receive notification about process
803    // termination
804    HWND hwnd = wxCreateHiddenWindow
805                (
806                    &gs_classForHiddenWindow,
807                    wxMSWEXEC_WNDCLASSNAME,
808                    (WNDPROC)wxExecuteWindowCbk
809                );
810
811    wxASSERT_MSG( hwnd, wxT("can't create a hidden window for wxExecute") );
812
813    // Alloc data
814    wxExecuteData *data = new wxExecuteData;
815    data->hProcess    = pi.hProcess;
816    data->dwProcessId = pi.dwProcessId;
817    data->hWnd        = hwnd;
818    data->state       = (flags & wxEXEC_SYNC) != 0;
819    if ( flags & wxEXEC_SYNC )
820    {
821        // handler may be !NULL for capturing program output, but we don't use
822        // it wxExecuteData struct in this case
823        data->handler = NULL;
824    }
825    else
826    {
827        // may be NULL or not
828        data->handler = handler;
829    }
830
831    DWORD tid;
832    HANDLE hThread = ::CreateThread(NULL,
833                                    0,
834                                    wxExecuteThread,
835                                    (void *)data,
836                                    0,
837                                    &tid);
838
839    // resume process we created now - whether the thread creation succeeded or
840    // not
841    if ( ::ResumeThread(pi.hThread) == (DWORD)-1 )
842    {
843        // ignore it - what can we do?
844        wxLogLastError(wxT("ResumeThread in wxExecute"));
845    }
846
847    // close unneeded handle
848    if ( !::CloseHandle(pi.hThread) )
849        wxLogLastError(wxT("CloseHandle(hThread)"));
850
851    if ( !hThread )
852    {
853        wxLogLastError(wxT("CreateThread in wxExecute"));
854
855        DestroyWindow(hwnd);
856        delete data;
857
858        // the process still started up successfully...
859        return pi.dwProcessId;
860    }
861
862    ::CloseHandle(hThread);
863
864#if wxUSE_IPC && !defined(__WXWINCE__)
865    // second part of DDE hack: now establish the DDE conversation with the
866    // just launched process
867    if ( !ddeServer.empty() )
868    {
869        bool ok;
870
871        // give the process the time to init itself
872        //
873        // we use a very big timeout hoping that WaitForInputIdle() will return
874        // much sooner, but not INFINITE just in case the process hangs
875        // completely - like this we will regain control sooner or later
876        switch ( ::WaitForInputIdle(pi.hProcess, 10000 /* 10 seconds */) )
877        {
878            default:
879                wxFAIL_MSG( _T("unexpected WaitForInputIdle() return code") );
880                // fall through
881
882            case -1:
883                wxLogLastError(_T("WaitForInputIdle() in wxExecute"));
884
885            case WAIT_TIMEOUT:
886                wxLogDebug(_T("Timeout too small in WaitForInputIdle"));
887
888                ok = false;
889                break;
890
891            case 0:
892                // ok, process ready to accept DDE requests
893                ok = wxExecuteDDE(ddeServer, ddeTopic, ddeCommand);
894        }
895
896        if ( !ok )
897        {
898            wxLogDebug(_T("Failed to send DDE request to the process \"%s\"."),
899                       cmd.c_str());
900        }
901    }
902#endif // wxUSE_IPC
903
904    if ( !(flags & wxEXEC_SYNC) )
905    {
906        // clean up will be done when the process terminates
907
908        // return the pid
909        return pi.dwProcessId;
910    }
911
912    wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
913    wxCHECK_MSG( traits, -1, _T("no wxAppTraits in wxExecute()?") );
914
915    void *cookie = NULL;
916    if ( !(flags & wxEXEC_NODISABLE) )
917    {
918        // disable all app windows while waiting for the child process to finish
919        cookie = traits->BeforeChildWaitLoop();
920    }
921
922    // wait until the child process terminates
923    while ( data->state )
924    {
925#if wxUSE_STREAMS && !defined(__WXWINCE__)
926        bufOut.Update();
927        bufErr.Update();
928#endif // wxUSE_STREAMS
929
930        // don't eat 100% of the CPU -- ugly but anything else requires
931        // real async IO which we don't have for the moment
932        ::Sleep(50);
933
934        // we must process messages or we'd never get wxWM_PROC_TERMINATED
935        traits->AlwaysYield();
936    }
937
938    if ( !(flags & wxEXEC_NODISABLE) )
939    {
940        // reenable disabled windows back
941        traits->AfterChildWaitLoop(cookie);
942    }
943
944    DWORD dwExitCode = data->dwExitCode;
945    delete data;
946
947    // return the exit code
948    return dwExitCode;
949}
950
951long wxExecute(wxChar **argv, int flags, wxProcess *handler)
952{
953    wxString command;
954
955    wxString arg;
956    for ( ;; )
957    {
958        arg = *argv++;
959
960        // we didn't quote the arguments properly in the previous wx versions
961        // and while this is the right thing to do, there is a good chance that
962        // people worked around our bug in their code by quoting the arguments
963        // manually before, so, for compatibility sake, keep the argument
964        // unchanged if it's already quoted
965
966        bool quote;
967        if ( arg.empty() )
968        {
969            // we need to quote empty arguments, otherwise they'd just
970            // disappear
971            quote = true;
972        }
973        else // non-empty
974        {
975            if ( *arg.begin() != _T('"') || *arg.rbegin() != _T('"') )
976            {
977                // escape any quotes present in the string to avoid interfering
978                // with the command line parsing in the child process
979                arg.Replace(_T("\""), _T("\\\""), true /* replace all */);
980
981                // and quote any arguments containing the spaces to prevent
982                // them from being broken down
983                quote = arg.find_first_of(_T(" \t")) != wxString::npos;
984            }
985            else // already quoted
986            {
987                quote = false;
988            }
989        }
990
991        if ( quote )
992            command += _T('\"') + arg + _T('\"');
993        else
994            command += arg;
995
996        if ( !*argv )
997            break;
998
999        command += _T(' ');
1000    }
1001
1002    return wxExecute(command, flags, handler);
1003}
1004