Get Win32 legacy control's tooltip text progra

2019-02-04 05:29发布

问题:

I would like to get the tooltip text for win32 legacy control (not WPF controls that inherently support UI Automation).

What I have done:

  • Given a button of interest, I've got its AutomationElement, and its bounding rect
  • I moved the mouse over this button (in code);
  • Thread.Sleep(1500) to wait for the tooltip control to popup;
  • Enumerate Desktop's all child windows, and get the child window tooltipAutomationElement, whose type is "Tooltip";
  • From tooltipAutomationElement, get this tooltip's name property, which corresponds to the tooltip string.

This actually works, but the penalty is: I have to sleep(1500) and manually wait for the tooltip to appear (5-20 buttons are to be scanned for the tooltip strings), which does not match performance requirement.

What is expected (not sure if it is feasible)

  • Programmatically get the button's tooltip string without requiring the tooltip to appear
  • Without having to place mouse over each button one-by-one.

Update 1: For TTN_NEEDTEXT, MSDN doc seems not very clear, and I have no clue how to program this using C#. One of the relevant link for low level structures/messages related to tooltip control can be found here.

Update 2: Those who believe this could be done by ... , I would say, it is easier said than done. I welcome those who have tried, to comment on this, and some ostensibly feasible solutions are welcome if you can offer some evidence to show its applicability and efficacy.

Update 3: If we try to minimize the TTM_SETDELAYTIME so that N in the sleep(N) can be minimized, this does not work after some experimentation. We can only adjust this once the tooltip window handle exists. e.g.

SendMessage(_tooltipCtrl.Handle, TTM_SETDELAYTIME, _TTDT_INITIAL, 10); //10 ms

Update 4: using TTM_GETTEXTA message seems to be a solution, however, it is similar to Update 3, where we need the handle of the tooltipCtrl, which is only available AFTER the tooltip is created, since to have this tooltip created, we have no choice but to hover mouse cursor above the tool, which seems to have performance issues (Thread.Sleep) as outlined above.

SendMessage(_tooltipCtrl.Handle, TTM_GETTEXTA, 0, ti);

Update 5: "How to get the tooltip text" using InterOp (PInvoke) or Automation UI using traditional approach (mouse hovering on the tool window, find the Hwnd handle, then get its text...) is not the concern of this post. What is expected: Can we extract the tooltip string of a control (say a button) with no need of hovering upon the control? If yes, how?

Update 6: using WM_MOUSEHOVER to activate the tooltip window seems not working, I have tested that out using SendMessage(...) with proper wparam and lparam filled, but in vein.

回答1:

Just a thought, but try using messages rather than leveraging the actual mouse.

Play with WM_HOVER, WM_MOUSEHOVER, WM_MOUSEENTER

 SendMessage(_buttonCtrl.Handle, WM_MOUSEHOVER, ..., ...)

etc.

Your screenshot looks like a custom control so it's going to be a matter of hacking to figure out what triggers the tooltip.

Potentially, you can send several WM_MOUSEENTER's or WM_MOUSEHOVER's simultaneously. It really depends on the underlying code.

If this is causing too long of a delay, (and none of the suggested solutions work) think about pulling tooltip testing into a secondary test pool that is executed less frequently or only on specific request.

Also... and I'm sure you've tried it already... but if not, check out UI Spy and see if it reports any information about the tooltip before it's actually generated.



回答2:

The best thing from UI Automation perspective we can do is to subscribe to the ToolTip Opened Event and in the event handler process the same. This link has a sample http://msdn.microsoft.com/en-us/library/ms752286.aspx . List of UI Automation Events can be found here http://msdn.microsoft.com/en-us/library/ms748252.aspx . Details on AutomationElement.ToolTipOpenedEvent can be found here http://msdn.microsoft.com/en-us/library/system.windows.automation.automationelement.tooltipopenedevent.aspx .

With UI Automation at the least we should let the things to happen, either button click or opening a window or displaying a tooltip. So subscribing to ToolTip events would do the job here with better performance than hard Sleep() delays. Otherwise the hacky way(although not end to end) as mentioned by few, is to get the resource string ids for the tooltip string upfront and verify the resource strings during execution of automated tests.