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