c# - How to force UI automation tree refresh
问题描述
I am currently trying to use System.Windows.Automation
to automate a chrome instance, but at a certain point AutomationElement.FindAll(TreeScope.Children, Condition.TrueCondition);
returns always 0 children, but I can see them in inspect.exe. When I hit refresh in inspect.exe the elements show up in my app too.
While looking for a solution, I found this SO post, that OP had more or less the same issue. An answer suggested to use:
SystemParametersInfo( SPI_SETSCREENREADER, TRUE, NULL, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
PostMessage( HWND_BROADCAST, WM_WININICHANGE, SPI_SETSCREENREADER, 0);
I implemented that as:
[DllImport("user32.dll", SetLastError = true)]
static extern bool SystemParametersInfo(int uiAction, int uiParam, IntPtr pvParam, int fWinIni);
[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
....
const int SPI_SETSCREENREADER = 0x0047;
IntPtr inptrnull = IntPtr.Zero;
const int SPIF_UPDATEINIFILE = 0x01;
const int SPIF_SENDCHANGE = 0x02;
IntPtr HWND_BROADCAST = new IntPtr(0xffff);
const int WM_WININICHANGE = 0x001A;
SystemParametersInfo(SPI_SETSCREENREADER, 1, inptrnull, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
PostMessage(HWND_BROADCAST, WM_WININICHANGE, SPI_SETSCREENREADER, 0);
But it has no effect.
What am I missing? Is there a other/better way to this?
解决方案
Looks like you're using an obsolete managed UIA implementation (System.Windows.Automation). It's a known case when it could return not all of the children, it might be the cause.
As per the documentation:
For Windows 7, the API has been rewritten in the Component Object Model (COM). Although the library functions introduced in the earlier version of UI Automation are still documented, they should not be used in new applications.
You might try to use UIA COM interface instead (Inspect uses the same approach):
Add a reference to COM -> UIAutomationClient to your project. This will generate a wrapper for you, so the COM interface will be accessible in the code in a usual OO-style.
Create a UI Automation object and do your stuff with UIA elements:
IUIAutomation automation = new CUIAutomation(); // Start with the root element; you could also get an element from the point or current focus IUIAutomationElement element = automation.GetRootElement(); IUIAutomationElementArray foundElements = element.FindAll(TreeScope.TreeScope_Children, automation.CreateTrueCondition()); for (int i = 0; i < foundElements.Length; i++) { IUIAutomationElement currentElement = foundElements.GetElement(i); // do your stuff with the element: get its properties, etc }
If the above doesn't help, you might try to use RawTreeWalker instead of calling FindAll() to traverse the UI tree:
IUIAutomationTreeWalker walker = automation.RawViewWalker; IUIAutomationElement child = walker.GetFirstChildElement(element); var sibling = walker.GetNextSiblingElement(child); while (sibling != null) { // do your stuff with sibling elements (get their child elements, etc) sibling = walker.GetNextSiblingElement(child); }
I've automated Chrome prevously using UIA and as far as I remember it might respond to UIA calls a bit odd: e.g. sometimes it returns a container element instead of the actual one (button, edit, etc). I resolved this case by doing several attempts until I finally retrieved what expected. What if you call FindAll() several times too?
推荐阅读
- python - Bokeh - 更新滑块的功能
- java - Java 正则表达式表现怪异
- debugging - 如何在 MongooseIM 的 rebar.config 中添加调试器应用程序?
- javascript - 删除多个数组中的唯一重复项并将它们求和 Javascript
- asp.net - ASP.NET Core 2.1 迁移关键字不支持用户 ID
- wolfram-mathematica - 如何使用 Mathematica 解决我的代码中的数值微分和积分?
- android - Android:指定的 AAPT2 可执行文件不存在:在创建应用程序时添加 kotlin 支持后
- c - 两个文件在C程序中各输出一行
- database - 甲骨文,DBMS_SESSION.SET_CONTEXT
- mysql - Mysql重复结果与连接