How to get hWnd of window opened by ShellExecuteEx.. hProcess?
Asked Answered
I

1

9

This "simple" issue seems to be fraught with side issues.
eg. Does the new process open multiple windows; Does it have a splash screen?
Is there a simple way? (I'm starting a new instance of Notepad++)

...
std::tstring  tstrNotepad_exe = tstrProgramFiles + _T("\\Notepad++\\notepad++.exe");

SHELLEXECUTEINFO SEI={0};
sei.cbSize       = sizeof(SHELLEXECUTEINFO);
sei.fMask        = SEE_MASK_NOCLOSEPROCESS;
sei.hwnd         = hWndMe;  // This app's window handle
sei.lpVerb       = _T("open");
sei.lpFile       = tstrNotepad_exe.c_str();     
sei.lpParameters = _T(" -multiInst -noPlugins -nosession -notabbar ";   
sei.lpDirectory  = NULL;
sei.nShow        = SW_SHOW;
sei.hInstApp     = NULL;    
if( ShellExecuteEx(&sei) )
{ // I have sei.hProcess, but how best to utilize it from here?
}
...
Intern answered 16/7, 2010 at 22:54 Comment(0)
C
15

First use WaitForInputIdle to pause your program until the application has started and is waiting for user input (the main window should have been created by then), then use EnumWindows and GetWindowThreadProcessId to determine which windows in the system belong to the created process.

For example:

struct ProcessWindowsInfo
{
    DWORD ProcessID;
    std::vector<HWND> Windows;

    ProcessWindowsInfo( DWORD const AProcessID )
        : ProcessID( AProcessID )
    {
    }
};

BOOL __stdcall EnumProcessWindowsProc( HWND hwnd, LPARAM lParam )
{
    ProcessWindowsInfo *Info = reinterpret_cast<ProcessWindowsInfo*>( lParam );
    DWORD WindowProcessID;

    GetWindowThreadProcessId( hwnd, &WindowProcessID );

    if( WindowProcessID == Info->ProcessID )
        Info->Windows.push_back( hwnd );

    return true;
}

....

if( ShellExecuteEx(&sei) )
{
    WaitForInputIdle( sei.hProcess, INFINITE );

    ProcessWindowsInfo Info( GetProcessId( sei.hProcess ) );

    EnumWindows( (WNDENUMPROC)EnumProcessWindowsProc,
        reinterpret_cast<LPARAM>( &Info ) );

    // Use Info.Windows.....
}
Calculable answered 16/7, 2010 at 23:8 Comment(7)
Thanks Jon... So short interval polling is the way to go... that makes sense :)Intern
I'm working through your example now... and a PS to my previous comment: I just noticed in MSDN: WaitForInputIdle can be used at any time, not just during application startup. However, WaitForInputIdle waits only once for a process to become idle; subsequent WaitForInputIdle calls return immediately, whether the process is idle or busy. * It seems polling is not a good idea... I'll do a few tests.Intern
You should only need to use WaitForInputIdle when the process is created. From then on, just poll the EnumWindows call to get the updated window list.Calculable
Fantastic :) neat and sweet! ... (but I don't have enough points to mark it up, (yet).Intern
I used your code,and it works ok, but hProcess is always 0 after ShellExecuteEx finishes. What gives?Dragster
I know this is ancient, but @ john : your process must be started with the SEE_MASK_NOCLOSEPROCESS flagRosina
WaitForInputIdle doesn't do what you think it does. See WaitForInputIdle should really be called WaitForProcessStartupComplete and WaitForInputIdle waits for any thread, which might not be the thread you care about. Use WinEvents instead to monitor window creation.Jampacked

© 2022 - 2024 — McMap. All rights reserved.