我在Windows上挂钩了Qt5应用程序的QPainter::drawText()
功能。
我的目标是识别绘制文本的顶级窗口的本机句柄。首先,我获得了相关的小部件。
QWidget *widget = static_cast<QWidget *>(painter->device());
因此应该可以找到相应的顶级窗口/窗口小部件。 但它比我想象的更难。这是我到目前为止所尝试的:
while (widget->parentWidget())
widget = widget->parentWidget();
HWND hwnd = (HWND) widget->winId();
没有成功。顶级父级永远不是理想的窗口。
QApplication::topLevelWidgets()
告诉我一个窗口包含几个顶级窗口小部件(包括我正在寻找的窗口小部件)。
我也试过QApplication::topLevelAt(widget->mapToGlobal(QPoint()))
在某些情况下,这实际上有效,但不可靠。
根据文字和窗口位置,我得到AccessViolationException
,
所以这不是一个选择。
通过测试widget->testAttribute(Qt::WA_NativeWindow)
我发现大多数小部件都是非本地的Alien Widgets。
这就是我得到(我称之为)顶级窗口的方式。
WinAPI.EnumChildWindows(
WinAPI.GetDesktopWindow(),
new EnumWindowsProc(this.EnumWindowsCallback), 0);
然后我检查窗口标题以找到我感兴趣的句柄。
我无法找到任何(低级别)窗口小部件与保存窗口标题的(顶级)窗口小部件之间的关系。
答案 0 :(得分:3)
对于充当顶级窗口的QWidget
call QWidget::window()
。
对于具有原生句柄的最近父级call QWidget::nativeParentWidget()
。
调用winId()
会强制小部件获取本机窗口句柄(如果它没有),这不是您的目标。顶级窗口将始终具有本机ID,因此(HWND)window()->winId()
很好。请注意,通常与calling QWidget::effectiveWinId()
相同。
答案 1 :(得分:1)
已经完成了!我找到了解决问题的方法。
每个窗口都有它自己的线程。
int threadId = WinApi.GetWindowThreadProcessId(wndHandle, IntPtr.Zero)
有了它我用EnumThreadWindows 获取该线程创建的所有窗口句柄的列表。
最后,我检查列表中是否有widget->effectiveWinId()
。
所以我可以将每个小部件映射到相应的窗口!