c++ 如何从进程ID中获取主窗口句柄?

lsmd5eda  于 11个月前  发布在  其他
关注(0)|答案(8)|浏览(204)

如何从进程id中获取main窗口句柄?
我想把这扇Windows移到前面。
它在“Process Explorer”中运行良好。

4urapxun

4urapxun1#

我检查了.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);
}

字符串

soat7uwm

soat7uwm2#

我不相信Windows(相对于.NET)提供了一个直接的方法来实现这一点。
我所知道的唯一方法是枚举所有具有EnumWindows()的顶层窗口,然后找出每个属于GetWindowThreadProcessID()的进程。这听起来很间接,效率很低,但并不像你想象的那么糟糕--在一个典型的情况下,你可能有十几个顶层窗口要遍历。

x7yiwoj4

x7yiwoj43#

这里可能存在误解,.Net中的WinForms框架会自动指定创建的第一个窗口(例如,Application.Run(new SomeForm()))作为MainWindow。然而,win32 API不承认每个进程的“主窗口”的想法。消息循环完全能够处理系统和进程资源允许您创建的尽可能多的“主”窗口。因此,你的进程没有一个“主窗口”。一般情况下,你能做的最好的事情是使用EnumWindows()来激活给定进程上的所有非子窗口,并尝试使用一些技巧来找出哪一个是你想要的。幸运的是,大多数进程在大多数时间里只可能有一个“主”窗口运行,所以在大多数情况下你应该会得到很好的结果。

fzwojiic

fzwojiic4#

这是我的解决方案,使用纯Win32/C++的基础上的顶部答案。这个想法是 Package 所需的一切到一个函数,而不需要外部回调函数或结构:

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

字符串

lyfkaqu1

lyfkaqu15#

虽然它可能与你的问题无关,但看看GetGUIThreadInfo Function

anauzrmj

anauzrmj6#

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

s2j5cfk0

s2j5cfk07#

只是为了确保你没有混淆tid(线程id)和pid(进程id):

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

字符串

ioekq8ef

ioekq8ef8#

如果你有一个命令行应用程序(而不是GUI应用程序),你可以使用GetConsoleWindow() winapi函数。
@Hiale给出的最上面的答案将不起作用,因为is_main_window不会将控制台窗口标识为应用程序的主窗口。

相关问题