]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/utilsexc.cpp
Fixed inability to select no superscript and no subscript in wxRichTextCtrl's
[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/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
85extern "C" WXDLLIMPEXP_BASE HWND
86wxCreateHiddenWindow(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
102static const wxChar *wxMSWEXEC_WNDCLASSNAME = wxT("_wxExecute_Internal_Class");
103static const wxChar *gs_classForHiddenWindow = NULL;
104
105// event used to wake up threads waiting in wxExecuteThread
106static HANDLE gs_heventShutdown = NULL;
107
108// handles of all threads monitoring the execution of asynchronously running
109// processes
110static wxVector<HANDLE> gs_asyncThreads;
111
112// ----------------------------------------------------------------------------
113// private types
114// ----------------------------------------------------------------------------
115
116// structure describing the process we're being waiting for
117struct wxExecuteData
118{
119public:
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
136class wxExecuteModule : public wxModule
137{
138public:
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
190private:
191 DECLARE_DYNAMIC_CLASS(wxExecuteModule)
192};
193
194IMPLEMENT_DYNAMIC_CLASS(wxExecuteModule, wxModule)
195
196#if wxUSE_STREAMS && !defined(__WXWINCE__)
197
198// ----------------------------------------------------------------------------
199// wxPipeStreams
200// ----------------------------------------------------------------------------
201
202class wxPipeInputStream: public wxInputStream
203{
204public:
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
214protected:
215 size_t OnSysRead(void *buffer, size_t len);
216
217protected:
218 HANDLE m_hInput;
219
220 DECLARE_NO_COPY_CLASS(wxPipeInputStream)
221};
222
223class wxPipeOutputStream: public wxOutputStream
224{
225public:
226 wxPipeOutputStream(HANDLE hOutput);
227 virtual ~wxPipeOutputStream() { Close(); }
228 bool Close();
229
230protected:
231 size_t OnSysWrite(const void *buffer, size_t len);
232
233protected:
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
247class wxPipe
248{
249public:
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
312private:
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
327static 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
379LRESULT 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
423wxPipeInputStream::wxPipeInputStream(HANDLE hInput)
424{
425 m_hInput = hInput;
426}
427
428wxPipeInputStream::~wxPipeInputStream()
429{
430 if ( m_hInput != INVALID_HANDLE_VALUE )
431 ::CloseHandle(m_hInput);
432}
433
434bool wxPipeInputStream::CanRead() const
435{
436 // we can read if there's something in the put back buffer
437 // even pipe is closed
438 if ( m_wbacksize > m_wbackcur )
439 return true;
440
441 wxPipeInputStream * const self = wxConstCast(this, wxPipeInputStream);
442
443 if ( !IsOpened() )
444 {
445 // set back to mark Eof as it may have been unset by Ungetch()
446 self->m_lasterror = wxSTREAM_EOF;
447 return false;
448 }
449
450 DWORD nAvailable;
451
452 // function name is misleading, it works with anon pipes as well
453 DWORD rc = ::PeekNamedPipe
454 (
455 m_hInput, // handle
456 NULL, 0, // ptr to buffer and its size
457 NULL, // [out] bytes read
458 &nAvailable, // [out] bytes available
459 NULL // [out] bytes left
460 );
461
462 if ( !rc )
463 {
464 if ( ::GetLastError() != ERROR_BROKEN_PIPE )
465 {
466 // unexpected error
467 wxLogLastError(_T("PeekNamedPipe"));
468 }
469
470 // don't try to continue reading from a pipe if an error occurred or if
471 // it had been closed
472 ::CloseHandle(m_hInput);
473
474 self->m_hInput = INVALID_HANDLE_VALUE;
475 self->m_lasterror = wxSTREAM_EOF;
476
477 nAvailable = 0;
478 }
479
480 return nAvailable != 0;
481}
482
483size_t wxPipeInputStream::OnSysRead(void *buffer, size_t len)
484{
485 if ( !IsOpened() )
486 {
487 m_lasterror = wxSTREAM_EOF;
488
489 return 0;
490 }
491
492 DWORD bytesRead;
493 if ( !::ReadFile(m_hInput, buffer, len, &bytesRead, NULL) )
494 {
495 m_lasterror = ::GetLastError() == ERROR_BROKEN_PIPE
496 ? wxSTREAM_EOF
497 : wxSTREAM_READ_ERROR;
498 }
499
500 // bytesRead is set to 0, as desired, if an error occurred
501 return bytesRead;
502}
503
504// ----------------------------------------------------------------------------
505// wxPipeOutputStream
506// ----------------------------------------------------------------------------
507
508wxPipeOutputStream::wxPipeOutputStream(HANDLE hOutput)
509{
510 m_hOutput = hOutput;
511
512 // unblock the pipe to prevent deadlocks when we're writing to the pipe
513 // from which the child process can't read because it is writing in its own
514 // end of it
515 DWORD mode = PIPE_READMODE_BYTE | PIPE_NOWAIT;
516 if ( !::SetNamedPipeHandleState
517 (
518 m_hOutput,
519 &mode,
520 NULL, // collection count (we don't set it)
521 NULL // timeout (we don't set it neither)
522 ) )
523 {
524 wxLogLastError(_T("SetNamedPipeHandleState(PIPE_NOWAIT)"));
525 }
526}
527
528bool wxPipeOutputStream::Close()
529{
530 return ::CloseHandle(m_hOutput) != 0;
531}
532
533
534size_t wxPipeOutputStream::OnSysWrite(const void *buffer, size_t len)
535{
536 m_lasterror = wxSTREAM_NO_ERROR;
537
538 DWORD totalWritten = 0;
539 while ( len > 0 )
540 {
541 DWORD chunkWritten;
542 if ( !::WriteFile(m_hOutput, buffer, len, &chunkWritten, NULL) )
543 {
544 m_lasterror = ::GetLastError() == ERROR_BROKEN_PIPE
545 ? wxSTREAM_EOF
546 : wxSTREAM_WRITE_ERROR;
547 break;
548 }
549
550 if ( !chunkWritten )
551 break;
552
553 buffer = (char *)buffer + chunkWritten;
554 totalWritten += chunkWritten;
555 len -= chunkWritten;
556 }
557
558 return totalWritten;
559}
560
561#endif // wxUSE_STREAMS
562
563// ============================================================================
564// wxExecute functions family
565// ============================================================================
566
567#if wxUSE_IPC
568
569// connect to the given server via DDE and ask it to execute the command
570bool
571wxExecuteDDE(const wxString& ddeServer,
572 const wxString& ddeTopic,
573 const wxString& ddeCommand)
574{
575 bool ok wxDUMMY_INITIALIZE(false);
576
577 wxDDEClient client;
578 wxConnectionBase *
579 conn = client.MakeConnection(wxEmptyString, ddeServer, ddeTopic);
580 if ( !conn )
581 {
582 ok = false;
583 }
584 else // connected to DDE server
585 {
586 // the added complication here is that although most programs use
587 // XTYP_EXECUTE for their DDE API, some important ones -- like Word
588 // and other MS stuff - use XTYP_REQUEST!
589 //
590 // moreover, anotheri mportant program (IE) understands both but
591 // returns an error from Execute() so we must try Request() first
592 // to avoid doing it twice
593 {
594 // we're prepared for this one to fail, so don't show errors
595 wxLogNull noErrors;
596
597 ok = conn->Request(ddeCommand) != NULL;
598 }
599
600 if ( !ok )
601 {
602 // now try execute -- but show the errors
603 ok = conn->Execute(ddeCommand);
604 }
605 }
606
607 return ok;
608}
609
610#endif // wxUSE_IPC
611
612long wxExecute(const wxString& cmd, int flags, wxProcess *handler)
613{
614 wxCHECK_MSG( !cmd.empty(), 0, wxT("empty command in wxExecute") );
615
616#if wxUSE_THREADS
617 // for many reasons, the code below breaks down if it's called from another
618 // thread -- this could be fixed, but as Unix versions don't support this
619 // neither I don't want to waste time on this now
620 wxASSERT_MSG( wxThread::IsMain(),
621 _T("wxExecute() can be called only from the main thread") );
622#endif // wxUSE_THREADS
623
624 wxString command;
625
626#if wxUSE_IPC
627 // DDE hack: this is really not pretty, but we need to allow this for
628 // transparent handling of DDE servers in wxMimeTypesManager. Usually it
629 // returns the command which should be run to view/open/... a file of the
630 // given type. Sometimes, however, this command just launches the server
631 // and an additional DDE request must be made to really open the file. To
632 // keep all this well hidden from the application, we allow a special form
633 // of command: WX_DDE#<command>#DDE_SERVER#DDE_TOPIC#DDE_COMMAND in which
634 // case we execute just <command> and process the rest below
635 wxString ddeServer, ddeTopic, ddeCommand;
636 static const size_t lenDdePrefix = 7; // strlen("WX_DDE:")
637 if ( cmd.Left(lenDdePrefix) == _T("WX_DDE#") )
638 {
639 // speed up the concatenations below
640 ddeServer.reserve(256);
641 ddeTopic.reserve(256);
642 ddeCommand.reserve(256);
643
644 const wxChar *p = cmd.c_str() + 7;
645 while ( *p && *p != _T('#') )
646 {
647 command += *p++;
648 }
649
650 if ( *p )
651 {
652 // skip '#'
653 p++;
654 }
655 else
656 {
657 wxFAIL_MSG(_T("invalid WX_DDE command in wxExecute"));
658 }
659
660 while ( *p && *p != _T('#') )
661 {
662 ddeServer += *p++;
663 }
664
665 if ( *p )
666 {
667 // skip '#'
668 p++;
669 }
670 else
671 {
672 wxFAIL_MSG(_T("invalid WX_DDE command in wxExecute"));
673 }
674
675 while ( *p && *p != _T('#') )
676 {
677 ddeTopic += *p++;
678 }
679
680 if ( *p )
681 {
682 // skip '#'
683 p++;
684 }
685 else
686 {
687 wxFAIL_MSG(_T("invalid WX_DDE command in wxExecute"));
688 }
689
690 while ( *p )
691 {
692 ddeCommand += *p++;
693 }
694
695 // if we want to just launch the program and not wait for its
696 // termination, try to execute DDE command right now, it can succeed if
697 // the process is already running - but as it fails if it's not
698 // running, suppress any errors it might generate
699 if ( !(flags & wxEXEC_SYNC) )
700 {
701 wxLogNull noErrors;
702 if ( wxExecuteDDE(ddeServer, ddeTopic, ddeCommand) )
703 {
704 // a dummy PID - this is a hack, of course, but it's well worth
705 // it as we don't open a new server each time we're called
706 // which would be quite bad
707 return -1;
708 }
709 }
710 }
711 else
712#endif // wxUSE_IPC
713 {
714 // no DDE
715 command = cmd;
716 }
717
718 // the IO redirection is only supported with wxUSE_STREAMS
719 BOOL redirect = FALSE;
720
721#if wxUSE_STREAMS && !defined(__WXWINCE__)
722 wxPipe pipeIn, pipeOut, pipeErr;
723
724 // we'll save here the copy of pipeIn[Write]
725 HANDLE hpipeStdinWrite = INVALID_HANDLE_VALUE;
726
727 // open the pipes to which child process IO will be redirected if needed
728 if ( handler && handler->IsRedirected() )
729 {
730 // create pipes for redirecting stdin, stdout and stderr
731 if ( !pipeIn.Create() || !pipeOut.Create() || !pipeErr.Create() )
732 {
733 wxLogSysError(_("Failed to redirect the child process IO"));
734
735 // indicate failure: we need to return different error code
736 // depending on the sync flag
737 return flags & wxEXEC_SYNC ? -1 : 0;
738 }
739
740 redirect = TRUE;
741 }
742#endif // wxUSE_STREAMS
743
744 // create the process
745 STARTUPINFO si;
746 wxZeroMemory(si);
747 si.cb = sizeof(si);
748
749#if wxUSE_STREAMS && !defined(__WXWINCE__)
750 if ( redirect )
751 {
752 si.dwFlags = STARTF_USESTDHANDLES;
753
754 si.hStdInput = pipeIn[wxPipe::Read];
755 si.hStdOutput = pipeOut[wxPipe::Write];
756 si.hStdError = pipeErr[wxPipe::Write];
757
758 // when the std IO is redirected, we don't show the (console) process
759 // window by default, but this can be overridden by the caller by
760 // specifying wxEXEC_NOHIDE flag
761 if ( !(flags & wxEXEC_NOHIDE) )
762 {
763 si.dwFlags |= STARTF_USESHOWWINDOW;
764 si.wShowWindow = SW_HIDE;
765 }
766
767 // we must duplicate the handle to the write side of stdin pipe to make
768 // it non inheritable: indeed, we must close the writing end of pipeIn
769 // before launching the child process as otherwise this handle will be
770 // inherited by the child which will never close it and so the pipe
771 // will never be closed and the child will be left stuck in ReadFile()
772 HANDLE pipeInWrite = pipeIn.Detach(wxPipe::Write);
773 if ( !::DuplicateHandle
774 (
775 ::GetCurrentProcess(),
776 pipeInWrite,
777 ::GetCurrentProcess(),
778 &hpipeStdinWrite,
779 0, // desired access: unused here
780 FALSE, // not inherited
781 DUPLICATE_SAME_ACCESS // same access as for src handle
782 ) )
783 {
784 wxLogLastError(_T("DuplicateHandle"));
785 }
786
787 ::CloseHandle(pipeInWrite);
788 }
789#endif // wxUSE_STREAMS
790
791 PROCESS_INFORMATION pi;
792 DWORD dwFlags = CREATE_SUSPENDED;
793
794#ifndef __WXWINCE__
795 dwFlags |= CREATE_DEFAULT_ERROR_MODE ;
796#else
797 // we are assuming commands without spaces for now
798 wxString moduleName = command.BeforeFirst(wxT(' '));
799 wxString arguments = command.AfterFirst(wxT(' '));
800#endif
801
802 bool ok = ::CreateProcess
803 (
804 // WinCE requires appname to be non null
805 // Win32 allows for null
806#ifdef __WXWINCE__
807 (wxChar *)
808 moduleName.wx_str(),// application name
809 (wxChar *)
810 arguments.wx_str(), // arguments
811#else
812 NULL, // application name (use only cmd line)
813 (wxChar *)
814 command.wx_str(), // full command line
815#endif
816 NULL, // security attributes: defaults for both
817 NULL, // the process and its main thread
818 redirect, // inherit handles if we use pipes
819 dwFlags, // process creation flags
820 NULL, // environment (use the same)
821 NULL, // current directory (use the same)
822 &si, // startup info (unused here)
823 &pi // process info
824 ) != 0;
825
826#if wxUSE_STREAMS && !defined(__WXWINCE__)
827 // we can close the pipe ends used by child anyhow
828 if ( redirect )
829 {
830 ::CloseHandle(pipeIn.Detach(wxPipe::Read));
831 ::CloseHandle(pipeOut.Detach(wxPipe::Write));
832 ::CloseHandle(pipeErr.Detach(wxPipe::Write));
833 }
834#endif // wxUSE_STREAMS
835
836 if ( !ok )
837 {
838#if wxUSE_STREAMS && !defined(__WXWINCE__)
839 // close the other handles too
840 if ( redirect )
841 {
842 ::CloseHandle(pipeOut.Detach(wxPipe::Read));
843 ::CloseHandle(pipeErr.Detach(wxPipe::Read));
844 }
845#endif // wxUSE_STREAMS
846
847 wxLogSysError(_("Execution of command '%s' failed"), command.c_str());
848
849 return flags & wxEXEC_SYNC ? -1 : 0;
850 }
851
852#if wxUSE_STREAMS && !defined(__WXWINCE__)
853 // the input buffer bufOut is connected to stdout, this is why it is
854 // called bufOut and not bufIn
855 wxStreamTempInputBuffer bufOut,
856 bufErr;
857
858 if ( redirect )
859 {
860 // We can now initialize the wxStreams
861 wxPipeInputStream *
862 outStream = new wxPipeInputStream(pipeOut.Detach(wxPipe::Read));
863 wxPipeInputStream *
864 errStream = new wxPipeInputStream(pipeErr.Detach(wxPipe::Read));
865 wxPipeOutputStream *
866 inStream = new wxPipeOutputStream(hpipeStdinWrite);
867
868 handler->SetPipeStreams(outStream, inStream, errStream);
869
870 bufOut.Init(outStream);
871 bufErr.Init(errStream);
872 }
873#endif // wxUSE_STREAMS
874
875 // create a hidden window to receive notification about process
876 // termination
877 HWND hwnd = wxCreateHiddenWindow
878 (
879 &gs_classForHiddenWindow,
880 wxMSWEXEC_WNDCLASSNAME,
881 (WNDPROC)wxExecuteWindowCbk
882 );
883
884 wxASSERT_MSG( hwnd, wxT("can't create a hidden window for wxExecute") );
885
886 // Alloc data
887 wxExecuteData *data = new wxExecuteData;
888 data->hProcess = pi.hProcess;
889 data->dwProcessId = pi.dwProcessId;
890 data->hWnd = hwnd;
891 data->state = (flags & wxEXEC_SYNC) != 0;
892 if ( flags & wxEXEC_SYNC )
893 {
894 // handler may be !NULL for capturing program output, but we don't use
895 // it wxExecuteData struct in this case
896 data->handler = NULL;
897 }
898 else
899 {
900 // may be NULL or not
901 data->handler = handler;
902 }
903
904 DWORD tid;
905 HANDLE hThread = ::CreateThread(NULL,
906 0,
907 wxExecuteThread,
908 (void *)data,
909 0,
910 &tid);
911
912 // resume process we created now - whether the thread creation succeeded or
913 // not
914 if ( ::ResumeThread(pi.hThread) == (DWORD)-1 )
915 {
916 // ignore it - what can we do?
917 wxLogLastError(wxT("ResumeThread in wxExecute"));
918 }
919
920 // close unneeded handle
921 if ( !::CloseHandle(pi.hThread) )
922 wxLogLastError(wxT("CloseHandle(hThread)"));
923
924 if ( !hThread )
925 {
926 wxLogLastError(wxT("CreateThread in wxExecute"));
927
928 DestroyWindow(hwnd);
929 delete data;
930
931 // the process still started up successfully...
932 return pi.dwProcessId;
933 }
934
935 gs_asyncThreads.push_back(hThread);
936
937#if wxUSE_IPC && !defined(__WXWINCE__)
938 // second part of DDE hack: now establish the DDE conversation with the
939 // just launched process
940 if ( !ddeServer.empty() )
941 {
942 bool ok;
943
944 // give the process the time to init itself
945 //
946 // we use a very big timeout hoping that WaitForInputIdle() will return
947 // much sooner, but not INFINITE just in case the process hangs
948 // completely - like this we will regain control sooner or later
949 switch ( ::WaitForInputIdle(pi.hProcess, 10000 /* 10 seconds */) )
950 {
951 default:
952 wxFAIL_MSG( _T("unexpected WaitForInputIdle() return code") );
953 // fall through
954
955 case -1:
956 wxLogLastError(_T("WaitForInputIdle() in wxExecute"));
957
958 case WAIT_TIMEOUT:
959 wxLogDebug(_T("Timeout too small in WaitForInputIdle"));
960
961 ok = false;
962 break;
963
964 case 0:
965 // ok, process ready to accept DDE requests
966 ok = wxExecuteDDE(ddeServer, ddeTopic, ddeCommand);
967 }
968
969 if ( !ok )
970 {
971 wxLogDebug(_T("Failed to send DDE request to the process \"%s\"."),
972 cmd.c_str());
973 }
974 }
975#endif // wxUSE_IPC
976
977 if ( !(flags & wxEXEC_SYNC) )
978 {
979 // clean up will be done when the process terminates
980
981 // return the pid
982 return pi.dwProcessId;
983 }
984
985 wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
986 wxCHECK_MSG( traits, -1, _T("no wxAppTraits in wxExecute()?") );
987
988 void *cookie = NULL;
989 if ( !(flags & wxEXEC_NODISABLE) )
990 {
991 // disable all app windows while waiting for the child process to finish
992 cookie = traits->BeforeChildWaitLoop();
993 }
994
995 // wait until the child process terminates
996 while ( data->state )
997 {
998#if wxUSE_STREAMS && !defined(__WXWINCE__)
999 if ( !bufOut.Update() && !bufErr.Update() )
1000#endif // wxUSE_STREAMS
1001 {
1002 // don't eat 100% of the CPU -- ugly but anything else requires
1003 // real async IO which we don't have for the moment
1004 ::Sleep(50);
1005 }
1006
1007 // we must process messages or we'd never get wxWM_PROC_TERMINATED
1008 traits->AlwaysYield();
1009 }
1010
1011 if ( !(flags & wxEXEC_NODISABLE) )
1012 {
1013 // reenable disabled windows back
1014 traits->AfterChildWaitLoop(cookie);
1015 }
1016
1017 DWORD dwExitCode = data->dwExitCode;
1018 delete data;
1019
1020 // return the exit code
1021 return dwExitCode;
1022}
1023
1024template <typename CharType>
1025long wxExecuteImpl(CharType **argv, int flags, wxProcess *handler)
1026{
1027 wxString command;
1028 command.reserve(1024);
1029
1030 wxString arg;
1031 for ( ;; )
1032 {
1033 arg = *argv++;
1034
1035 bool quote;
1036 if ( arg.empty() )
1037 {
1038 // we need to quote empty arguments, otherwise they'd just
1039 // disappear
1040 quote = true;
1041 }
1042 else // non-empty
1043 {
1044 // escape any quotes present in the string to avoid interfering
1045 // with the command line parsing in the child process
1046 arg.Replace("\"", "\\\"", true /* replace all */);
1047
1048 // and quote any arguments containing the spaces to prevent them from
1049 // being broken down
1050 quote = arg.find_first_of(" \t") != wxString::npos;
1051 }
1052
1053 if ( quote )
1054 command += '\"' + arg + '\"';
1055 else
1056 command += arg;
1057
1058 if ( !*argv )
1059 break;
1060
1061 command += ' ';
1062 }
1063
1064 return wxExecute(command, flags, handler);
1065}
1066
1067long wxExecute(char **argv, int flags, wxProcess *handler)
1068{
1069 return wxExecuteImpl(argv, flags, handler);
1070}
1071
1072#if wxUSE_UNICODE
1073
1074long wxExecute(wchar_t **argv, int flags, wxProcess *handler)
1075{
1076 return wxExecuteImpl(argv, flags, handler);
1077}
1078
1079#endif // wxUSE_UNICODE