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 84extern "C" WXDLLIMPEXP_BASE HWND 85wxCreateHiddenWindow(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 101static const wxChar *wxMSWEXEC_WNDCLASSNAME = wxT("_wxExecute_Internal_Class"); 102static const wxChar *gs_classForHiddenWindow = NULL; 103 104// ---------------------------------------------------------------------------- 105// private types 106// ---------------------------------------------------------------------------- 107 108// structure describing the process we're being waiting for 109struct wxExecuteData 110{ 111public: 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 128class wxExecuteModule : public wxModule 129{ 130public: 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 145private: 146 DECLARE_DYNAMIC_CLASS(wxExecuteModule) 147}; 148 149#if wxUSE_STREAMS && !defined(__WXWINCE__) 150 151// ---------------------------------------------------------------------------- 152// wxPipeStreams 153// ---------------------------------------------------------------------------- 154 155class wxPipeInputStream: public wxInputStream 156{ 157public: 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 167protected: 168 size_t OnSysRead(void *buffer, size_t len); 169 170protected: 171 HANDLE m_hInput; 172 173 DECLARE_NO_COPY_CLASS(wxPipeInputStream) 174}; 175 176class wxPipeOutputStream: public wxOutputStream 177{ 178public: 179 wxPipeOutputStream(HANDLE hOutput); 180 virtual ~wxPipeOutputStream() { Close(); } 181 bool Close(); 182 183protected: 184 size_t OnSysWrite(const void *buffer, size_t len); 185 186protected: 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 200class wxPipe 201{ 202public: 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 265private: 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 280static 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 306LRESULT 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 350wxPipeInputStream::wxPipeInputStream(HANDLE hInput) 351{ 352 m_hInput = hInput; 353} 354 355wxPipeInputStream::~wxPipeInputStream() 356{ 357 if ( m_hInput != INVALID_HANDLE_VALUE ) 358 ::CloseHandle(m_hInput); 359} 360 361bool 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 410size_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 435wxPipeOutputStream::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 455bool wxPipeOutputStream::Close() 456{ 457 return ::CloseHandle(m_hOutput) != 0; 458} 459 460 461size_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 497bool 498wxExecuteDDE(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 539long 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 951long 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} 1004