/[pcsx2_0.9.7]/branch/r3113_0.9.7_beta/3rdparty/wxWidgets/src/msw/utilsexc.cpp
ViewVC logotype

Contents of /branch/r3113_0.9.7_beta/3rdparty/wxWidgets/src/msw/utilsexc.cpp

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.22