X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/039f62f43136b06b15444a7437b6c030efeaf76b..a06066343d670807825adcafebfa4fb8cfff5521:/src/msw/utilsexc.cpp diff --git a/src/msw/utilsexc.cpp b/src/msw/utilsexc.cpp index 12a78c001a..453b7efc5d 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 @@ -120,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 // ============================================================================ @@ -289,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(); @@ -314,6 +402,55 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler) return result; #else // 1 + HANDLE hpipeRead[2]; + HANDLE hpipeWrite[2]; + HANDLE hStdIn = INVALID_HANDLE_VALUE; + HANDLE hStdOut = INVALID_HANDLE_VALUE; + + // we need to inherit handles in the child process if we want to redirect + // its IO + BOOL inheritHandles = FALSE; + + // open the pipes to which child process IO will be redirected if needed + if ( handler && handler->IsRedirected() ) + { + SECURITY_ATTRIBUTES security; + + security.nLength = sizeof(security); + security.lpSecurityDescriptor = NULL; + security.bInheritHandle = TRUE; + + if ( !::CreatePipe(&hpipeRead[0], &hpipeRead[1], &security, 0) ) + { + wxLogSysError(_("Can't create the inter-process read pipe")); + + return 0; + } + + if ( !::CreatePipe(&hpipeWrite[0], &hpipeWrite[1], &security, 0) ) + { + ::CloseHandle(hpipeRead[0]); + ::CloseHandle(hpipeRead[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 + hStdIn = ::GetStdHandle(STD_INPUT_HANDLE); + hStdOut = ::GetStdHandle(STD_OUTPUT_HANDLE); + + if ( !::SetStdHandle(STD_INPUT_HANDLE, hpipeRead[0]) || + !::SetStdHandle(STD_OUTPUT_HANDLE, hpipeWrite[1]) ) + { + wxLogDebug(_T("Failed to change stdin/out handles")); + } + + inheritHandles = TRUE; + } + // create the process STARTUPINFO si; wxZeroMemory(si); @@ -327,7 +464,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) @@ -336,11 +473,39 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler) &pi // process info ) == 0 ) { + if ( inheritHandles ) + { + ::CloseHandle(hpipeWrite[0]); + ::CloseHandle(hpipeWrite[1]); + ::CloseHandle(hpipeRead[0]); + ::CloseHandle(hpipeRead[1]); + } + wxLogSysError(_("Execution of command '%s' failed"), command.c_str()); return 0; } + // Restore the old stdio handles + if ( inheritHandles ) + { + if ( !::SetStdHandle(STD_INPUT_HANDLE, hStdIn) || + !::SetStdHandle(STD_OUTPUT_HANDLE, hStdOut) ) + { + wxLogDebug(_T("Failed to restore old stdin/out handles")); + } + + // they're still opened in child process + ::CloseHandle(hpipeWrite[1]); + ::CloseHandle(hpipeRead[0]); + + // We can now initialize the wxStreams + wxInputStream *inStream = new wxPipeInputStream(hpipeWrite[0]); + wxOutputStream *outStream = new wxPipeOutputStream(hpipeRead[1]); + + handler->SetPipeStreams(inStream, outStream); + } + // register the class for the hidden window used for the notifications if ( !gs_classForHiddenWindow ) { @@ -374,8 +539,8 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler) data->state = sync; if ( sync ) { - wxASSERT_MSG( !handler, wxT("wxProcess param ignored for sync execution") ); - + // handler may be !NULL for capturing program output, but we don't use + // it wxExecuteData struct in this case data->handler = NULL; } else @@ -441,16 +606,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;