it-swarm-es.com

¿Cómo obtener el identificador de la ventana principal desde el ID de proceso?

¿Cómo obtener main window handle desde el ID de proceso?

Quiero traer esta ventana al frente.

Funciona bien en "Process Explorer".

53
Alexey Malistov

Verifiqué cómo .NET determina la ventana principal.

Mi hallazgo demostró que también usa EnumWindows().

Este código debería hacerlo de manera similar a la forma .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);
}
50
Hiale

No creo que Windows (a diferencia de .NET) proporcione una forma directa de conseguir eso.

La única forma que conozco es enumerar todas las ventanas de nivel superior con EnumWindows() y luego encontrar qué proceso pertenece a GetWindowThreadProcessID(). Esto suena indirecto e ineficiente, pero no es tan malo como podría esperarse: en un caso típico, es posible que tenga una docena de ventanas de nivel superior para caminar ...

37
Jerry Coffin

Existe la posibilidad de un malentendido aquí. El marco de trabajo de WinForms en .Net designa automáticamente la primera ventana creada (por ejemplo, Application.Run(new SomeForm())) como MainWindow. Sin embargo, la API de win32 no reconoce la idea de una "ventana principal" por proceso. El bucle de mensajes es totalmente capaz de manejar tantas ventanas "principales" como los recursos del sistema y del proceso le permitirán crear. Por lo tanto, su proceso no tiene una "ventana principal". Lo mejor que puede hacer en el caso general es usar EnumWindows() para activar todas las ventanas no secundarias en un proceso determinado y tratar de usar algunas heurísticas para determinar cuál es la que desea. Afortunadamente, es probable que la mayoría de los procesos solo tengan una ventana "principal" que se ejecute la mayor parte del tiempo, por lo que debería obtener buenos resultados en la mayoría de los casos.

11
Dathan

Esta es mi solución utilizando Win32/C++ puro basado en la respuesta superior. La idea es envolver todo lo requerido en una función sin la necesidad de funciones o estructuras de devolución de llamada externas:

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

Aunque puede no estar relacionado con su pregunta, eche un vistazo a Función GetGUIThreadInfo .

2
AntonK

Solo para asegurarse de que no está confundiendo el tid (id de hilo) y el pid (id de proceso):

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

Como extensión de la solución de Hiale, puede proporcionar una versión diferente o modificada que admita procesos que tengan varias ventanas principales.

Primero, modifique la estructura para permitir el almacenamiento de múltiples manejadores:

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

En segundo lugar, modifique la función de devolución de llamada:

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

Finalmente, enmendar las devoluciones en la función principal:

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