Win32 - 获取应用程序的主 Wnd 句柄

2021-12-18 00:00:00 windows winapi c++

我已将我的 dll 注入进程.如何获取宿主应用程序的主窗口句柄?

I have injected my dll into process. How can I get Main window handle of host application?

推荐答案

宿主应用程序可能有多个主窗口".要检测它们,您可以

The host application may have multiple 'main windows'. To detect them, you could

  1. 调用 GetCurrentProcessId获取当前进程的PID
  2. 调用 EnumWindows遍历桌面的所有顶级窗口
  3. 对于桌面上的每个窗口,调用 GetWindowThreadProcessId获取创建窗口的进程的PID
  4. 如果窗口的 PID 与您自己进程的 PID 匹配,请记住该窗口.

这为您提供了由您注入 DLL 的进程创建的顶级窗口列表.但是,请注意,这种方法可能会产生在您处理构建的窗口列表时已被破坏的窗口.因此,在使用 Windows 执行某些操作时,请确保使用 IsWindow 函数以确保手头的窗口仍然有效(这仍然容易出现竞争条件,因为在您调用 IsWindow 和实际访问窗口,但时间窗口要小得多).

That gives you a list of toplevel windows created by the process which you injected your DLL into. However, please note that this approach may yield windows which have been destroyed by the time you process the constructed list of windows. Hence, when doing something with the windows, make sure to use the IsWindow function to ensure that the window at hand is still valid (this is still prone to race conditions since the window may become invalid between your call to IsWindow and actually accessing the window, but the time window is much smaller).

这是一个实现该算法的 C++ 函数.它实现了一个 getToplevelWindows 函数,该函数产生一个 std::vector,其中包含当前进程的所有顶级窗口的句柄.

Here's a C++ function implementing this algorithm. It implements a getToplevelWindows function which yields a std::vector<HWND> containing the handles of all toplevel windows of the current process.

struct EnumWindowsCallbackArgs {
    EnumWindowsCallbackArgs( DWORD p ) : pid( p ) { }
    const DWORD pid;
    std::vector<HWND> handles;
};

static BOOL CALLBACK EnumWindowsCallback( HWND hnd, LPARAM lParam )
{
    EnumWindowsCallbackArgs *args = (EnumWindowsCallbackArgs *)lParam;

    DWORD windowPID;
    (void)::GetWindowThreadProcessId( hnd, &windowPID );
    if ( windowPID == args->pid ) {
        args->handles.push_back( hnd );
    }

    return TRUE;
}

std::vector<HWND> getToplevelWindows()
{
    EnumWindowsCallbackArgs args( ::GetCurrentProcessId() );
    if ( ::EnumWindows( &EnumWindowsCallback, (LPARAM) &args ) == FALSE ) {
      // XXX Log error here
      return std::vector<HWND>();
    }
    return args.handles;
}

更新:这些天(我给出答案大约四年后)我也会考虑 遍历应用程序的线程列表,然后使用EnumThreadWindows 在每个线程上.我注意到这在许多情况下要快得多.

UPDATE: These days (about four years after I gave the answer) I would also consider traversing the list of threads of the application and then using EnumThreadWindows on each thread. I noticed that this is considerably faster in many cases.

相关文章