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