X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/5bd3a2da9573f270564cd035e0cfbf6902cf8750..5c8fc7c1debd3d2a58c015132f2a3d9e3e26cd38:/src/msw/utilsexc.cpp diff --git a/src/msw/utilsexc.cpp b/src/msw/utilsexc.cpp index 6f2ee55757..4a5489086c 100644 --- a/src/msw/utilsexc.cpp +++ b/src/msw/utilsexc.cpp @@ -37,6 +37,7 @@ #include "wx/log.h" #ifdef __WIN32__ + #include "wx/stream.h" #include "wx/process.h" #endif @@ -74,7 +75,9 @@ #endif #include -#include "wx/dde.h" // for WX_DDE hack in wxExecute +#if wxUSE_IPC + #include "wx/dde.h" // for WX_DDE hack in wxExecute +#endif // wxUSE_IPC // ---------------------------------------------------------------------------- // constants @@ -118,6 +121,94 @@ public: bool state; // set to FALSE when the process finishes }; + +#ifdef __WIN32__ +// ---------------------------------------------------------------------------- +// wxPipeStreams +// ---------------------------------------------------------------------------- + +class wxPipeInputStream: public wxInputStream { +public: + wxPipeInputStream(HANDLE hInput); + ~wxPipeInputStream(); + +protected: + size_t OnSysRead(void *buffer, size_t len); + +protected: + HANDLE m_hInput; +}; + +class wxPipeOutputStream: public wxOutputStream { +public: + wxPipeOutputStream(HANDLE hOutput); + ~wxPipeOutputStream(); + +protected: + size_t OnSysWrite(const void *buffer, size_t len); + +protected: + HANDLE m_hOutput; +}; + +// ================== +// wxPipeInputStream +// ================== + +wxPipeInputStream::wxPipeInputStream(HANDLE hInput) +{ + m_hInput = hInput; +} + +wxPipeInputStream::~wxPipeInputStream() +{ + ::CloseHandle(m_hInput); +} + +size_t wxPipeInputStream::OnSysRead(void *buffer, size_t len) +{ + DWORD bytesRead; + + m_lasterror = wxSTREAM_NOERROR; + if (! ::ReadFile(m_hInput, buffer, len, &bytesRead, NULL) ) { + if (GetLastError() == ERROR_BROKEN_PIPE) + m_lasterror = wxSTREAM_EOF; + else + m_lasterror = wxSTREAM_READ_ERROR; + } + return bytesRead; +} + +// ================== +// wxPipeOutputStream +// ================== + +wxPipeOutputStream::wxPipeOutputStream(HANDLE hOutput) +{ + m_hOutput = hOutput; +} + +wxPipeOutputStream::~wxPipeOutputStream() +{ + ::CloseHandle(m_hOutput); +} + +size_t wxPipeOutputStream::OnSysWrite(const void *buffer, size_t len) +{ + DWORD bytesRead; + + m_lasterror = wxSTREAM_NOERROR; + if (! ::WriteFile(m_hOutput, buffer, len, &bytesRead, NULL) ) { + if (GetLastError() == ERROR_BROKEN_PIPE) + m_lasterror = wxSTREAM_EOF; + else + m_lasterror = wxSTREAM_READ_ERROR; + } + return bytesRead; +} + +#endif // __WIN32__ + // ============================================================================ // implementation // ============================================================================ @@ -177,12 +268,14 @@ LRESULT APIENTRY _EXPORT wxExecuteWindowCbk(HWND hWnd, UINT message, return DefWindowProc(hWnd, message, wParam, lParam); } } -#endif +#endif // Win32 long wxExecute(const wxString& cmd, bool sync, wxProcess *handler) { wxCHECK_MSG( !!cmd, 0, wxT("empty command in wxExecute") ); + wxString command; +#if wxUSE_IPC // DDE hack: this is really not pretty, but we need to allow this for // transparent handling of DDE servers in wxMimeTypesManager. Usually it // returns the command which should be run to view/open/... a file of the @@ -191,7 +284,7 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler) // keep all this well hidden from the application, we allow a special form // of command: WX_DDE::DDE_SERVER:DDE_TOPIC:DDE_COMMAND in which // case we execute just and process the rest below - wxString command, ddeServer, ddeTopic, ddeCommand; + wxString ddeServer, ddeTopic, ddeCommand; static const size_t lenDdePrefix = 7; // strlen("WX_DDE:") if ( cmd.Left(lenDdePrefix) == _T("WX_DDE#") ) { @@ -247,6 +340,7 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler) } } else +#endif // wxUSE_IPC { // no DDE command = cmd; @@ -284,7 +378,6 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler) // only reached for space not inside quotes break; } - wxString commandArgs = pc; wxWindow *winTop = wxTheApp->GetTopWindow(); @@ -309,6 +402,50 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler) return result; #else // 1 + HANDLE h_readPipe[2]; + HANDLE h_writePipe[2]; + HANDLE h_oldreadPipe; + HANDLE h_oldwritePipe; + BOOL inheritHandles; + + // open the pipes to which child process IO will be redirected if needed + inheritHandles = FALSE; + if ( handler && handler->IsRedirected() ) + { + SECURITY_ATTRIBUTES security; + + security.nLength = sizeof(security); + security.lpSecurityDescriptor = NULL; + security.bInheritHandle = TRUE; + + if (! ::CreatePipe(&h_readPipe[0], &h_readPipe[1], &security, 0) ) + { + wxLogSysError(_("Can't create the inter-process read pipe")); + + return 0; + } + + if (! ::CreatePipe(&h_writePipe[0], &h_writePipe[1], &security, 0) ) + { + ::CloseHandle(h_readPipe[0]); + ::CloseHandle(h_readPipe[1]); + + wxLogSysError(_("Can't create the inter-process write pipe")); + + return 0; + } + + // We need to save the old stdio handles to restore them after the call + // to CreateProcess + h_oldreadPipe = GetStdHandle(STD_INPUT_HANDLE); + h_oldwritePipe = GetStdHandle(STD_OUTPUT_HANDLE); + + SetStdHandle(STD_INPUT_HANDLE, h_readPipe[0]); + SetStdHandle(STD_OUTPUT_HANDLE, h_writePipe[1]); + + inheritHandles = TRUE; + } + // create the process STARTUPINFO si; wxZeroMemory(si); @@ -322,7 +459,7 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler) (wxChar *)command.c_str(), // full command line NULL, // security attributes: defaults for both NULL, // the process and its main thread - FALSE, // don't inherit handles + inheritHandles, // inherit handles if we need pipes CREATE_DEFAULT_ERROR_MODE | CREATE_SUSPENDED, // flags NULL, // environment (use the same) @@ -331,11 +468,33 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler) &pi // process info ) == 0 ) { + if ( inheritHandles ) + { + ::CloseHandle(h_writePipe[0]); + ::CloseHandle(h_writePipe[1]); + ::CloseHandle(h_readPipe[0]); + ::CloseHandle(h_readPipe[1]); + } + wxLogSysError(_("Execution of command '%s' failed"), command.c_str()); return 0; } + // Restore the old stdio handles + if (inheritHandles) { + SetStdHandle(STD_INPUT_HANDLE, h_oldreadPipe); + SetStdHandle(STD_OUTPUT_HANDLE, h_oldwritePipe); + + ::CloseHandle(h_writePipe[1]); + ::CloseHandle(h_readPipe[0]); + // We can now initialize the wxStreams + wxInputStream *processOutput = new wxPipeInputStream(h_writePipe[0]); + wxOutputStream *processInput = new wxPipeOutputStream(h_readPipe[1]); + + handler->SetPipeStreams(processOutput, processInput); + } + // register the class for the hidden window used for the notifications if ( !gs_classForHiddenWindow ) { @@ -410,6 +569,7 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler) return pi.dwProcessId; } +#if wxUSE_IPC // second part of DDE hack: now establish the DDE conversation with the // just launched process if ( !!ddeServer ) @@ -423,6 +583,7 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler) wxLogError(_("Couldn't launch DDE server '%s'."), command.c_str()); } } +#endif // wxUSE_IPC if ( !sync ) { @@ -434,16 +595,17 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler) // waiting until command executed (disable everything while doing it) #if wxUSE_GUI - wxBeginBusyCursor(); - wxEnableTopLevelWindows(FALSE); + { + wxBusyCursor bc; + + wxWindowDisabler wd; #endif // wxUSE_GUI while ( data->state ) wxYield(); #if wxUSE_GUI - wxEnableTopLevelWindows(TRUE); - wxEndBusyCursor(); + } #endif // wxUSE_GUI DWORD dwExitCode = data->dwExitCode;