]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/utilsexc.cpp
Don't use wxCHECK_W32API_VERSION() in #if when it can be undefined.
[wxWidgets.git] / src / msw / utilsexc.cpp
... / ...
CommitLineData
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
99static const wxChar *wxMSWEXEC_WNDCLASSNAME = wxT("_wxExecute_Internal_Class");
100static const wxChar *gs_classForHiddenWindow = NULL;
101
102// event used to wake up threads waiting in wxExecuteThread
103static HANDLE gs_heventShutdown = NULL;
104
105// handles of all threads monitoring the execution of asynchronously running
106// processes
107static wxVector<HANDLE> gs_asyncThreads;
108
109// ----------------------------------------------------------------------------
110// private types
111// ----------------------------------------------------------------------------
112
113// structure describing the process we're being waiting for
114struct wxExecuteData
115{
116public:
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
133class wxExecuteModule : public wxModule
134{
135public:
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
187private:
188 DECLARE_DYNAMIC_CLASS(wxExecuteModule)
189};
190
191IMPLEMENT_DYNAMIC_CLASS(wxExecuteModule, wxModule)
192
193#if wxUSE_STREAMS && !defined(__WXWINCE__)
194
195// ----------------------------------------------------------------------------
196// wxPipeStreams
197// ----------------------------------------------------------------------------
198
199class wxPipeInputStream: public wxInputStream
200{
201public:
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
211protected:
212 size_t OnSysRead(void *buffer, size_t len);
213
214protected:
215 HANDLE m_hInput;
216
217 wxDECLARE_NO_COPY_CLASS(wxPipeInputStream);
218};
219
220class wxPipeOutputStream: public wxOutputStream
221{
222public:
223 wxPipeOutputStream(HANDLE hOutput);
224 virtual ~wxPipeOutputStream() { Close(); }
225 bool Close();
226
227protected:
228 size_t OnSysWrite(const void *buffer, size_t len);
229
230protected:
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
244class wxPipe
245{
246public:
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
309private:
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
324static 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
376LRESULT 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
420wxPipeInputStream::wxPipeInputStream(HANDLE hInput)
421{
422 m_hInput = hInput;
423}
424
425wxPipeInputStream::~wxPipeInputStream()
426{
427 if ( m_hInput != INVALID_HANDLE_VALUE )
428 ::CloseHandle(m_hInput);
429}
430
431bool 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
480size_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
505wxPipeOutputStream::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
525bool wxPipeOutputStream::Close()
526{
527 return ::CloseHandle(m_hOutput) != 0;
528}
529
530
531size_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
567bool
568wxExecuteDDE(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
609long 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 (wxChar *)
861 moduleName.wx_str(),// application name
862 (wxChar *)
863 arguments.wx_str(), // arguments
864#else
865 NULL, // application name (use only cmd line)
866 (wxChar *)
867 command.wx_str(), // full command line
868#endif
869 NULL, // security attributes: defaults for both
870 NULL, // the process and its main thread
871 redirect, // inherit handles if we use pipes
872 dwFlags, // process creation flags
873 envBuffer.data(), // environment (may be NULL which is fine)
874 useCwd // initial working directory
875 ? const_cast<wxChar *>(env->cwd.wx_str())
876 : NULL, // (or use the same)
877 &si, // startup info (unused here)
878 &pi // process info
879 ) != 0;
880
881#if wxUSE_STREAMS && !defined(__WXWINCE__)
882 // we can close the pipe ends used by child anyhow
883 if ( redirect )
884 {
885 ::CloseHandle(pipeIn.Detach(wxPipe::Read));
886 ::CloseHandle(pipeOut.Detach(wxPipe::Write));
887 ::CloseHandle(pipeErr.Detach(wxPipe::Write));
888 }
889#endif // wxUSE_STREAMS
890
891 if ( !ok )
892 {
893#if wxUSE_STREAMS && !defined(__WXWINCE__)
894 // close the other handles too
895 if ( redirect )
896 {
897 ::CloseHandle(pipeOut.Detach(wxPipe::Read));
898 ::CloseHandle(pipeErr.Detach(wxPipe::Read));
899 }
900#endif // wxUSE_STREAMS
901
902 wxLogSysError(_("Execution of command '%s' failed"), command.c_str());
903
904 return flags & wxEXEC_SYNC ? -1 : 0;
905 }
906
907#if wxUSE_STREAMS && !defined(__WXWINCE__)
908 // the input buffer bufOut is connected to stdout, this is why it is
909 // called bufOut and not bufIn
910 wxStreamTempInputBuffer bufOut,
911 bufErr;
912
913 if ( redirect )
914 {
915 // We can now initialize the wxStreams
916 wxPipeInputStream *
917 outStream = new wxPipeInputStream(pipeOut.Detach(wxPipe::Read));
918 wxPipeInputStream *
919 errStream = new wxPipeInputStream(pipeErr.Detach(wxPipe::Read));
920 wxPipeOutputStream *
921 inStream = new wxPipeOutputStream(hpipeStdinWrite);
922
923 handler->SetPipeStreams(outStream, inStream, errStream);
924
925 bufOut.Init(outStream);
926 bufErr.Init(errStream);
927 }
928#endif // wxUSE_STREAMS
929
930 // create a hidden window to receive notification about process
931 // termination
932 HWND hwnd = wxCreateHiddenWindow
933 (
934 &gs_classForHiddenWindow,
935 wxMSWEXEC_WNDCLASSNAME,
936 (WNDPROC)wxExecuteWindowCbk
937 );
938
939 wxASSERT_MSG( hwnd, wxT("can't create a hidden window for wxExecute") );
940
941 // Alloc data
942 wxExecuteData *data = new wxExecuteData;
943 data->hProcess = pi.hProcess;
944 data->dwProcessId = pi.dwProcessId;
945 data->hWnd = hwnd;
946 data->state = (flags & wxEXEC_SYNC) != 0;
947 if ( flags & wxEXEC_SYNC )
948 {
949 // handler may be !NULL for capturing program output, but we don't use
950 // it wxExecuteData struct in this case
951 data->handler = NULL;
952 }
953 else
954 {
955 // may be NULL or not
956 data->handler = handler;
957
958 if (handler)
959 handler->SetPid(pi.dwProcessId);
960 }
961
962 DWORD tid;
963 HANDLE hThread = ::CreateThread(NULL,
964 0,
965 wxExecuteThread,
966 (void *)data,
967 0,
968 &tid);
969
970 // resume process we created now - whether the thread creation succeeded or
971 // not
972 if ( ::ResumeThread(pi.hThread) == (DWORD)-1 )
973 {
974 // ignore it - what can we do?
975 wxLogLastError(wxT("ResumeThread in wxExecute"));
976 }
977
978 // close unneeded handle
979 if ( !::CloseHandle(pi.hThread) )
980 {
981 wxLogLastError(wxT("CloseHandle(hThread)"));
982 }
983
984 if ( !hThread )
985 {
986 wxLogLastError(wxT("CreateThread in wxExecute"));
987
988 DestroyWindow(hwnd);
989 delete data;
990
991 // the process still started up successfully...
992 return pi.dwProcessId;
993 }
994
995 gs_asyncThreads.push_back(hThread);
996
997#if wxUSE_IPC && !defined(__WXWINCE__)
998 // second part of DDE hack: now establish the DDE conversation with the
999 // just launched process
1000 if ( !ddeServer.empty() )
1001 {
1002 bool ok;
1003
1004 // give the process the time to init itself
1005 //
1006 // we use a very big timeout hoping that WaitForInputIdle() will return
1007 // much sooner, but not INFINITE just in case the process hangs
1008 // completely - like this we will regain control sooner or later
1009 switch ( ::WaitForInputIdle(pi.hProcess, 10000 /* 10 seconds */) )
1010 {
1011 default:
1012 wxFAIL_MSG( wxT("unexpected WaitForInputIdle() return code") );
1013 // fall through
1014
1015 case WAIT_FAILED:
1016 wxLogLastError(wxT("WaitForInputIdle() in wxExecute"));
1017
1018 case WAIT_TIMEOUT:
1019 wxLogDebug(wxT("Timeout too small in WaitForInputIdle"));
1020
1021 ok = false;
1022 break;
1023
1024 case 0:
1025 // ok, process ready to accept DDE requests
1026 ok = wxExecuteDDE(ddeServer, ddeTopic, ddeCommand);
1027 }
1028
1029 if ( !ok )
1030 {
1031 wxLogDebug(wxT("Failed to send DDE request to the process \"%s\"."),
1032 cmd.c_str());
1033 }
1034 }
1035#endif // wxUSE_IPC
1036
1037 if ( !(flags & wxEXEC_SYNC) )
1038 {
1039 // clean up will be done when the process terminates
1040
1041 // return the pid
1042 return pi.dwProcessId;
1043 }
1044
1045 wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
1046 wxCHECK_MSG( traits, -1, wxT("no wxAppTraits in wxExecute()?") );
1047
1048 void *cookie = NULL;
1049 if ( !(flags & wxEXEC_NODISABLE) )
1050 {
1051 // disable all app windows while waiting for the child process to finish
1052 cookie = traits->BeforeChildWaitLoop();
1053 }
1054
1055 // wait until the child process terminates
1056 while ( data->state )
1057 {
1058#if wxUSE_STREAMS && !defined(__WXWINCE__)
1059 if ( !bufOut.Update() && !bufErr.Update() )
1060#endif // wxUSE_STREAMS
1061 {
1062 // don't eat 100% of the CPU -- ugly but anything else requires
1063 // real async IO which we don't have for the moment
1064 ::Sleep(50);
1065 }
1066
1067 // we must always process messages for our hidden window or we'd never
1068 // get wxWM_PROC_TERMINATED and so this loop would never terminate
1069 MSG msg;
1070 ::PeekMessage(&msg, data->hWnd, 0, 0, PM_REMOVE);
1071
1072 // we may also need to process messages for all the other application
1073 // windows
1074 if ( !(flags & wxEXEC_NOEVENTS) )
1075 {
1076 wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
1077 if ( loop )
1078 loop->Yield();
1079 }
1080 }
1081
1082 if ( !(flags & wxEXEC_NODISABLE) )
1083 {
1084 // reenable disabled windows back
1085 traits->AfterChildWaitLoop(cookie);
1086 }
1087
1088 DWORD dwExitCode = data->dwExitCode;
1089 delete data;
1090
1091 // return the exit code
1092 return dwExitCode;
1093}
1094
1095template <typename CharType>
1096long wxExecuteImpl(CharType **argv, int flags, wxProcess *handler,
1097 const wxExecuteEnv *env)
1098{
1099 wxString command;
1100 command.reserve(1024);
1101
1102 wxString arg;
1103 for ( ;; )
1104 {
1105 arg = *argv++;
1106
1107 bool quote;
1108 if ( arg.empty() )
1109 {
1110 // we need to quote empty arguments, otherwise they'd just
1111 // disappear
1112 quote = true;
1113 }
1114 else // non-empty
1115 {
1116 // escape any quotes present in the string to avoid interfering
1117 // with the command line parsing in the child process
1118 arg.Replace("\"", "\\\"", true /* replace all */);
1119
1120 // and quote any arguments containing the spaces to prevent them from
1121 // being broken down
1122 quote = arg.find_first_of(" \t") != wxString::npos;
1123 }
1124
1125 if ( quote )
1126 command += '\"' + arg + '\"';
1127 else
1128 command += arg;
1129
1130 if ( !*argv )
1131 break;
1132
1133 command += ' ';
1134 }
1135
1136 return wxExecute(command, flags, handler, env);
1137}
1138
1139long wxExecute(char **argv, int flags, wxProcess *handler,
1140 const wxExecuteEnv *env)
1141{
1142 return wxExecuteImpl(argv, flags, handler, env);
1143}
1144
1145#if wxUSE_UNICODE
1146
1147long wxExecute(wchar_t **argv, int flags, wxProcess *handler,
1148 const wxExecuteEnv *env)
1149{
1150 return wxExecuteImpl(argv, flags, handler, env);
1151}
1152
1153#endif // wxUSE_UNICODE