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