通过小部件获取 top-level window
Getting top-level window by widget
我正在挂钩 Windows 上 Qt5 应用程序的 QPainter::drawText()
函数。
我的目标是识别绘制文本的 top-level-window 的本机句柄。首先,我正在获取关联的小部件。
QWidget *widget = static_cast<QWidget *>(painter->device());
所以应该可以找到对应的top-levelwindow/widget。
但这比我想象的要难。这是我到目前为止尝试过的:
while (widget->parentWidget())
widget = widget->parentWidget();
HWND hwnd = (HWND) widget->winId();
没有成功。 top-parent 永远不是想要的 window.
QApplication::topLevelWidgets()
向我展示了一个 window 包含多个 top-level 小部件(包括我正在寻找的小部件)。
我也试过了QApplication::topLevelAt(widget->mapToGlobal(QPoint()))
在某些情况下这确实有效,但并不可靠。
根据文本和 window 位置,我得到 AccessViolationException
,
所以这不是一个选择。
通过测试widget->testAttribute(Qt::WA_NativeWindow)
我发现大多数小部件都是 non-native Alien Widgets.
我就是这样得到(我所说的)top-level window.
WinAPI.EnumChildWindows(
WinAPI.GetDesktopWindow(),
new EnumWindowsProc(this.EnumWindowsCallback), 0);
然后我查看 window 标题以找到我感兴趣的句柄。
我无法找到任何 (low-level) 小部件与拥有 window 标题的 (top-level) 小部件之间的关系。
对于作为顶层的QWidget
window,call QWidget::window()
.
对于具有本机句柄的最近父级,call QWidget::nativeParentWidget()
。
调用 winId()
强制小部件获取本机 window 句柄(如果它没有 ),这不是您的目标。顶级 window 将始终具有本机 ID,因此 (HWND)window()->winId()
没问题。请注意,这 通常 与 calling QWidget::effectiveWinId()
相同。
完成!我找到了解决问题的方法。
每个 windows 都有自己的线程。
int threadId = WinApi.GetWindowThreadProcessId(wndHandle, IntPtr.Zero)
有了它我用EnumThreadWindows
获取此线程创建的所有 window-句柄的列表。
最后我检查了widget->effectiveWinId()
是否在列表中。
所以我可以将每个小部件映射到其对应的 window!
我正在挂钩 Windows 上 Qt5 应用程序的 QPainter::drawText()
函数。
我的目标是识别绘制文本的 top-level-window 的本机句柄。首先,我正在获取关联的小部件。
QWidget *widget = static_cast<QWidget *>(painter->device());
所以应该可以找到对应的top-levelwindow/widget。 但这比我想象的要难。这是我到目前为止尝试过的:
while (widget->parentWidget())
widget = widget->parentWidget();
HWND hwnd = (HWND) widget->winId();
没有成功。 top-parent 永远不是想要的 window.
QApplication::topLevelWidgets()
向我展示了一个 window 包含多个 top-level 小部件(包括我正在寻找的小部件)。
我也试过了QApplication::topLevelAt(widget->mapToGlobal(QPoint()))
在某些情况下这确实有效,但并不可靠。
根据文本和 window 位置,我得到 AccessViolationException
,
所以这不是一个选择。
通过测试widget->testAttribute(Qt::WA_NativeWindow)
我发现大多数小部件都是 non-native Alien Widgets.
我就是这样得到(我所说的)top-level window.
WinAPI.EnumChildWindows(
WinAPI.GetDesktopWindow(),
new EnumWindowsProc(this.EnumWindowsCallback), 0);
然后我查看 window 标题以找到我感兴趣的句柄。
我无法找到任何 (low-level) 小部件与拥有 window 标题的 (top-level) 小部件之间的关系。
对于作为顶层的QWidget
window,call QWidget::window()
.
对于具有本机句柄的最近父级,call QWidget::nativeParentWidget()
。
调用 winId()
强制小部件获取本机 window 句柄(如果它没有 ),这不是您的目标。顶级 window 将始终具有本机 ID,因此 (HWND)window()->winId()
没问题。请注意,这 通常 与 calling QWidget::effectiveWinId()
相同。
完成!我找到了解决问题的方法。
每个 windows 都有自己的线程。
int threadId = WinApi.GetWindowThreadProcessId(wndHandle, IntPtr.Zero)
有了它我用EnumThreadWindows 获取此线程创建的所有 window-句柄的列表。
最后我检查了widget->effectiveWinId()
是否在列表中。
所以我可以将每个小部件映射到其对应的 window!