X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/3bce6687f47dfa5fb8d4bab92702a5b5b1eb3485..e52d9c784ed95b099017cca9301b325085c7f4d1:/src/msw/utilsexc.cpp diff --git a/src/msw/utilsexc.cpp b/src/msw/utilsexc.cpp index e550fca890..58b26f2c07 100644 --- a/src/msw/utilsexc.cpp +++ b/src/msw/utilsexc.cpp @@ -32,10 +32,12 @@ #include "wx/utils.h" #include "wx/app.h" #include "wx/intl.h" + #include "wx/log.h" + #if wxUSE_GUI // See 'dirty hack' below. + #include "wx/frame.h" + #endif #endif -#include "wx/log.h" - #ifdef __WIN32__ #include "wx/stream.h" #include "wx/process.h" @@ -260,7 +262,7 @@ private: // thread function for the thread monitoring the process termination static DWORD __stdcall wxExecuteThread(void *arg) { - wxExecuteData *data = (wxExecuteData*)arg; + wxExecuteData * const data = (wxExecuteData *)arg; if ( ::WaitForSingleObject(data->hProcess, INFINITE) != WAIT_OBJECT_0 ) { @@ -291,7 +293,7 @@ LRESULT APIENTRY _EXPORT wxExecuteWindowCbk(HWND hWnd, UINT message, { DestroyWindow(hWnd); // we don't need it any more - wxExecuteData *data = (wxExecuteData *)lParam; + wxExecuteData * const data = (wxExecuteData *)lParam; if ( data->handler ) { data->handler->OnTerminate((int)data->dwProcessId, @@ -314,7 +316,7 @@ LRESULT APIENTRY _EXPORT wxExecuteWindowCbk(HWND hWnd, UINT message, } else { - return DefWindowProc(hWnd, message, wParam, lParam); + return ::DefWindowProc(hWnd, message, wParam, lParam); } } @@ -845,12 +847,44 @@ long wxExecute(const wxString& cmd, int flags, wxProcess *handler) return pi.dwProcessId; } - // waiting until command executed (disable everything while doing it) + // disable all app windows while waiting for the child process to finish #if wxUSE_GUI + + /* + We use a dirty hack here to disable all application windows (which we + must do because otherwise the calls to wxYield() could lead to some very + unexpected reentrancies in the users code) but to avoid losing + focus/activation entirely when the child process terminates which would + happen if we simply disabled everything using wxWindowDisabler. Indeed, + remember that Windows will never activate a disabled window and when the + last childs window is closed and Windows looks for a window to activate + all our windows are still disabled. There is no way to enable them in + time because we don't know when the childs windows are going to be + closed, so the solution we use here is to keep one special tiny frame + enabled all the time. Then when the child terminates it will get + activated and when we close it below -- after reenabling all the other + windows! -- the previously active window becomes activated again and + everything is ok. + */ + wxWindow *winActive; { wxBusyCursor bc; + // first disable all existing windows wxWindowDisabler wd; + + // then create an "invisible" frame: it has minimal size, is positioned + // (hopefully) outside the screen and doesn't appear on the taskbar + winActive = new wxFrame + ( + wxTheApp->GetTopWindow(), + -1, + _T(""), + wxPoint(32600, 32600), + wxSize(1, 1), + wxDEFAULT_FRAME_STYLE | wxFRAME_NO_TASKBAR + ); + winActive->Show(); #endif // wxUSE_GUI // wait until the child process terminates @@ -865,12 +899,24 @@ long wxExecute(const wxString& cmd, int flags, wxProcess *handler) // real async IO which we don't have for the moment ::Sleep(50); +#if wxUSE_GUI // repaint the GUI wxYield(); +#else // !GUI + // dispatch the messages to the hidden window so that it could + // process the wxWM_PROC_TERMINATED notification + MSG msg; + ::PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE); +#endif // GUI/!GUI } #if wxUSE_GUI } + + // finally delete the dummy frame and, as wd has been already destroyed and + // the other windows reenabled, the activation is going to return to the + // window which had it before + winActive->Destroy(); #endif // wxUSE_GUI DWORD dwExitCode = data->dwExitCode;