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