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