]> git.saurik.com Git - wxWidgets.git/blame - src/msw/utilsexc.cpp
compilation fixes for non default wxUSE_XXX values (patch 662781)
[wxWidgets.git] / src / msw / utilsexc.cpp
CommitLineData
32592631 1/////////////////////////////////////////////////////////////////////////////
b568d04f 2// Name: msw/utilsexec.cpp
79066131 3// Purpose: wxExecute implementation for MSW
32592631
GL
4// Author: Julian Smart
5// Modified by:
6// Created: 04/01/98
7// RCS-ID: $Id$
79066131 8// Copyright: (c) 1998-2002 wxWindows dev team
3f4a0c5b 9// Licence: wxWindows license
32592631
GL
10/////////////////////////////////////////////////////////////////////////////
11
b568d04f
VZ
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
32592631 20#ifdef __GNUG__
b568d04f 21 #pragma implementation
32592631
GL
22#endif
23
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
b568d04f 28 #pragma hdrstop
32592631
GL
29#endif
30
31#ifndef WX_PRECOMP
b568d04f
VZ
32 #include "wx/utils.h"
33 #include "wx/app.h"
34 #include "wx/intl.h"
068a7cfe 35 #include "wx/log.h"
45d5a0c6
VZ
36 #if wxUSE_GUI // See 'dirty hack' below.
37 #include "wx/frame.h"
38 #endif
2ae8a353 39#endif
32592631 40
1044a386 41#ifdef __WIN32__
8b33ae2d 42 #include "wx/stream.h"
b568d04f 43 #include "wx/process.h"
1044a386 44#endif
dbeac4bd 45
32592631 46#include "wx/msw/private.h"
dbeac4bd 47
32592631
GL
48#include <ctype.h>
49
b4da152e 50#if !defined(__GNUWIN32__) && !defined(__SALFORDC__) && !defined(__WXMICROWIN__)
b568d04f 51 #include <direct.h>
17dff81c 52#ifndef __MWERKS__
b568d04f 53 #include <dos.h>
32592631 54#endif
17dff81c 55#endif
32592631 56
b568d04f
VZ
57#if defined(__GNUWIN32__) && !defined(__TWIN32__)
58 #include <sys/unistd.h>
59 #include <sys/stat.h>
57c208c5 60#endif
32592631 61
b4da152e 62#if defined(__WIN32__) && !defined(__WXMICROWIN__)
32592631
GL
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__
3f4a0c5b
VZ
74 #if !(defined(_MSC_VER) && (_MSC_VER > 800))
75 #include <errno.h>
76 #endif
32592631
GL
77#endif
78#include <stdarg.h>
79
731dd422
VZ
80#if wxUSE_IPC
81 #include "wx/dde.h" // for WX_DDE hack in wxExecute
82#endif // wxUSE_IPC
5bd3a2da 83
b568d04f
VZ
84// ----------------------------------------------------------------------------
85// constants
86// ----------------------------------------------------------------------------
87
cb6827a8
VZ
88// this message is sent when the process we're waiting for terminates
89#define wxWM_PROC_TERMINATED (WM_USER + 10000)
32592631 90
b568d04f
VZ
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
98static const wxChar *gs_classForHiddenWindow = NULL;
99
100// ----------------------------------------------------------------------------
101// private types
102// ----------------------------------------------------------------------------
103
cb6827a8
VZ
104// structure describing the process we're being waiting for
105struct wxExecuteData
106{
107public:
108 ~wxExecuteData()
109 {
750b78ba 110#ifndef __WIN16__
cb6827a8
VZ
111 if ( !::CloseHandle(hProcess) )
112 {
f6bcfd97 113 wxLogLastError(wxT("CloseHandle(hProcess)"));
cb6827a8 114 }
750b78ba 115#endif
cb6827a8
VZ
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
32592631
GL
124};
125
f6bcfd97 126#if defined(__WIN32__) && wxUSE_STREAMS
8b33ae2d 127
8b33ae2d
GL
128// ----------------------------------------------------------------------------
129// wxPipeStreams
130// ----------------------------------------------------------------------------
131
f6bcfd97
BP
132class wxPipeInputStream: public wxInputStream
133{
8b33ae2d
GL
134public:
135 wxPipeInputStream(HANDLE hInput);
79066131 136 virtual ~wxPipeInputStream();
8b33ae2d 137
79066131
VZ
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
2b5f62a0 142 virtual bool CanRead() const;
f6bcfd97 143
8b33ae2d
GL
144protected:
145 size_t OnSysRead(void *buffer, size_t len);
146
147protected:
148 HANDLE m_hInput;
22f3361e
VZ
149
150 DECLARE_NO_COPY_CLASS(wxPipeInputStream)
8b33ae2d
GL
151};
152
f6bcfd97
BP
153class wxPipeOutputStream: public wxOutputStream
154{
8b33ae2d
GL
155public:
156 wxPipeOutputStream(HANDLE hOutput);
79066131 157 virtual ~wxPipeOutputStream();
8b33ae2d
GL
158
159protected:
160 size_t OnSysWrite(const void *buffer, size_t len);
161
162protected:
163 HANDLE m_hOutput;
22f3361e
VZ
164
165 DECLARE_NO_COPY_CLASS(wxPipeOutputStream)
8b33ae2d
GL
166};
167
79066131
VZ
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
176class wxPipe
177{
178public:
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
250private:
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
267static DWORD __stdcall wxExecuteThread(void *arg)
268{
45d5a0c6 269 wxExecuteData * const data = (wxExecuteData *)arg;
79066131
VZ
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
293LRESULT 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
45d5a0c6 300 wxExecuteData * const data = (wxExecuteData *)lParam;
79066131
VZ
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 {
45d5a0c6 323 return ::DefWindowProc(hWnd, message, wParam, lParam);
79066131
VZ
324 }
325}
326
327// ============================================================================
328// implementation of IO redirection support classes
329// ============================================================================
330
331#if wxUSE_STREAMS
332
333// ----------------------------------------------------------------------------
334// wxPipeInputStreams
335// ----------------------------------------------------------------------------
8b33ae2d
GL
336
337wxPipeInputStream::wxPipeInputStream(HANDLE hInput)
338{
339 m_hInput = hInput;
cd6ce4a9 340}
8b33ae2d
GL
341
342wxPipeInputStream::~wxPipeInputStream()
343{
79066131
VZ
344 if ( m_hInput != INVALID_HANDLE_VALUE )
345 ::CloseHandle(m_hInput);
8b33ae2d
GL
346}
347
2b5f62a0 348bool wxPipeInputStream::CanRead() const
8b33ae2d 349{
79066131
VZ
350 if ( !IsOpened() )
351 return FALSE;
352
f6bcfd97
BP
353 DWORD nAvailable;
354
355 // function name is misleading, it works with anon pipes as well
356 DWORD rc = ::PeekNamedPipe
357 (
358 m_hInput, // handle
359 NULL, 0, // ptr to buffer and its size
360 NULL, // [out] bytes read
361 &nAvailable, // [out] bytes available
362 NULL // [out] bytes left
363 );
364
365 if ( !rc )
366 {
367 if ( ::GetLastError() != ERROR_BROKEN_PIPE )
368 {
369 // unexpected error
370 wxLogLastError(_T("PeekNamedPipe"));
371 }
8b33ae2d 372
f6bcfd97
BP
373 // don't try to continue reading from a pipe if an error occured or if
374 // it had been closed
79066131
VZ
375 ::CloseHandle(m_hInput);
376
2b5f62a0 377 wxPipeInputStream *self = wxConstCast(this, wxPipeInputStream);
79066131 378
2b5f62a0
VZ
379 self->m_hInput = INVALID_HANDLE_VALUE;
380 self->m_lasterror = wxSTREAM_EOF;
381
382 nAvailable = 0;
f6bcfd97 383 }
79066131
VZ
384
385 return nAvailable != 0;
f6bcfd97
BP
386}
387
388size_t wxPipeInputStream::OnSysRead(void *buffer, size_t len)
389{
2b5f62a0 390 if ( !IsOpened() )
79066131
VZ
391 {
392 m_lasterror = wxSTREAM_EOF;
393
f6bcfd97 394 return 0;
79066131
VZ
395 }
396
f6bcfd97
BP
397 DWORD bytesRead;
398 if ( !::ReadFile(m_hInput, buffer, len, &bytesRead, NULL) )
399 {
2b5f62a0
VZ
400 m_lasterror = ::GetLastError() == ERROR_BROKEN_PIPE
401 ? wxSTREAM_EOF
402 : wxSTREAM_READ_ERROR;
8b33ae2d 403 }
f6bcfd97 404
2b5f62a0 405 // bytesRead is set to 0, as desired, if an error occured
8b33ae2d
GL
406 return bytesRead;
407}
408
79066131 409// ----------------------------------------------------------------------------
8b33ae2d 410// wxPipeOutputStream
79066131 411// ----------------------------------------------------------------------------
8b33ae2d
GL
412
413wxPipeOutputStream::wxPipeOutputStream(HANDLE hOutput)
414{
415 m_hOutput = hOutput;
cd6ce4a9 416}
8b33ae2d
GL
417
418wxPipeOutputStream::~wxPipeOutputStream()
419{
420 ::CloseHandle(m_hOutput);
421}
422
423size_t wxPipeOutputStream::OnSysWrite(const void *buffer, size_t len)
424{
2b5f62a0 425 DWORD bytesWritten;
8b33ae2d 426
2b5f62a0
VZ
427 m_lasterror = wxSTREAM_NO_ERROR;
428 if ( !::WriteFile(m_hOutput, buffer, len, &bytesWritten, NULL) )
f6bcfd97 429 {
2b5f62a0
VZ
430 m_lasterror = ::GetLastError() == ERROR_BROKEN_PIPE
431 ? wxSTREAM_EOF
432 : wxSTREAM_WRITE_ERROR;
8b33ae2d 433 }
f6bcfd97 434
2b5f62a0 435 return bytesWritten;
8b33ae2d
GL
436}
437
79066131
VZ
438#endif // wxUSE_STREAMS
439
440#endif // Win32
8b33ae2d 441
b568d04f 442// ============================================================================
79066131 443// wxExecute functions family
b568d04f 444// ============================================================================
5260b1c5 445
ca289436
VZ
446#if wxUSE_IPC
447
448// connect to the given server via DDE and ask it to execute the command
449static bool wxExecuteDDE(const wxString& ddeServer,
450 const wxString& ddeTopic,
451 const wxString& ddeCommand)
452{
2b5f62a0 453 bool ok = FALSE;
ca289436
VZ
454
455 wxDDEClient client;
456 wxConnectionBase *conn = client.MakeConnection(_T(""),
457 ddeServer,
458 ddeTopic);
459 if ( !conn )
460 {
461 ok = FALSE;
462 }
463 else // connected to DDE server
464 {
465 // the added complication here is that although most
466 // programs use XTYP_EXECUTE for their DDE API, some
467 // important ones - like IE and other MS stuff - use
468 // XTYP_REQUEST!
469 //
2b5f62a0 470 // so we try one first and then the other one if it
ca289436
VZ
471 // failed
472 {
473 wxLogNull noErrors;
2b5f62a0 474 ok = conn->Execute(ddeCommand);
ca289436
VZ
475 }
476
477 if ( !ok )
478 {
2b5f62a0
VZ
479 // now try request - but show the errors
480 ok = conn->Request(ddeCommand) != NULL;
ca289436
VZ
481 }
482 }
483
484 return ok;
485}
486
487#endif // wxUSE_IPC
488
fbf456aa 489long wxExecute(const wxString& cmd, int flags, wxProcess *handler)
32592631 490{
5bd3a2da
VZ
491 wxCHECK_MSG( !!cmd, 0, wxT("empty command in wxExecute") );
492
039f62f4 493 wxString command;
6ba63600 494
731dd422 495#if wxUSE_IPC
5bd3a2da
VZ
496 // DDE hack: this is really not pretty, but we need to allow this for
497 // transparent handling of DDE servers in wxMimeTypesManager. Usually it
498 // returns the command which should be run to view/open/... a file of the
499 // given type. Sometimes, however, this command just launches the server
500 // and an additional DDE request must be made to really open the file. To
501 // keep all this well hidden from the application, we allow a special form
6ba63600 502 // of command: WX_DDE#<command>#DDE_SERVER#DDE_TOPIC#DDE_COMMAND in which
5bd3a2da 503 // case we execute just <command> and process the rest below
039f62f4 504 wxString ddeServer, ddeTopic, ddeCommand;
5bd3a2da
VZ
505 static const size_t lenDdePrefix = 7; // strlen("WX_DDE:")
506 if ( cmd.Left(lenDdePrefix) == _T("WX_DDE#") )
507 {
ca289436
VZ
508 // speed up the concatenations below
509 ddeServer.reserve(256);
510 ddeTopic.reserve(256);
511 ddeCommand.reserve(256);
512
5bd3a2da
VZ
513 const wxChar *p = cmd.c_str() + 7;
514 while ( *p && *p != _T('#') )
515 {
516 command += *p++;
517 }
518
519 if ( *p )
520 {
521 // skip '#'
522 p++;
523 }
524 else
525 {
526 wxFAIL_MSG(_T("invalid WX_DDE command in wxExecute"));
527 }
528
529 while ( *p && *p != _T('#') )
530 {
531 ddeServer += *p++;
532 }
533
534 if ( *p )
535 {
536 // skip '#'
537 p++;
538 }
539 else
540 {
541 wxFAIL_MSG(_T("invalid WX_DDE command in wxExecute"));
542 }
543
544 while ( *p && *p != _T('#') )
545 {
546 ddeTopic += *p++;
547 }
548
549 if ( *p )
550 {
551 // skip '#'
552 p++;
553 }
554 else
555 {
556 wxFAIL_MSG(_T("invalid WX_DDE command in wxExecute"));
557 }
558
559 while ( *p )
560 {
561 ddeCommand += *p++;
562 }
6ba63600 563
ca289436
VZ
564 // if we want to just launch the program and not wait for its
565 // termination, try to execute DDE command right now, it can succeed if
566 // the process is already running - but as it fails if it's not
567 // running, suppress any errors it might generate
fbf456aa 568 if ( !(flags & wxEXEC_SYNC) )
6ba63600 569 {
ca289436
VZ
570 wxLogNull noErrors;
571 if ( wxExecuteDDE(ddeServer, ddeTopic, ddeCommand) )
572 {
573 // a dummy PID - this is a hack, of course, but it's well worth
574 // it as we don't open a new server each time we're called
575 // which would be quite bad
576 return -1;
577 }
6ba63600 578 }
5bd3a2da
VZ
579 }
580 else
731dd422 581#endif // wxUSE_IPC
5bd3a2da
VZ
582 {
583 // no DDE
584 command = cmd;
585 }
32592631 586
57c208c5 587#if defined(__WIN32__) && !defined(__TWIN32__)
cb6827a8 588
f6bcfd97
BP
589 // the IO redirection is only supported with wxUSE_STREAMS
590 BOOL redirect = FALSE;
79066131 591
f6bcfd97 592#if wxUSE_STREAMS
79066131
VZ
593 wxPipe pipeIn, pipeOut, pipeErr;
594
595 // we'll save here the copy of pipeIn[Write]
33ac7e6f 596 HANDLE hpipeStdinWrite = INVALID_HANDLE_VALUE;
8b33ae2d 597
cd6ce4a9 598 // open the pipes to which child process IO will be redirected if needed
cd6ce4a9
VZ
599 if ( handler && handler->IsRedirected() )
600 {
79066131
VZ
601 // create pipes for redirecting stdin, stdout and stderr
602 if ( !pipeIn.Create() || !pipeOut.Create() || !pipeErr.Create() )
cd6ce4a9 603 {
79066131 604 wxLogSysError(_("Failed to redirect the child process IO"));
8b33ae2d 605
fbf456aa
VZ
606 // indicate failure: we need to return different error code
607 // depending on the sync flag
608 return flags & wxEXEC_SYNC ? -1 : 0;
8b33ae2d
GL
609 }
610
f6bcfd97 611 redirect = TRUE;
8b33ae2d 612 }
f6bcfd97 613#endif // wxUSE_STREAMS
5bd3a2da 614
cb6827a8
VZ
615 // create the process
616 STARTUPINFO si;
11c7d5b6 617 wxZeroMemory(si);
cb6827a8
VZ
618 si.cb = sizeof(si);
619
f6bcfd97
BP
620#if wxUSE_STREAMS
621 if ( redirect )
cb6827a8 622 {
fbf456aa 623 si.dwFlags = STARTF_USESTDHANDLES;
f6bcfd97 624
79066131
VZ
625 si.hStdInput = pipeIn[wxPipe::Read];
626 si.hStdOutput = pipeOut[wxPipe::Write];
627 si.hStdError = pipeErr[wxPipe::Write];
f6bcfd97 628
fbf456aa
VZ
629 // when the std IO is redirected, we don't show the (console) process
630 // window by default, but this can be overridden by the caller by
631 // specifying wxEXEC_NOHIDE flag
632 if ( !(flags & wxEXEC_NOHIDE) )
633 {
634 si.dwFlags |= STARTF_USESHOWWINDOW;
635 si.wShowWindow = SW_HIDE;
636 }
f6bcfd97
BP
637
638 // we must duplicate the handle to the write side of stdin pipe to make
79066131
VZ
639 // it non inheritable: indeed, we must close the writing end of pipeIn
640 // before launching the child process as otherwise this handle will be
f6bcfd97
BP
641 // inherited by the child which will never close it and so the pipe
642 // will never be closed and the child will be left stuck in ReadFile()
79066131 643 HANDLE pipeInWrite = pipeIn.Detach(wxPipe::Write);
f6bcfd97
BP
644 if ( !::DuplicateHandle
645 (
79066131
VZ
646 ::GetCurrentProcess(),
647 pipeInWrite,
648 ::GetCurrentProcess(),
f6bcfd97
BP
649 &hpipeStdinWrite,
650 0, // desired access: unused here
651 FALSE, // not inherited
652 DUPLICATE_SAME_ACCESS // same access as for src handle
653 ) )
cd6ce4a9 654 {
f6bcfd97 655 wxLogLastError(_T("DuplicateHandle"));
8b33ae2d 656 }
cd6ce4a9 657
79066131 658 ::CloseHandle(pipeInWrite);
f6bcfd97
BP
659 }
660#endif // wxUSE_STREAMS
cb6827a8 661
f6bcfd97
BP
662 PROCESS_INFORMATION pi;
663 DWORD dwFlags = CREATE_DEFAULT_ERROR_MODE | CREATE_SUSPENDED;
664
665 bool ok = ::CreateProcess
666 (
667 NULL, // application name (use only cmd line)
668 (wxChar *)
669 command.c_str(), // full command line
670 NULL, // security attributes: defaults for both
671 NULL, // the process and its main thread
672 redirect, // inherit handles if we use pipes
673 dwFlags, // process creation flags
674 NULL, // environment (use the same)
675 NULL, // current directory (use the same)
676 &si, // startup info (unused here)
677 &pi // process info
678 ) != 0;
679
680#if wxUSE_STREAMS
681 // we can close the pipe ends used by child anyhow
682 if ( redirect )
683 {
79066131
VZ
684 ::CloseHandle(pipeIn.Detach(wxPipe::Read));
685 ::CloseHandle(pipeOut.Detach(wxPipe::Write));
686 ::CloseHandle(pipeErr.Detach(wxPipe::Write));
cb6827a8 687 }
f6bcfd97 688#endif // wxUSE_STREAMS
cb6827a8 689
f6bcfd97 690 if ( !ok )
5e1febfa 691 {
f6bcfd97
BP
692#if wxUSE_STREAMS
693 // close the other handles too
694 if ( redirect )
5e1febfa 695 {
79066131
VZ
696 ::CloseHandle(pipeOut.Detach(wxPipe::Read));
697 ::CloseHandle(pipeErr.Detach(wxPipe::Read));
5e1febfa 698 }
f6bcfd97 699#endif // wxUSE_STREAMS
5e1febfa 700
f6bcfd97
BP
701 wxLogSysError(_("Execution of command '%s' failed"), command.c_str());
702
fbf456aa 703 return flags & wxEXEC_SYNC ? -1 : 0;
f6bcfd97 704 }
8b33ae2d 705
f6bcfd97 706#if wxUSE_STREAMS
79066131
VZ
707 // the input buffer bufOut is connected to stdout, this is why it is
708 // called bufOut and not bufIn
709 wxStreamTempInputBuffer bufOut,
710 bufErr;
711
f6bcfd97
BP
712 if ( redirect )
713 {
8b33ae2d 714 // We can now initialize the wxStreams
79066131
VZ
715 wxPipeInputStream *
716 outStream = new wxPipeInputStream(pipeOut.Detach(wxPipe::Read));
717 wxPipeInputStream *
718 errStream = new wxPipeInputStream(pipeErr.Detach(wxPipe::Read));
719 wxPipeOutputStream *
720 inStream = new wxPipeOutputStream(hpipeStdinWrite);
721
722 handler->SetPipeStreams(outStream, inStream, errStream);
8b33ae2d 723
79066131
VZ
724 bufOut.Init(outStream);
725 bufErr.Init(errStream);
8b33ae2d 726 }
f6bcfd97 727#endif // wxUSE_STREAMS
8b33ae2d 728
0d7ea902 729 // register the class for the hidden window used for the notifications
b568d04f
VZ
730 if ( !gs_classForHiddenWindow )
731 {
732 gs_classForHiddenWindow = _T("wxHiddenWindow");
733
734 WNDCLASS wndclass;
735 wxZeroMemory(wndclass);
736 wndclass.lpfnWndProc = (WNDPROC)wxExecuteWindowCbk;
737 wndclass.hInstance = wxGetInstance();
738 wndclass.lpszClassName = gs_classForHiddenWindow;
739
740 if ( !::RegisterClass(&wndclass) )
741 {
f6bcfd97 742 wxLogLastError(wxT("RegisterClass(hidden window)"));
b568d04f
VZ
743 }
744 }
745
cb6827a8
VZ
746 // create a hidden window to receive notification about process
747 // termination
b568d04f 748 HWND hwnd = ::CreateWindow(gs_classForHiddenWindow, NULL,
0d7ea902
VZ
749 WS_OVERLAPPEDWINDOW,
750 0, 0, 0, 0, NULL,
cb6827a8 751 (HMENU)NULL, wxGetInstance(), 0);
223d09f6 752 wxASSERT_MSG( hwnd, wxT("can't create a hidden window for wxExecute") );
e6045e08 753
cb6827a8
VZ
754 // Alloc data
755 wxExecuteData *data = new wxExecuteData;
756 data->hProcess = pi.hProcess;
757 data->dwProcessId = pi.dwProcessId;
758 data->hWnd = hwnd;
fbf456aa
VZ
759 data->state = (flags & wxEXEC_SYNC) != 0;
760 if ( flags & wxEXEC_SYNC )
e6045e08 761 {
5e1febfa
VZ
762 // handler may be !NULL for capturing program output, but we don't use
763 // it wxExecuteData struct in this case
e6045e08
VZ
764 data->handler = NULL;
765 }
766 else
767 {
768 // may be NULL or not
769 data->handler = handler;
770 }
cb6827a8
VZ
771
772 DWORD tid;
773 HANDLE hThread = ::CreateThread(NULL,
774 0,
19193a2c 775 wxExecuteThread,
cb6827a8
VZ
776 (void *)data,
777 0,
778 &tid);
779
0d7ea902
VZ
780 // resume process we created now - whether the thread creation succeeded or
781 // not
782 if ( ::ResumeThread(pi.hThread) == (DWORD)-1 )
783 {
784 // ignore it - what can we do?
f6bcfd97 785 wxLogLastError(wxT("ResumeThread in wxExecute"));
0d7ea902
VZ
786 }
787
788 // close unneeded handle
789 if ( !::CloseHandle(pi.hThread) )
f6bcfd97 790 wxLogLastError(wxT("CloseHandle(hThread)"));
0d7ea902 791
cb6827a8
VZ
792 if ( !hThread )
793 {
f6bcfd97 794 wxLogLastError(wxT("CreateThread in wxExecute"));
cb6827a8
VZ
795
796 DestroyWindow(hwnd);
797 delete data;
798
799 // the process still started up successfully...
800 return pi.dwProcessId;
801 }
e6045e08 802
f6bcfd97
BP
803 ::CloseHandle(hThread);
804
731dd422 805#if wxUSE_IPC
5bd3a2da
VZ
806 // second part of DDE hack: now establish the DDE conversation with the
807 // just launched process
ca289436 808 if ( !ddeServer.empty() )
5bd3a2da 809 {
ca289436
VZ
810 bool ok;
811
812 // give the process the time to init itself
813 //
814 // we use a very big timeout hoping that WaitForInputIdle() will return
815 // much sooner, but not INFINITE just in case the process hangs
816 // completely - like this we will regain control sooner or later
817 switch ( ::WaitForInputIdle(pi.hProcess, 10000 /* 10 seconds */) )
6ba63600 818 {
ca289436
VZ
819 default:
820 wxFAIL_MSG( _T("unexpected WaitForInputIdle() return code") );
821 // fall through
6ba63600 822
ca289436
VZ
823 case -1:
824 wxLogLastError(_T("WaitForInputIdle() in wxExecute"));
6ba63600 825
ca289436
VZ
826 case WAIT_TIMEOUT:
827 wxLogDebug(_T("Timeout too small in WaitForInputIdle"));
828
829 ok = FALSE;
830 break;
831
832 case 0:
833 // ok, process ready to accept DDE requests
834 ok = wxExecuteDDE(ddeServer, ddeTopic, ddeCommand);
6ba63600 835 }
5bd3a2da 836 }
731dd422 837#endif // wxUSE_IPC
5bd3a2da 838
fbf456aa 839 if ( !(flags & wxEXEC_SYNC) )
cb6827a8
VZ
840 {
841 // clean up will be done when the process terminates
e6045e08
VZ
842
843 // return the pid
cb6827a8
VZ
844 return pi.dwProcessId;
845 }
e6045e08 846
068a7cfe 847 // disable all app windows while waiting for the child process to finish
0d7ea902 848#if wxUSE_GUI
068a7cfe
VZ
849
850 /*
851 We use a dirty hack here to disable all application windows (which we
852 must do because otherwise the calls to wxYield() could lead to some very
853 unexpected reentrancies in the users code) but to avoid losing
854 focus/activation entirely when the child process terminates which would
855 happen if we simply disabled everything using wxWindowDisabler. Indeed,
856 remember that Windows will never activate a disabled window and when the
857 last childs window is closed and Windows looks for a window to activate
858 all our windows are still disabled. There is no way to enable them in
859 time because we don't know when the childs windows are going to be
860 closed, so the solution we use here is to keep one special tiny frame
861 enabled all the time. Then when the child terminates it will get
862 activated and when we close it below -- after reenabling all the other
863 windows! -- the previously active window becomes activated again and
864 everything is ok.
865 */
866 wxWindow *winActive;
cd6ce4a9
VZ
867 {
868 wxBusyCursor bc;
869
068a7cfe 870 // first disable all existing windows
cd6ce4a9 871 wxWindowDisabler wd;
068a7cfe
VZ
872
873 // then create an "invisible" frame: it has minimal size, is positioned
874 // (hopefully) outside the screen and doesn't appear on the taskbar
875 winActive = new wxFrame
876 (
877 wxTheApp->GetTopWindow(),
878 -1,
879 _T(""),
880 wxPoint(32600, 32600),
881 wxSize(1, 1),
882 wxDEFAULT_FRAME_STYLE | wxFRAME_NO_TASKBAR
883 );
884 winActive->Show();
0d7ea902
VZ
885#endif // wxUSE_GUI
886
79066131
VZ
887 // wait until the child process terminates
888 while ( data->state )
889 {
890#if wxUSE_STREAMS
891 bufOut.Update();
892 bufErr.Update();
893#endif // wxUSE_STREAMS
894
895 // don't eat 100% of the CPU -- ugly but anything else requires
896 // real async IO which we don't have for the moment
897 ::Sleep(50);
898
45d5a0c6 899#if wxUSE_GUI
79066131
VZ
900 // repaint the GUI
901 wxYield();
45d5a0c6
VZ
902#else // !GUI
903 // dispatch the messages to the hidden window so that it could
904 // process the wxWM_PROC_TERMINATED notification
905 MSG msg;
906 ::PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE);
907#endif // GUI/!GUI
79066131 908 }
e6045e08 909
0d7ea902 910#if wxUSE_GUI
cd6ce4a9 911 }
068a7cfe
VZ
912
913 // finally delete the dummy frame and, as wd has been already destroyed and
914 // the other windows reenabled, the activation is going to return to the
915 // window which had it before
916 winActive->Destroy();
0d7ea902
VZ
917#endif // wxUSE_GUI
918
e6045e08 919 DWORD dwExitCode = data->dwExitCode;
cb6827a8
VZ
920 delete data;
921
e6045e08
VZ
922 // return the exit code
923 return dwExitCode;
cb6827a8
VZ
924#else // Win16
925 long instanceID = WinExec((LPCSTR) WXSTRINGCAST command, SW_SHOW);
fbf456aa
VZ
926 if (instanceID < 32)
927 return flags & wxEXEC_SYNC ? -1 : 0;
e6045e08 928
fbf456aa
VZ
929 if ( flags & wxEXEC_SYNC )
930 {
cb6827a8 931 int running;
fbf456aa
VZ
932 do
933 {
cb6827a8 934 wxYield();
27a9bd48 935 running = GetModuleUsage((HINSTANCE)instanceID);
cb6827a8
VZ
936 } while (running);
937 }
938
fbf456aa 939 return instanceID;
cb6827a8 940#endif // Win16/32
32592631 941}
c740f496 942
0493ba13 943long wxExecute(wxChar **argv, int flags, wxProcess *handler)
c740f496 944{
cb6827a8 945 wxString command;
e6045e08 946
0493ba13 947 for ( ;; )
cb6827a8 948 {
0493ba13
VZ
949 command += *argv++;
950 if ( !*argv )
951 break;
cb6827a8 952
0493ba13
VZ
953 command += _T(' ');
954 }
cb6827a8 955
fbf456aa 956 return wxExecute(command, flags, handler);
c740f496 957}
006162a9 958