diff options
author | Mike Kaganski <mike.kaganski@collabora.com> | 2018-10-28 19:14:28 +0300 |
---|---|---|
committer | Mike Kaganski <mike.kaganski@collabora.com> | 2018-10-28 20:27:52 +0100 |
commit | de26ed225eb03ab36efed592774e460b21e695fa (patch) | |
tree | 8af766ee723d994b8a4412584229b2db987292b5 /shell/source | |
parent | a21ec77601e2dd15a2281727b827db9310cece6d (diff) |
tdf#120703 PVS: V547 Fix activation of launched process' window
V547 Expression 'procHandle != nullptr' is always false.
The code was nonsensical overall. First, the launched process handle
was never returned by ShellExecuteExW, because SEE_MASK_NOCLOSEPROCESS
wasn't used, so GetProcessId couldn't succeed. Then, nullptr window
handle was passed to GetWindowThreadProcessId, thus never returning a
meaningful result.
This reimplements this to find the launched process' main window by
first waiting for process idle (up to 1-second delay is possible),
then enumerating all the top-level windows and checking their process.
Change-Id: I5fb4c04147b3f9414e27650a023f7844523c18bd
Reviewed-on: https://gerrit.libreoffice.org/62478
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Diffstat (limited to 'shell/source')
-rw-r--r-- | shell/source/win32/SysShExec.cxx | 49 |
1 files changed, 35 insertions, 14 deletions
diff --git a/shell/source/win32/SysShExec.cxx b/shell/source/win32/SysShExec.cxx index e9e5909991c5..11ca42005b10 100644 --- a/shell/source/win32/SysShExec.cxx +++ b/shell/source/win32/SysShExec.cxx @@ -240,6 +240,34 @@ CSysShExec::CSysShExec( const Reference< css::uno::XComponentContext >& xContext CoInitialize( nullptr ); } +namespace +{ +// This callback checks if the found window is the specified process's top-level window, +// and activates the first found such window. +BOOL CALLBACK FindAndActivateProcWnd(HWND hwnd, LPARAM lParam) +{ + if (!IsWindowVisible(hwnd)) + return TRUE; // continue enumeration + if (GetWindow(hwnd, GW_OWNER)) // not a top-level window + return TRUE; // continue enumeration + const DWORD nParamProcId = static_cast<DWORD>(lParam); + assert(nParamProcId != 0); + DWORD nWndProcId = 0; + (void)GetWindowThreadProcessId(hwnd, &nWndProcId); + if (nWndProcId != nParamProcId) + return TRUE; // continue enumeration + + // Found it! Bring it to front + if (IsIconic(hwnd)) + { + ShowWindow(hwnd, SW_RESTORE); + } + SetForegroundWindow(hwnd); + SetActiveWindow(hwnd); + return FALSE; // stop enumeration +} +} + void SAL_CALL CSysShExec::execute( const OUString& aCommand, const OUString& aParameter, sal_Int32 nFlags ) { // parameter checking @@ -296,9 +324,10 @@ void SAL_CALL CSysShExec::execute( const OUString& aCommand, const OUString& aPa sei.lpFile = o3tl::toW(preprocessed_command.getStr()); sei.lpParameters = o3tl::toW(aParameter.getStr()); sei.nShow = SW_SHOWNORMAL; + sei.fMask = SEE_MASK_NOCLOSEPROCESS; // we need sei.hProcess if (NO_SYSTEM_ERROR_MESSAGE & nFlags) - sei.fMask = SEE_MASK_FLAG_NO_UI; + sei.fMask |= SEE_MASK_FLAG_NO_UI; SetLastError( 0 ); @@ -322,20 +351,12 @@ void SAL_CALL CSysShExec::execute( const OUString& aCommand, const OUString& aPa else { // Get Permission make changes to the Window of the created Process - HWND procHandle = nullptr; - DWORD procId = GetProcessId(sei.hProcess); - AllowSetForegroundWindow(procId); - - // Get the handle of the created Window - DWORD check = 0; - GetWindowThreadProcessId(procHandle, &check); - SAL_WARN_IF(check != procId, "shell", "Could not get handle of process called by shell."); - - // Move created Window into the foreground - if(procHandle != nullptr) + const DWORD procId = GetProcessId(sei.hProcess); + if (procId != 0) { - SetForegroundWindow(procHandle); - SetActiveWindow(procHandle); + AllowSetForegroundWindow(procId); + WaitForInputIdle(sei.hProcess, 1000); // so that main window is created; imperfect + EnumWindows(FindAndActivateProcWnd, static_cast<LPARAM>(procId)); } } |