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