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>
This commit is contained in:
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user