2

I'm hooking the QPainter::drawText() function of a Qt5 application on Windows. My goal is to identify the native handle of the top-level-window to which the text is painted. First, I'm getting the associated widget.

QWidget *widget = static_cast<QWidget *>(painter->device());

So it should be possible to find the corresponding top-level window/widget. But it's harder than I thought. This is what I tried so far:

while (widget->parentWidget())
    widget = widget->parentWidget();

HWND hwnd = (HWND) widget->winId();

No success. The top-parent is never the desired window.

QApplication::topLevelWidgets()

Showed me that one single window contains several top-level-widgets (including the one I'm looking for).

I also tried QApplication::topLevelAt(widget->mapToGlobal(QPoint()))

In some cases this actually works, but not reliably. Depending on text and window position I'm getting a AccessViolationException, so this is not an option.

By testing widget->testAttribute(Qt::WA_NativeWindow) I found out that most of the widgets are non-native Alien Widgets.

This is how I get the (what I call) top-level window.

WinAPI.EnumChildWindows(
    WinAPI.GetDesktopWindow(),
    new EnumWindowsProc(this.EnumWindowsCallback), 0);

Then I check the window titles to find the handles I'm interested in.

I'm not able to find a relation from any (low-level) widget to the (top-level) widget that holds the window title.

m1st4x
  • 31
  • 1
  • 8
  • 1
    To clarify: Are you looking for the handle of the first "Container 'Client'", or your "Top-Level-Window"? Can you show some code or describe how your "top-level widgets" relate to that single window? – JKSH May 08 '16 at 02:47
  • Please note that using the Windows API or a third-party utility to paint in Qt is highly unlikely to work reliably unless you embed a native widget and paint on that. – jonspaceharper May 08 '16 at 15:00
  • I don't want to draw anything. I'm intercepting the whole text output of the application and compare each string to some keywords. If I find a match, I want to map it to one of the application's open windows. – m1st4x May 08 '16 at 17:40
  • I don't have any souce code of the application I'm intercepting. – m1st4x May 08 '16 at 17:40

3 Answers3

4

For the QWidget that acts as a top level window, call QWidget::window().

For the nearest parent with a native handle, call QWidget::nativeParentWidget().

Calling winId() forces the widget to acquire a native window handle if it does not have one, which isn't your goal. A top level window will always have a native id, so (HWND)window()->winId() is fine. Note that this is usually the same as calling QWidget::effectiveWinId().

jonspaceharper
  • 4,207
  • 2
  • 22
  • 42
  • Very good hint! So if you deal with non-native (alien) widgets, avoid using QWidget::winId() for debugging purposes, like I did :P – m1st4x May 08 '16 at 21:03
  • Yes. `widget->nativeParentWidget()->effectiveWinId()` gives me the nearest native parent handle. But unfortunately it's never the wanted :( – m1st4x May 09 '16 at 08:32
1

It's done! I found a solution for my problem.

Each windows has it's own thread.

int threadId = WinApi.GetWindowThreadProcessId(wndHandle, IntPtr.Zero)

With it I use EnumThreadWindows to get a list of all window-handles created by this thread.

Finally I check wheather widget->effectiveWinId() is in the list.

So I can map each widget to its corresponding window!

m1st4x
  • 31
  • 1
  • 8
0

My 5 cents:

widget->backingStore()->window()->winId()
user1095108
  • 14,119
  • 9
  • 58
  • 116