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