]> git.saurik.com Git - wxWidgets.git/blame - src/msw/utilsexc.cpp
use SetMenuItemInfo() to update the item label to avoid reseting its bitmap and so...
[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{
386a2898
VZ
436 // we can read if there's something in the put back buffer
437 // even pipe is closed
438 if ( m_wbacksize > m_wbackcur )
439 return true;
440
441 wxPipeInputStream * const self = wxConstCast(this, wxPipeInputStream);
442
79066131 443 if ( !IsOpened() )
386a2898
VZ
444 {
445 // set back to mark Eof as it may have been unset by Ungetch()
446 self->m_lasterror = wxSTREAM_EOF;
27d2dbbc 447 return false;
386a2898 448 }
79066131 449
f6bcfd97
BP
450 DWORD nAvailable;
451
452 // function name is misleading, it works with anon pipes as well
453 DWORD rc = ::PeekNamedPipe
454 (
455 m_hInput, // handle
456 NULL, 0, // ptr to buffer and its size
457 NULL, // [out] bytes read
458 &nAvailable, // [out] bytes available
459 NULL // [out] bytes left
460 );
461
462 if ( !rc )
463 {
464 if ( ::GetLastError() != ERROR_BROKEN_PIPE )
465 {
466 // unexpected error
467 wxLogLastError(_T("PeekNamedPipe"));
468 }
8b33ae2d 469
3103e8a9 470 // don't try to continue reading from a pipe if an error occurred or if
f6bcfd97 471 // it had been closed
79066131
VZ
472 ::CloseHandle(m_hInput);
473
2b5f62a0
VZ
474 self->m_hInput = INVALID_HANDLE_VALUE;
475 self->m_lasterror = wxSTREAM_EOF;
476
477 nAvailable = 0;
f6bcfd97 478 }
79066131
VZ
479
480 return nAvailable != 0;
f6bcfd97
BP
481}
482
483size_t wxPipeInputStream::OnSysRead(void *buffer, size_t len)
484{
2b5f62a0 485 if ( !IsOpened() )
79066131
VZ
486 {
487 m_lasterror = wxSTREAM_EOF;
488
f6bcfd97 489 return 0;
79066131
VZ
490 }
491
f6bcfd97
BP
492 DWORD bytesRead;
493 if ( !::ReadFile(m_hInput, buffer, len, &bytesRead, NULL) )
494 {
2b5f62a0
VZ
495 m_lasterror = ::GetLastError() == ERROR_BROKEN_PIPE
496 ? wxSTREAM_EOF
497 : wxSTREAM_READ_ERROR;
8b33ae2d 498 }
f6bcfd97 499
3103e8a9 500 // bytesRead is set to 0, as desired, if an error occurred
8b33ae2d
GL
501 return bytesRead;
502}
503
79066131 504// ----------------------------------------------------------------------------
8b33ae2d 505// wxPipeOutputStream
79066131 506// ----------------------------------------------------------------------------
8b33ae2d
GL
507
508wxPipeOutputStream::wxPipeOutputStream(HANDLE hOutput)
509{
510 m_hOutput = hOutput;
3338a5bd
VZ
511
512 // unblock the pipe to prevent deadlocks when we're writing to the pipe
513 // from which the child process can't read because it is writing in its own
514 // end of it
515 DWORD mode = PIPE_READMODE_BYTE | PIPE_NOWAIT;
516 if ( !::SetNamedPipeHandleState
517 (
518 m_hOutput,
519 &mode,
520 NULL, // collection count (we don't set it)
521 NULL // timeout (we don't set it neither)
522 ) )
523 {
524 wxLogLastError(_T("SetNamedPipeHandleState(PIPE_NOWAIT)"));
525 }
cd6ce4a9 526}
8b33ae2d 527
8f0ff178 528bool wxPipeOutputStream::Close()
8b33ae2d 529{
8f0ff178 530 return ::CloseHandle(m_hOutput) != 0;
8b33ae2d
GL
531}
532
8f0ff178 533
8b33ae2d
GL
534size_t wxPipeOutputStream::OnSysWrite(const void *buffer, size_t len)
535{
2b5f62a0 536 m_lasterror = wxSTREAM_NO_ERROR;
3338a5bd
VZ
537
538 DWORD totalWritten = 0;
539 while ( len > 0 )
f6bcfd97 540 {
3338a5bd
VZ
541 DWORD chunkWritten;
542 if ( !::WriteFile(m_hOutput, buffer, len, &chunkWritten, NULL) )
543 {
544 m_lasterror = ::GetLastError() == ERROR_BROKEN_PIPE
545 ? wxSTREAM_EOF
546 : wxSTREAM_WRITE_ERROR;
547 break;
548 }
549
550 if ( !chunkWritten )
551 break;
552
553 buffer = (char *)buffer + chunkWritten;
554 totalWritten += chunkWritten;
555 len -= chunkWritten;
8b33ae2d 556 }
f6bcfd97 557
3338a5bd 558 return totalWritten;
8b33ae2d
GL
559}
560
79066131
VZ
561#endif // wxUSE_STREAMS
562
b568d04f 563// ============================================================================
79066131 564// wxExecute functions family
b568d04f 565// ============================================================================
5260b1c5 566
ca289436
VZ
567#if wxUSE_IPC
568
569// connect to the given server via DDE and ask it to execute the command
42d0df00
VZ
570bool
571wxExecuteDDE(const wxString& ddeServer,
572 const wxString& ddeTopic,
573 const wxString& ddeCommand)
ca289436 574{
999836aa 575 bool ok wxDUMMY_INITIALIZE(false);
ca289436
VZ
576
577 wxDDEClient client;
42d0df00
VZ
578 wxConnectionBase *
579 conn = client.MakeConnection(wxEmptyString, ddeServer, ddeTopic);
ca289436
VZ
580 if ( !conn )
581 {
27d2dbbc 582 ok = false;
ca289436
VZ
583 }
584 else // connected to DDE server
585 {
4dd03db9
VZ
586 // the added complication here is that although most programs use
587 // XTYP_EXECUTE for their DDE API, some important ones -- like Word
588 // and other MS stuff - use XTYP_REQUEST!
ca289436 589 //
4dd03db9
VZ
590 // moreover, anotheri mportant program (IE) understands both but
591 // returns an error from Execute() so we must try Request() first
592 // to avoid doing it twice
ca289436 593 {
4dd03db9 594 // we're prepared for this one to fail, so don't show errors
ca289436 595 wxLogNull noErrors;
4dd03db9
VZ
596
597 ok = conn->Request(ddeCommand) != NULL;
ca289436
VZ
598 }
599
600 if ( !ok )
601 {
4dd03db9
VZ
602 // now try execute -- but show the errors
603 ok = conn->Execute(ddeCommand);
ca289436
VZ
604 }
605 }
606
607 return ok;
608}
609
610#endif // wxUSE_IPC
611
fbf456aa 612long wxExecute(const wxString& cmd, int flags, wxProcess *handler)
32592631 613{
c3fad64b 614 wxCHECK_MSG( !cmd.empty(), 0, wxT("empty command in wxExecute") );
5bd3a2da 615
647b8e37
VZ
616#if wxUSE_THREADS
617 // for many reasons, the code below breaks down if it's called from another
618 // thread -- this could be fixed, but as Unix versions don't support this
619 // neither I don't want to waste time on this now
620 wxASSERT_MSG( wxThread::IsMain(),
621 _T("wxExecute() can be called only from the main thread") );
622#endif // wxUSE_THREADS
623
039f62f4 624 wxString command;
6ba63600 625
731dd422 626#if wxUSE_IPC
5bd3a2da
VZ
627 // DDE hack: this is really not pretty, but we need to allow this for
628 // transparent handling of DDE servers in wxMimeTypesManager. Usually it
629 // returns the command which should be run to view/open/... a file of the
630 // given type. Sometimes, however, this command just launches the server
631 // and an additional DDE request must be made to really open the file. To
632 // keep all this well hidden from the application, we allow a special form
6ba63600 633 // of command: WX_DDE#<command>#DDE_SERVER#DDE_TOPIC#DDE_COMMAND in which
5bd3a2da 634 // case we execute just <command> and process the rest below
039f62f4 635 wxString ddeServer, ddeTopic, ddeCommand;
5bd3a2da
VZ
636 static const size_t lenDdePrefix = 7; // strlen("WX_DDE:")
637 if ( cmd.Left(lenDdePrefix) == _T("WX_DDE#") )
638 {
ca289436
VZ
639 // speed up the concatenations below
640 ddeServer.reserve(256);
641 ddeTopic.reserve(256);
642 ddeCommand.reserve(256);
643
5bd3a2da
VZ
644 const wxChar *p = cmd.c_str() + 7;
645 while ( *p && *p != _T('#') )
646 {
647 command += *p++;
648 }
649
650 if ( *p )
651 {
652 // skip '#'
653 p++;
654 }
655 else
656 {
657 wxFAIL_MSG(_T("invalid WX_DDE command in wxExecute"));
658 }
659
660 while ( *p && *p != _T('#') )
661 {
662 ddeServer += *p++;
663 }
664
665 if ( *p )
666 {
667 // skip '#'
668 p++;
669 }
670 else
671 {
672 wxFAIL_MSG(_T("invalid WX_DDE command in wxExecute"));
673 }
674
675 while ( *p && *p != _T('#') )
676 {
677 ddeTopic += *p++;
678 }
679
680 if ( *p )
681 {
682 // skip '#'
683 p++;
684 }
685 else
686 {
687 wxFAIL_MSG(_T("invalid WX_DDE command in wxExecute"));
688 }
689
690 while ( *p )
691 {
692 ddeCommand += *p++;
693 }
6ba63600 694
ca289436
VZ
695 // if we want to just launch the program and not wait for its
696 // termination, try to execute DDE command right now, it can succeed if
697 // the process is already running - but as it fails if it's not
698 // running, suppress any errors it might generate
fbf456aa 699 if ( !(flags & wxEXEC_SYNC) )
6ba63600 700 {
ca289436
VZ
701 wxLogNull noErrors;
702 if ( wxExecuteDDE(ddeServer, ddeTopic, ddeCommand) )
703 {
704 // a dummy PID - this is a hack, of course, but it's well worth
705 // it as we don't open a new server each time we're called
706 // which would be quite bad
707 return -1;
708 }
6ba63600 709 }
5bd3a2da
VZ
710 }
711 else
731dd422 712#endif // wxUSE_IPC
5bd3a2da
VZ
713 {
714 // no DDE
715 command = cmd;
716 }
32592631 717
f6bcfd97
BP
718 // the IO redirection is only supported with wxUSE_STREAMS
719 BOOL redirect = FALSE;
79066131 720
4676948b 721#if wxUSE_STREAMS && !defined(__WXWINCE__)
79066131
VZ
722 wxPipe pipeIn, pipeOut, pipeErr;
723
724 // we'll save here the copy of pipeIn[Write]
33ac7e6f 725 HANDLE hpipeStdinWrite = INVALID_HANDLE_VALUE;
8b33ae2d 726
cd6ce4a9 727 // open the pipes to which child process IO will be redirected if needed
cd6ce4a9
VZ
728 if ( handler && handler->IsRedirected() )
729 {
79066131
VZ
730 // create pipes for redirecting stdin, stdout and stderr
731 if ( !pipeIn.Create() || !pipeOut.Create() || !pipeErr.Create() )
cd6ce4a9 732 {
79066131 733 wxLogSysError(_("Failed to redirect the child process IO"));
8b33ae2d 734
fbf456aa
VZ
735 // indicate failure: we need to return different error code
736 // depending on the sync flag
737 return flags & wxEXEC_SYNC ? -1 : 0;
8b33ae2d
GL
738 }
739
f6bcfd97 740 redirect = TRUE;
8b33ae2d 741 }
f6bcfd97 742#endif // wxUSE_STREAMS
5bd3a2da 743
cb6827a8
VZ
744 // create the process
745 STARTUPINFO si;
11c7d5b6 746 wxZeroMemory(si);
cb6827a8
VZ
747 si.cb = sizeof(si);
748
4676948b 749#if wxUSE_STREAMS && !defined(__WXWINCE__)
f6bcfd97 750 if ( redirect )
cb6827a8 751 {
fbf456aa 752 si.dwFlags = STARTF_USESTDHANDLES;
f6bcfd97 753
79066131
VZ
754 si.hStdInput = pipeIn[wxPipe::Read];
755 si.hStdOutput = pipeOut[wxPipe::Write];
756 si.hStdError = pipeErr[wxPipe::Write];
f6bcfd97 757
fbf456aa
VZ
758 // when the std IO is redirected, we don't show the (console) process
759 // window by default, but this can be overridden by the caller by
760 // specifying wxEXEC_NOHIDE flag
761 if ( !(flags & wxEXEC_NOHIDE) )
762 {
763 si.dwFlags |= STARTF_USESHOWWINDOW;
764 si.wShowWindow = SW_HIDE;
765 }
f6bcfd97
BP
766
767 // we must duplicate the handle to the write side of stdin pipe to make
79066131
VZ
768 // it non inheritable: indeed, we must close the writing end of pipeIn
769 // before launching the child process as otherwise this handle will be
f6bcfd97
BP
770 // inherited by the child which will never close it and so the pipe
771 // will never be closed and the child will be left stuck in ReadFile()
79066131 772 HANDLE pipeInWrite = pipeIn.Detach(wxPipe::Write);
f6bcfd97
BP
773 if ( !::DuplicateHandle
774 (
79066131
VZ
775 ::GetCurrentProcess(),
776 pipeInWrite,
777 ::GetCurrentProcess(),
f6bcfd97
BP
778 &hpipeStdinWrite,
779 0, // desired access: unused here
780 FALSE, // not inherited
781 DUPLICATE_SAME_ACCESS // same access as for src handle
782 ) )
cd6ce4a9 783 {
f6bcfd97 784 wxLogLastError(_T("DuplicateHandle"));
8b33ae2d 785 }
cd6ce4a9 786
79066131 787 ::CloseHandle(pipeInWrite);
f6bcfd97
BP
788 }
789#endif // wxUSE_STREAMS
cb6827a8 790
f6bcfd97 791 PROCESS_INFORMATION pi;
4676948b 792 DWORD dwFlags = CREATE_SUSPENDED;
78c743d8 793
4676948b
JS
794#ifndef __WXWINCE__
795 dwFlags |= CREATE_DEFAULT_ERROR_MODE ;
78c743d8 796#else
9cd03a43
WS
797 // we are assuming commands without spaces for now
798 wxString moduleName = command.BeforeFirst(wxT(' '));
799 wxString arguments = command.AfterFirst(wxT(' '));
4676948b 800#endif
f6bcfd97
BP
801
802 bool ok = ::CreateProcess
803 (
9cd03a43 804 // WinCE requires appname to be non null
78c743d8
JS
805 // Win32 allows for null
806#ifdef __WXWINCE__
807 (wxChar *)
c9f78968 808 moduleName.wx_str(),// application name
78c743d8 809 (wxChar *)
c9f78968 810 arguments.wx_str(), // arguments
78c743d8 811#else
9cd03a43 812 NULL, // application name (use only cmd line)
f6bcfd97 813 (wxChar *)
c9f78968 814 command.wx_str(), // full command line
78c743d8 815#endif
9cd03a43
WS
816 NULL, // security attributes: defaults for both
817 NULL, // the process and its main thread
818 redirect, // inherit handles if we use pipes
819 dwFlags, // process creation flags
820 NULL, // environment (use the same)
821 NULL, // current directory (use the same)
822 &si, // startup info (unused here)
823 &pi // process info
f6bcfd97
BP
824 ) != 0;
825
4676948b 826#if wxUSE_STREAMS && !defined(__WXWINCE__)
f6bcfd97
BP
827 // we can close the pipe ends used by child anyhow
828 if ( redirect )
829 {
79066131
VZ
830 ::CloseHandle(pipeIn.Detach(wxPipe::Read));
831 ::CloseHandle(pipeOut.Detach(wxPipe::Write));
832 ::CloseHandle(pipeErr.Detach(wxPipe::Write));
cb6827a8 833 }
f6bcfd97 834#endif // wxUSE_STREAMS
cb6827a8 835
f6bcfd97 836 if ( !ok )
5e1febfa 837 {
4676948b 838#if wxUSE_STREAMS && !defined(__WXWINCE__)
f6bcfd97
BP
839 // close the other handles too
840 if ( redirect )
5e1febfa 841 {
79066131
VZ
842 ::CloseHandle(pipeOut.Detach(wxPipe::Read));
843 ::CloseHandle(pipeErr.Detach(wxPipe::Read));
5e1febfa 844 }
f6bcfd97 845#endif // wxUSE_STREAMS
5e1febfa 846
f6bcfd97
BP
847 wxLogSysError(_("Execution of command '%s' failed"), command.c_str());
848
fbf456aa 849 return flags & wxEXEC_SYNC ? -1 : 0;
f6bcfd97 850 }
8b33ae2d 851
4676948b 852#if wxUSE_STREAMS && !defined(__WXWINCE__)
79066131
VZ
853 // the input buffer bufOut is connected to stdout, this is why it is
854 // called bufOut and not bufIn
855 wxStreamTempInputBuffer bufOut,
856 bufErr;
857
f6bcfd97
BP
858 if ( redirect )
859 {
8b33ae2d 860 // We can now initialize the wxStreams
79066131
VZ
861 wxPipeInputStream *
862 outStream = new wxPipeInputStream(pipeOut.Detach(wxPipe::Read));
863 wxPipeInputStream *
864 errStream = new wxPipeInputStream(pipeErr.Detach(wxPipe::Read));
865 wxPipeOutputStream *
866 inStream = new wxPipeOutputStream(hpipeStdinWrite);
867
868 handler->SetPipeStreams(outStream, inStream, errStream);
8b33ae2d 869
79066131
VZ
870 bufOut.Init(outStream);
871 bufErr.Init(errStream);
8b33ae2d 872 }
f6bcfd97 873#endif // wxUSE_STREAMS
8b33ae2d 874
cb6827a8
VZ
875 // create a hidden window to receive notification about process
876 // termination
eccd1992
VZ
877 HWND hwnd = wxCreateHiddenWindow
878 (
879 &gs_classForHiddenWindow,
880 wxMSWEXEC_WNDCLASSNAME,
881 (WNDPROC)wxExecuteWindowCbk
882 );
883
223d09f6 884 wxASSERT_MSG( hwnd, wxT("can't create a hidden window for wxExecute") );
e6045e08 885
cb6827a8
VZ
886 // Alloc data
887 wxExecuteData *data = new wxExecuteData;
888 data->hProcess = pi.hProcess;
889 data->dwProcessId = pi.dwProcessId;
890 data->hWnd = hwnd;
fbf456aa
VZ
891 data->state = (flags & wxEXEC_SYNC) != 0;
892 if ( flags & wxEXEC_SYNC )
e6045e08 893 {
5e1febfa
VZ
894 // handler may be !NULL for capturing program output, but we don't use
895 // it wxExecuteData struct in this case
e6045e08
VZ
896 data->handler = NULL;
897 }
898 else
899 {
900 // may be NULL or not
901 data->handler = handler;
902 }
cb6827a8
VZ
903
904 DWORD tid;
905 HANDLE hThread = ::CreateThread(NULL,
906 0,
19193a2c 907 wxExecuteThread,
cb6827a8
VZ
908 (void *)data,
909 0,
910 &tid);
911
0d7ea902
VZ
912 // resume process we created now - whether the thread creation succeeded or
913 // not
914 if ( ::ResumeThread(pi.hThread) == (DWORD)-1 )
915 {
916 // ignore it - what can we do?
f6bcfd97 917 wxLogLastError(wxT("ResumeThread in wxExecute"));
0d7ea902
VZ
918 }
919
920 // close unneeded handle
921 if ( !::CloseHandle(pi.hThread) )
f6bcfd97 922 wxLogLastError(wxT("CloseHandle(hThread)"));
0d7ea902 923
cb6827a8
VZ
924 if ( !hThread )
925 {
f6bcfd97 926 wxLogLastError(wxT("CreateThread in wxExecute"));
cb6827a8
VZ
927
928 DestroyWindow(hwnd);
929 delete data;
930
931 // the process still started up successfully...
932 return pi.dwProcessId;
933 }
e6045e08 934
5a8561fc 935 gs_asyncThreads.push_back(hThread);
f6bcfd97 936
4676948b 937#if wxUSE_IPC && !defined(__WXWINCE__)
5bd3a2da
VZ
938 // second part of DDE hack: now establish the DDE conversation with the
939 // just launched process
ca289436 940 if ( !ddeServer.empty() )
5bd3a2da 941 {
ca289436
VZ
942 bool ok;
943
944 // give the process the time to init itself
945 //
946 // we use a very big timeout hoping that WaitForInputIdle() will return
947 // much sooner, but not INFINITE just in case the process hangs
948 // completely - like this we will regain control sooner or later
949 switch ( ::WaitForInputIdle(pi.hProcess, 10000 /* 10 seconds */) )
6ba63600 950 {
ca289436
VZ
951 default:
952 wxFAIL_MSG( _T("unexpected WaitForInputIdle() return code") );
953 // fall through
6ba63600 954
ca289436
VZ
955 case -1:
956 wxLogLastError(_T("WaitForInputIdle() in wxExecute"));
6ba63600 957
ca289436
VZ
958 case WAIT_TIMEOUT:
959 wxLogDebug(_T("Timeout too small in WaitForInputIdle"));
960
27d2dbbc 961 ok = false;
ca289436
VZ
962 break;
963
964 case 0:
965 // ok, process ready to accept DDE requests
966 ok = wxExecuteDDE(ddeServer, ddeTopic, ddeCommand);
6ba63600 967 }
1b47bebc
VZ
968
969 if ( !ok )
970 {
971 wxLogDebug(_T("Failed to send DDE request to the process \"%s\"."),
972 cmd.c_str());
973 }
5bd3a2da 974 }
731dd422 975#endif // wxUSE_IPC
5bd3a2da 976
fbf456aa 977 if ( !(flags & wxEXEC_SYNC) )
cb6827a8
VZ
978 {
979 // clean up will be done when the process terminates
e6045e08
VZ
980
981 // return the pid
cb6827a8
VZ
982 return pi.dwProcessId;
983 }
e6045e08 984
d60e2332
VZ
985 wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
986 wxCHECK_MSG( traits, -1, _T("no wxAppTraits in wxExecute()?") );
987
c3fad64b 988 void *cookie = NULL;
f38f6899
VZ
989 if ( !(flags & wxEXEC_NODISABLE) )
990 {
f38f6899
VZ
991 // disable all app windows while waiting for the child process to finish
992 cookie = traits->BeforeChildWaitLoop();
993 }
e2478fde
VZ
994
995 // wait until the child process terminates
996 while ( data->state )
997 {
4676948b 998#if wxUSE_STREAMS && !defined(__WXWINCE__)
4d425dee 999 if ( !bufOut.Update() && !bufErr.Update() )
79066131 1000#endif // wxUSE_STREAMS
4d425dee
VZ
1001 {
1002 // don't eat 100% of the CPU -- ugly but anything else requires
1003 // real async IO which we don't have for the moment
1004 ::Sleep(50);
1005 }
e6045e08 1006
e2478fde
VZ
1007 // we must process messages or we'd never get wxWM_PROC_TERMINATED
1008 traits->AlwaysYield();
cd6ce4a9 1009 }
068a7cfe 1010
d60e2332
VZ
1011 if ( !(flags & wxEXEC_NODISABLE) )
1012 {
1013 // reenable disabled windows back
f38f6899 1014 traits->AfterChildWaitLoop(cookie);
d60e2332 1015 }
0d7ea902 1016
e6045e08 1017 DWORD dwExitCode = data->dwExitCode;
cb6827a8
VZ
1018 delete data;
1019
e6045e08
VZ
1020 // return the exit code
1021 return dwExitCode;
32592631 1022}
c740f496 1023
05718a98
VZ
1024template <typename CharType>
1025long wxExecuteImpl(CharType **argv, int flags, wxProcess *handler)
c740f496 1026{
cb6827a8 1027 wxString command;
05718a98 1028 command.reserve(1024);
e6045e08 1029
3cdd564f 1030 wxString arg;
0493ba13 1031 for ( ;; )
cb6827a8 1032 {
3cdd564f
VZ
1033 arg = *argv++;
1034
a6eac99d
VZ
1035 bool quote;
1036 if ( arg.empty() )
1037 {
1038 // we need to quote empty arguments, otherwise they'd just
1039 // disappear
1040 quote = true;
1041 }
1042 else // non-empty
1043 {
1044 // escape any quotes present in the string to avoid interfering
1045 // with the command line parsing in the child process
1046 arg.Replace("\"", "\\\"", true /* replace all */);
3cdd564f 1047
a6eac99d
VZ
1048 // and quote any arguments containing the spaces to prevent them from
1049 // being broken down
1050 quote = arg.find_first_of(" \t") != wxString::npos;
1051 }
1052
1053 if ( quote )
3cdd564f 1054 command += '\"' + arg + '\"';
a6eac99d
VZ
1055 else
1056 command += arg;
3cdd564f 1057
0493ba13
VZ
1058 if ( !*argv )
1059 break;
cb6827a8 1060
05718a98 1061 command += ' ';
0493ba13 1062 }
cb6827a8 1063
fbf456aa 1064 return wxExecute(command, flags, handler);
c740f496 1065}
05718a98
VZ
1066
1067long wxExecute(char **argv, int flags, wxProcess *handler)
1068{
1069 return wxExecuteImpl(argv, flags, handler);
1070}
1071
d7ef641d
VZ
1072#if wxUSE_UNICODE
1073
05718a98
VZ
1074long wxExecute(wchar_t **argv, int flags, wxProcess *handler)
1075{
1076 return wxExecuteImpl(argv, flags, handler);
1077}
d7ef641d
VZ
1078
1079#endif // wxUSE_UNICODE