web-dev-qa-db-fra.com

Comment obtenir le handle de la fenêtre principale à partir d'un identifiant de processus?

Comment obtenir le descripteur main window à partir de l'ID de processus?

Je veux apporter cette fenêtre à l'avant.

Cela fonctionne bien dans "Process Explorer".

53
Alexey Malistov

J'ai vérifié comment .NET détermine la fenêtre principale.

Ma conclusion a montré qu'il utilise également EnumWindows().

Ce code devrait le faire de manière similaire à la manière .NET:

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);
}
49
Hiale

Je ne crois pas que Windows (contrairement à .NET) fournisse un moyen direct de l'obtenir.

Le seul moyen que je connaisse est d’énumérer toutes les fenêtres de niveau supérieur avec EnumWindows(), puis de trouver le processus correspondant à chacune des GetWindowThreadProcessID(). Cela semble indirect et inefficace, mais ce n’est pas aussi grave que vous pourriez le penser: dans un cas typique, vous pourriez avoir une douzaine de fenêtres de premier niveau à traverser ...

36
Jerry Coffin

Il y a la possibilité d'une mauvaise compréhension ici. La structure WinForms dans .Net désigne automatiquement la première fenêtre créée (par exemple, Application.Run(new SomeForm())) en tant que MainWindow. L'API win32, cependant, ne reconnaît pas l'idée d'une "fenêtre principale" par processus. La boucle de message est tout à fait capable de gérer autant de fenêtres "principales" que les ressources système et de traitement vous permettront de créer. Votre processus n'a donc pas de "fenêtre principale". Le mieux que vous puissiez faire dans le cas général consiste à utiliser EnumWindows() pour activer toutes les fenêtres non enfants sur un processus donné et à utiliser des méthodes heuristiques pour déterminer celle qui vous convient. Heureusement, la plupart des processus ne disposent généralement que d’une seule fenêtre "principale". Vous devriez donc obtenir de bons résultats dans la plupart des cas.

11
Dathan

Ceci est ma solution utilisant pur Win32/C++ basé sur la réponse en haut. L'idée est de regrouper tous les éléments requis dans une seule fonction sans recourir à des fonctions ou structures de rappel externes:

#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;
}
5
Benj

Bien que cela puisse n’être pas lié à votre question, jetez un coup d’œil à Fonction GetGUIThreadInfo .

2
AntonK

Juste pour vous assurer que vous ne confondez pas le tid (id du fil) et le pid (id du processus):

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

En tant qu'extension de la solution Hiale, vous pouvez fournir une version différente ou modifiée prenant en charge les processus comportant plusieurs fenêtres principales.

Commencez par modifier la structure pour permettre le stockage de plusieurs handles:

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

Deuxièmement, modifiez la fonction de rappel:

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;   
 }

Enfin, modifiez les retours sur la fonction principale:

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;
}
0
Class Skeleton