summaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorMike Kaganski <mike.kaganski@collabora.com>2018-10-28 19:14:28 +0300
committerAndras Timar <andras.timar@collabora.com>2019-04-04 09:34:22 +0200
commite132f392594037ec9524c2da5304138405158744 (patch)
treea3bf413f272fc6509df5f9ee003512a209d1b3fa /shell
parent74181e6b89e16eeaec9f48024775c10835c36f1b (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')
-rw-r--r--shell/source/win32/SysShExec.cxx49
1 files changed, 35 insertions, 14 deletions
diff --git a/shell/source/win32/SysShExec.cxx b/shell/source/win32/SysShExec.cxx
index 55b20e62fc46..05daf97586d8 100644
--- a/shell/source/win32/SysShExec.cxx
+++ b/shell/source/win32/SysShExec.cxx
@@ -245,6 +245,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
@@ -301,9 +329,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 );
@@ -327,20 +356,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));
}
}