Hoe krijg ik de hoofdvenster-handle van proces-ID?

Hoe krijg ik de hoofdvensterhandle van proces-ID?

Ik wil dit venster naar voren halen.

Het werkt goed in “Procesverkenner”.


Antwoord 1, autoriteit 100%

Ik heb gecontroleerd hoe .NET het hoofdvenster bepaalt.

Mijn bevinding toonde aan dat het ook EnumWindows()gebruikt.

Deze code zou het op dezelfde manier moeten doen als de .NET-manier:

struct handle_data {
    unsigned long process_id;
    HWND window_handle;
};
HWND find_main_window(unsigned long process_id)
{
    handle_data data;
    data.process_id = process_id;
    data.window_handle = 0;
    EnumWindows(enum_windows_callback, (LPARAM)&data);
    return data.window_handle;
}
BOOL CALLBACK enum_windows_callback(HWND handle, LPARAM lParam)
{
    handle_data& data = *(handle_data*)lParam;
    unsigned long process_id = 0;
    GetWindowThreadProcessId(handle, &process_id);
    if (data.process_id != process_id || !is_main_window(handle))
        return TRUE;
    data.window_handle = handle;
    return FALSE;   
}
BOOL is_main_window(HWND handle)
{   
    return GetWindow(handle, GW_OWNER) == (HWND)0 && IsWindowVisible(handle);
}

Antwoord 2, autoriteit 59%

Ik geloof niet dat Windows (in tegenstelling tot .NET) een directe manier biedt om dat te krijgen.

De enige manier die ik ken is om alle vensters op het hoogste niveau op te sommen met EnumWindows()en dan te zoeken welk proces elk bij GetWindowThreadProcessID()hoort. Dit klinkt indirect en inefficiënt, maar het is niet zo erg als je zou verwachten — in een typisch geval heb je misschien een dozijn vensters op het hoogste niveau om doorheen te lopen…


Antwoord 3, autoriteit 17%

Er is een mogelijkheid van een misverstand hier. Het WinForms-framework in .Net wijst automatisch het eerste gemaakte venster (bijv. Application.Run(new SomeForm())) aan als het MainWindow. De win32 API herkent echter niet het idee van een “hoofdvenster” per proces. De berichtenlus is volledig in staat om zoveel “hoofd”-vensters te verwerken als systeem- en procesbronnen u kunnen laten maken. Uw proces heeft dus geen “hoofdvenster”. Het beste wat u in het algemeen kunt doen, is EnumWindows()gebruiken om alle niet-onderliggende vensters actief te krijgen in een bepaald proces en proberen enkele heuristieken te gebruiken om erachter te komen welke u wilt . Gelukkig hebben de meeste processen meestal maar één enkel “hoofd”-venster, dus in de meeste gevallen zou je goede resultaten moeten krijgen.


Antwoord 4, autoriteit 16%

Dit is mijn oplossing met pure Win32/C++ gebaseerd op het beste antwoord. Het idee is om alles wat nodig is in één functie in te pakken zonder dat externe callback-functies of -structuren nodig zijn:

#include <utility>
HWND FindTopWindow(DWORD pid)
{
    std::pair<HWND, DWORD> params = { 0, pid };
    // Enumerate the windows using a lambda to process each window
    BOOL bResult = EnumWindows([](HWND hwnd, LPARAM lParam) -> BOOL 
    {
        auto pParams = (std::pair<HWND, DWORD>*)(lParam);
        DWORD processId;
        if (GetWindowThreadProcessId(hwnd, &processId) && processId == pParams->second)
        {
            // Stop enumerating
            SetLastError(-1);
            pParams->first = hwnd;
            return FALSE;
        }
        // Continue enumerating
        return TRUE;
    }, (LPARAM)&params);
    if (!bResult && GetLastError() == -1 && params.first)
    {
        return params.first;
    }
    return 0;
}

Antwoord 5, autoriteit 3%

Hoewel het misschien niets met uw vraag te maken heeft, kunt u een kijkje nemen op GetGUIThreadInfo-functie.


Antwoord 6, autoriteit 3%

Als uitbreiding op de oplossing van Hiale kunt u een andere of aangepaste versie leveren die processen ondersteunt die meerdere hoofdvensters hebben.

Pas eerst de structuur aan om het opslaan van meerdere handvatten toe te staan:

struct handle_data {
    unsigned long process_id;
    std::vector<HWND> handles;
};

Ten tweede, wijzig de callback-functie:

BOOL CALLBACK enum_windows_callback(HWND handle, LPARAM lParam)
{
    handle_data& data = *(handle_data*)lParam;
    unsigned long process_id = 0;
    GetWindowThreadProcessId(handle, &process_id);
    if (data.process_id != process_id || !is_main_window(handle)) {
        return TRUE;
    }
    // change these 2 lines to allow storing of handle and loop again
    data.handles.push_back(handle);
    return TRUE;   
 }

Wijzig ten slotte de resultaten van de hoofdfunctie:

std::vector<HWD> find_main_window(unsigned long process_id)
{
    handle_data data;
    data.process_id = process_id;
    EnumWindows(enum_windows_callback, (LPARAM)&data);
    return data.handles;
}

Antwoord 7

Om er zeker van te zijn dat je de tid (thread-ID) en de pid (proces-ID) niet door elkaar haalt:

DWORD pid;
DWORD tid = GetWindowThreadProcessId( this->m_hWnd, &pid);

Other episodes