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