Kaydet (Commit) de26ed22 authored tarafından Mike Kaganski's avatar Mike Kaganski

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: 's avatarMike Kaganski <mike.kaganski@collabora.com>
üst a21ec776
......@@ -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));
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment