C++ 通过小部件获取顶级窗口

C++ 通过小部件获取顶级窗口,c++,qt,hook,C++,Qt,Hook,我正在挂接Windows上Qt5应用程序的qPaint::drawText()函数。 我的目标是识别将文本绘制到的顶层窗口的本机句柄。首先,我得到相关的小部件 QWidget *widget = static_cast<QWidget *>(painter->device()); 没有成功。顶部父窗口永远不是所需的窗口 QApplication::topLevelWidgets() 向我展示了一个窗口包含多个顶级小部件(包括我正在寻找的小部件) 我还尝试了QApplicat

我正在挂接Windows上Qt5应用程序的
qPaint::drawText()
函数。 我的目标是识别将文本绘制到的顶层窗口的本机句柄。首先,我得到相关的小部件

QWidget *widget = static_cast<QWidget *>(painter->device());
没有成功。顶部父窗口永远不是所需的窗口

QApplication::topLevelWidgets()
向我展示了一个窗口包含多个顶级小部件(包括我正在寻找的小部件)

我还尝试了
QApplication::topLevelAt(widget->mapToGlobal(QPoint())

在某些情况下,这确实有效,但并不可靠。 根据文本和窗口位置,我得到一个
AccessViolationException
, 所以这不是一个选择

通过测试
widget->testAttribute(Qt::WA_NativeWindow)
我发现大多数小部件都是非本地的

这就是我获取(我称之为)顶层窗口的方式

WinAPI.EnumChildWindows(
    WinAPI.GetDesktopWindow(),
    new EnumWindowsProc(this.EnumWindowsCallback), 0);
然后我检查窗口标题以找到我感兴趣的句柄


我无法找到任何(低级)小部件与保存窗口标题的(顶级)小部件之间的关系。

对于充当顶级窗口的
QWidget

对于具有本机句柄的最近父级


调用
winId()
会强制小部件获取本机窗口句柄(如果它没有),这不是您的目标。顶级窗口将始终具有本机id,因此
(HWND)window()->winId()
可以。请注意,这通常与用作顶级窗口的
QWidget
相同

对于具有本机句柄的最近父级


调用
winId()
会强制小部件获取本机窗口句柄(如果它没有),这不是您的目标。顶级窗口将始终具有本机id,因此
(HWND)window()->winId()
可以。请注意,这通常与。

完成了!我找到了解决问题的办法

每个窗口都有自己的线程

int threadId = WinApi.GetWindowThreadProcessId(wndHandle, IntPtr.Zero)
我用它 获取此线程创建的所有窗口句柄的列表

最后,我检查列表中是否有
widget->effectiveWinId()


因此,我可以将每个小部件映射到相应的窗口

完成了!我找到了解决问题的办法

每个窗口都有自己的线程

int threadId = WinApi.GetWindowThreadProcessId(wndHandle, IntPtr.Zero)
我用它 获取此线程创建的所有窗口句柄的列表

最后,我检查列表中是否有
widget->effectiveWinId()


因此,我可以将每个小部件映射到相应的窗口

澄清一下:您是在寻找第一个“容器‘客户端’”的句柄,还是您的“顶级窗口”?你能展示一些代码或描述一下你的“顶级小部件”是如何与单个窗口相关的吗?请注意,除非你嵌入一个本地小部件并在上面绘制,否则使用Windows API或第三方实用程序在Qt中绘制是不可能可靠工作的。我不想绘制任何东西。我截取应用程序的整个文本输出,并将每个字符串与一些关键字进行比较。如果找到匹配项,我希望将其映射到应用程序的一个打开窗口。我没有正在拦截的应用程序的任何源代码。澄清一下:您是在寻找第一个“容器‘客户端’”的句柄,还是您的“顶级窗口”?你能展示一些代码或描述一下你的“顶级小部件”是如何与单个窗口相关的吗?请注意,除非你嵌入一个本地小部件并在上面绘制,否则使用Windows API或第三方实用程序在Qt中绘制是不可能可靠工作的。我不想绘制任何东西。我截取应用程序的整个文本输出,并将每个字符串与一些关键字进行比较。如果我找到了匹配项,我想将其映射到应用程序打开的窗口之一。我没有正在拦截的应用程序的任何源代码。非常好的提示!因此,如果处理非本机(外来)小部件,请避免使用QWidget::winId()进行调试,就像我所做的那样:PYes
widget->nativeParentWidget()->effectiveWinId()
为我提供了最近的本机父句柄。但不幸的是,它从来都不是想要的:(非常好的提示!因此,如果您处理非本机(外来)小部件,请避免使用QWidget::winId()进行调试,就像我所做的那样:PYes。
widget->nativeParentWidget()->effectiveWinId()
为我提供了最接近的本机父句柄。但不幸的是,它从来都不是想要的:(