簡體   English   中英

如何從進程ID獲取主窗口句柄?

[英]How to get main window handle from process id?

如何從進程ID獲取窗口句柄?

我想把這個窗口放在前面。

它在“進程資源管理器”中運行良好。

我檢查了 .NET 如何確定主窗口。

我的發現表明它也使用EnumWindows()

這段代碼應該與 .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);
}

我不相信 Windows(而不是 .NET)提供了一種直接的方法來獲得它。

我知道的唯一方法是使用EnumWindows()枚舉所有頂級窗口,然后找到每個進程屬於GetWindowThreadProcessID() 這聽起來間接且效率低下,但它並沒有你想象的那么糟糕——在典型的情況下,你可能有十幾個頂層窗口要穿過......

這里有誤會的可能。 .Net 中的 WinForms 框架自動將創建的第一個窗口(例如Application.Run(new SomeForm()) )指定為MainWindow 但是,win32 API 無法識別每個進程的“主窗口”的概念。 消息循環完全能夠處理與系統和進程資源允許您創建的盡可能多的“主”窗口。 因此,您的流程沒有“主窗口”。 在一般情況下,您可以做的最好的事情是使用EnumWindows()使給定進程上的所有非子窗口都處於活動狀態,並嘗試使用一些啟發式方法來確定哪個是您想要的。 幸運的是,大多數進程大部分時間可能只有一個“主”窗口在運行,因此在大多數情況下您應該會獲得良好的結果。

這是我基於最佳答案使用純 Win32/C++ 的解決方案。 這個想法是將所需的所有內容包裝到一個函數中,而無需外部回調函數或結構:

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

盡管它可能與您的問題無關,但請查看GetGUIThreadInfo Function

作為 Hiale 解決方案的擴展,您可以提供支持具有多個主窗口的進程的不同或修改版本。

首先,修改結構以允許存儲多個句柄:

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

二、修改回調函數:

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

最后,修改 main 函數的返回值:

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

只是為了確保您不會混淆 tid(線程 ID)和 pid(進程 ID):

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

在這里,我想補充一點,如果您正在讀取進程的 HWND 窗口句柄,則該進程不應在調試中運行,否則它將無法使用 FindWindowEx 找到窗口句柄。

老問題但似乎有很多流量,這里有一個簡單的解決方案:

IntPtr GetMainWindowHandle(IntPtr aHandle) {
        return System.Diagnostics.Process.GetProcessById(aHandle.ToInt32()).MainWindowHandle;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM