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

11

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


12
我认为“受害应用程序”比“主机应用程序”更合适。如果持枪歹徒闯入我的房子并把我扣为人质,我将成为受害者而不是主机。 - Adrian McCarthy
2个回答

37

主机应用程序可能有多个“主窗口”。要检测它们,您可以:

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

这样可以得到一个由您注入DLL的进程创建的顶层窗口列表。但是,请注意,此方法可能会产生已在构建的窗口列表处理时销毁的窗口。因此,在处理窗口时,请确保使用IsWindow函数确保手头的窗口仍然有效(这仍然容易受到竞争条件的影响,因为窗口可能在您调用IsWindow和实际访问窗口之间变得无效,但时间窗口要小得多)。

这是一个实现该算法的 C++ 函数。它实现了一个名为 getToplevelWindows 的函数,该函数生成一个包含当前进程所有顶级窗口句柄的 std::vector<HWND>
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。我注意到在许多情况下,这样做要快得多。

我对EnumWindowsEnumThreadWindows之间的性能产生了好奇。在我的测试中,使用EnumWindows要快得多:当使用EnumThreadWindows时,速度为4毫秒对比200毫秒。我在此仅提供参考,将我的实现发布在此处:https://gist.github.com/gaspardpetit/3b1a10f6a2a9866b2bba8eb5d8e4ef36 - GaspardP

1

对于之前的答案,有一个小补充 - 主应用程序窗口没有父窗口,因此GetParent()将返回0。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接