summaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorMike Kaganski <mike.kaganski@collabora.com>2018-10-28 19:14:28 +0300
committerMike Kaganski <mike.kaganski@collabora.com>2018-10-28 20:27:52 +0100
commitde26ed225eb03ab36efed592774e460b21e695fa (patch)
tree8af766ee723d994b8a4412584229b2db987292b5 /shell
parenta21ec77601e2dd15a2281727b827db9310cece6d (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 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));
}
}