it-swarm.it

Come ottenere l'handle della finestra principale dall'ID di processo?

Come ottenere main handle della finestra dall'id di processo?

Voglio portare questa finestra in primo piano.

Funziona bene in "Process Explorer".

53
Alexey Malistov

Ho controllato in che modo .NET determina la finestra principale.

La mia scoperta ha dimostrato che usa anche EnumWindows().

Questo codice dovrebbe farlo in modo simile al modo .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

Non credo che Windows (al contrario di .NET) fornisca un modo diretto per farlo.

L'unico modo che conosco è enumerare tutte le finestre di primo livello con EnumWindows() e quindi trovare quale processo appartengono a GetWindowThreadProcessID(). Questo suona indiretto e inefficiente, ma non è così male come ci si potrebbe aspettare - in un caso tipico, potresti avere una dozzina di finestre di alto livello da attraversare ...

36
Jerry Coffin

C'è la possibilità di una comprensione errata qui. Il framework WinForms in .Net designa automaticamente la prima finestra creata (ad esempio, Application.Run(new SomeForm())) come MainWindow. L'API win32, tuttavia, non riconosce l'idea di una "finestra principale" per processo. Il ciclo dei messaggi è completamente in grado di gestire tante finestre "principali" come le risorse di sistema e di processo ti permetteranno di creare. Quindi, il tuo processo non ha una "finestra principale". Il meglio che puoi fare nel caso generale è usare EnumWindows() per ottenere tutte le finestre non secondarie attive su un dato processo e provare a usare qualche euristica per capire quale è quella che vuoi. Fortunatamente, è probabile che la maggior parte dei processi abbia una sola finestra "principale" in esecuzione la maggior parte del tempo, quindi nella maggior parte dei casi è consigliabile ottenere buoni risultati.

11
Dathan

Questa è la mia soluzione utilizzando puro Win32/C++ in base alla risposta migliore. L'idea è di avvolgere tutto ciò che è necessario in una funzione senza la necessità di funzioni o strutture di callback esterne:

#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

Anche se potrebbe non essere correlato alla tua domanda, dai un'occhiata a GetGUIThreadInfo Function .

2
AntonK

Solo per assicurarti di non confondere il tid (id del thread) e il pid (id del processo):

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

Come estensione della soluzione di Hiale, potresti fornire una versione diversa o modificata che supporta processi che hanno più finestre principali.

Innanzitutto, modifica la struttura per consentire la memorizzazione di più maniglie:

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

Secondo, modifica la funzione di callback:

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

Infine, modifica i ritorni sulla funzione 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