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