Search code examples
c++winapiprocesshwndenumerate

C++/Win32 enumerate windows belonging to my process & close them


I have a Windows app that houses a web browser (Internet explorer) embedded in it. The app can be closed from another process by means of IPC. It works just fine except the situation when the embedded web browser may be displaying a pop-up dialog window (say, during saving of contents). In that case my app crashes when it tries to close from an outside request via IPC. (Internally it simply posts the WM_CLOSE message to itself.)

In light of that I thought to come up with a way to enumerate all windows that belong to my process and close them first before closing my process itself. The question is, how do you enumerate all windows belonging to my process for the purpose of closing them?


Solution

  • OK, I guess I got it myself. Here's if someone is interested:

    #define SIZEOF(f) (sizeof(f) / sizeof(f[0]))
    typedef struct _ENUM_POPUPS_INFO{
        DWORD dwProcID;
        HWND hThisWnd;
        int nNextHWNDIndex;
        HWND hFoundHWNDs[256];
    }ENUM_POPUPS_INFO;
    
    void CloseAllOpenPopups(HWND hWnd, int dwmsWait)
    {
        //'hWnd' = our main window handle (we won't close it)
        //'dwmsWait' = maximum wait time in milliseconds, or -1 to wait for as long as needed
        ENUM_POPUPS_INFO epi = {0};
        BOOL bR;
        int i, iIteration;
        HWND hWndRoot, hWndActivePopup;
    
        DWORD dwmsTickBegin = GetTickCount();
    
        for(iIteration = 0;; iIteration = 1)
        {
            //Get our process ID
            memset(&epi, 0, sizeof(epi));
            epi.hThisWnd = hWnd;
            epi.dwProcID = GetCurrentProcessId();
    
            bR = EnumWindows(EnumPopupWindowsProc, (LPARAM)&epi);
    
            //Did we get any
            if(epi.nNextHWNDIndex == 0)
                break;
    
            //Wait on a second and later iteration
            if(iIteration > 0)
            {
                if(dwmsWait != -1)
                {
                    DWORD dwmsTick = GetTickCount();
                    int nmsDiff = abs((long)(dwmsTick - dwmsTickBegin));
                    if(nmsDiff >= dwmsWait)
                    {
                            //Timed out
                    break;
                    }
    
                    //Wait
                    Sleep(min(100, dwmsWait - nmsDiff));
                }
                else
                {
                    //Wait
                    Sleep(100);
                }
            }
    
            //Go through all windows found
                for(i = 0; i < epi.nNextHWNDIndex; i++)
            {
                //Get root owner
                hWndRoot = GetAncestor(epi.hFoundHWNDs[i], GA_ROOTOWNER);
                if(!hWndRoot)
                    continue;
    
                //Get it's active popup
                hWndActivePopup = GetLastActivePopup(hWndRoot);
                if(!hWndActivePopup)
                    continue;
    
                //Close it
                PostMessage(hWndActivePopup, WM_CLOSE, 0, 0);
            }
        }
    }    
    
    
    BOOL CALLBACK EnumPopupWindowsProc(HWND hWnd, LPARAM lParam)
    {
        ENUM_POPUPS_INFO* pEPI = (ENUM_POPUPS_INFO*)lParam;
    
        //Get process ID of the window
        DWORD dwProcID = 0;
        GetWindowThreadProcessId(hWnd, &dwProcID);
    
        //We need this window only if it's our process
        if(dwProcID == pEPI->dwProcID &&
            pEPI->hThisWnd != hWnd &&
            ((GetWindowLongPtr(hWnd, GWL_STYLE) & (WS_VISIBLE | WS_POPUP | WS_CAPTION)) == (WS_VISIBLE | WS_POPUP | WS_CAPTION)))
        {
            if(pEPI->nNextHWNDIndex >= SIZEOF(pEPI->hFoundHWNDs))
            {
                //Stop, we're full
                return FALSE;
            }
    
            //Add it
            pEPI->hFoundHWNDs[pEPI->nNextHWNDIndex] = hWnd;
            pEPI->nNextHWNDIndex++;
        }
    
        return TRUE;
    }