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