按小部件获取顶级窗口

时间:2016-05-07 23:03:20

标签: c++ qt hook

我在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);

然后我检查窗口标题以找到我感兴趣的句柄。

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

2 个答案:

答案 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()

所以我可以将每个小部件映射到相应的窗口!