Search code examples
c++mfcshellexecuteshellexecuteex

How to find out if process created with ShellExecuteEx owns a window?


I'm using ShellExecuteEx to run external application:

SHELLEXECUTEINFO shExInfo = { 0 };
    shExInfo.cbSize = sizeof(shExInfo);
    shExInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
    shExInfo.hwnd = 0;
    shExInfo.lpVerb = L"runas";                // Operation to perform
    shExInfo.lpFile = windowStringContainingAppPath.c_str();       // Application to start    
    shExInfo.lpParameters = windowStringContainingAppParameters.c_str();                  // Additional parameters
    shExInfo.lpDirectory = 0;
    shExInfo.nShow = SW_SHOW;
    shExInfo.hInstApp = 0;

    if(ShellExecuteEx(&shExInfo))
    {
        WaitForSingleObject(shExInfo.hProcess, INFINITE);

        DeleteFile(wsMesh3dx64Parameter.c_str());

        CloseHandle(shExInfo.hProcess);
    }

Everything works perfectly but there exist an unplanned behaviour of this external app that after closing its main window its process is still active. This prevents WaitForSingleObject(shExInfo.hProcess, INFINITE); from returning and I have to terminate the process manualy.

Instead I'm looking for a way to replace WaitForSingleObject(shExInfo.hProcess, INFINITE);with a loop that checks if external process owns a window and if not terminate it.

This is what I thought of but if there is a better way please point it out for me.

UPDATE:

Thanks to Robson answer I managed to do what I intended to:

struct Porcess_ID_HWND
{
    DWORD processID;
    HWND processhWnd;
};

BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam)
{
    Porcess_ID_HWND*info = (Porcess_ID_HWND*)lParam;

    DWORD processID;
    GetWindowThreadProcessId(hWnd, &processID);

    if (processID == info->processID){
        info->processhWnd = hWnd;
        return FALSE;
    }

    return TRUE;
}

And my loop:

if(ShellExecuteEx(&shExInfo))
{
    DWORD dwProcessID = GetProcessId(shExInfo.hProcess);

    Porcess_ID_HWND info;
    info.processID = dwProcessID;
    // wait for window to appear
    do
    {
        info.processhWnd = NULL;
        EnumWindows(EnumWindowsProc, (LPARAM)&info);

    } while (!info.processhWnd);

    // wait for window to close
    do
    {
        info.processhWnd = NULL;
        EnumWindows(EnumWindowsProc, (LPARAM)&info);

    } while (info.processhWnd);

    //WaitForSingleObject(shExInfo.hProcess, INFINITE);

    DeleteFile(wsMesh3dx64Parameter.c_str());

    CloseHandle(shExInfo.hProcess);
}

Solution

  • found a good answer at http://forums.codeguru.com/showthread.php?392273-RESOLVED-How-to-get-window-s-HWND-from-it-s-process-handle

    1)
    HAVE: Process ID, NEED: Process handle
    Solution: OpenProcess()
    
    2)
    HAVE: Process handle, NEED: Process ID
    Solution: GetProcessId()
    
    3)
    HAVE: Window handle, NEED: Process ID
    Solution: GetWindowThreadProcessId()
    
    4)
    HAVE: Window handle, NEED: Process handle
    Solution: Use 3) and then 1)
    
    5)
    HAVE: Process ID, NEED: Window handle
    Solution: EnumWindows(), then in the callback function do 3) and check if it matches your process ID.
    
    6)
    HAVE: Process handle, NEED: Window handle
    Solution: 2) and then 5)
    

    so you are in case 6. then if no window handle's process ID is matched with your shExInfo.hProcess's process ID then shExInfo.hProcess owns no window