我将从纯 C 和 Win32 的角度回答这个问题,因为我不了解 Delphi 或其库。可以通过 p/invoke 将其转换为 C#,但某些部分可能/将需要非托管。
首先,不保证。如果目标应用程序正在执行无 Windows 控件(如果每个屏幕控件下都没有 HWND),那么您就很不走运了。这并不少见,所以是的......
第一步,注册一个窗口挂钩,监听目标进程创建的新窗口*:
//dllHMod is an HMODULE that refers to the DLL containing ShellHookProc
HHOOK hook = SetWindowsHookEx(WH_SHELL, ShellHookProc, dllHMod, 0);
// error handling, stashing hook away for unregistering later, etc...
LRESULT CALLBACK ShellHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if(nCode < 0) return CallNextHookEx(NULL, nCode, wParam, lParam);
if(nCode == HSHELL_WINDOWCREATED)
{
WindowCreate((HWND)wParam);
}
return 0;
}
如果正确的进程(通过GetWindowThreadProcessId 确定)拥有它,WindowCreated(HWND) 应该将 HWND 隐藏起来。此时,您将能够获得目标进程拥有的每个顶级窗口。请注意,注册全局钩子会带来显着的性能损失,这在您的情况下并不重要,但您应该预料到它。
现在是有趣的部分。没有可靠的方法来判断窗口何时完全构建,或何时完成渲染(有一些方法可以判断它何时开始渲染,但这并没有真正帮助)。我的建议,猜。只需在那里随意等待,然后尝试枚举所有子窗口。
枚举子窗口(如果您对目标窗口有足够的了解,有更好的方法可以做到这一点;但我假设搜索是最简单的):
//targetHWND is an HWND of one of the top-level windows you've found
EnumChildWindows(targetHWND, ChildWindowCallback, NULL);
//more code...
BOOL ChildWindowCallback(HWND window, LPARAM ignored)
{
if(IsTargetWindow(window)) { /* Do something */ }
return TRUE;
}
实现IsTargetWindow 是另一个棘手的部分。希望您能找到一些可靠的测试方法(例如检查类名、窗口名、样式等;查看GetWindowInfo)。
一旦您有了想要监控的窗口,您就可以使用SetWindowLongPtr 和GWLP_WNDPROC 来查看它收到的所有消息。这将需要代码注入(因此需要非托管代码)并且级别非常低。如果您可以避免它,我建议您不要这样做,但缺少来源...
我认为这个答案是一个不错的起点,但再次这将是令人难以置信的痛苦,如果它甚至可能的话。祝你好运。
*或者,如果您知道目标应用程序不会创建窗口,除非在启动时(或在可检测/可预测的时间点),您可以使用EnumWindows。