我正在使用AccessibleObjectFromPoint
功能的辅助功能,我希望它能够在每个监视器的DPI环境中正常工作。不幸的是,我无法让它发挥作用。我尝试了很多东西,现在的情况是:
True/PM
)GetCursorPos
然后使用AccessibleObjectFromPoint
。如何重现问题:
AccessibleObjectFromPoint
,它无法正常使用。它适用于某些应用程序(DPI识别,似乎像探险家一样),但不能与其他人一起工作。我尝试了几个相关的功能,例如GetPhysicalCursorPos
和PhysicalToLogicalPointForPerMonitorDPI
,但没有任何作用。
值得注意的是,Microsoft的inspect.exe
按预期工作。
答案 0 :(得分:1)
几周以来,我一直在努力解决这个问题,现在可以告诉你我的发现。不幸的是,我不能给你一些代码,因为我正在研究的项目是专有的。
问题始于Windows 8.1。 Windows 7或Vista上不存在此问题,因为AccessibleObjectFromPoint始终使用原始物理坐标,如下所示:https://msdn.microsoft.com/en-us/library/windows/desktop/dd317984(v=vs.85).aspx。
“Microsoft Active Accessibility不使用逻辑坐标。以下方法和函数要么返回物理坐标,要么将它们作为参数。“自Windows 8.1以来,这种情况并非如此。
AccessibleObjectFromPoint现在使用一个有缺陷的计算,由于与我的问题类似的原因,无法始终找到正确的窗口:High DPI scaling, mouse hooks and WindowFromPoint。 我的发现让我得出一个结论:API被打破了。这并不意味着它不可能。
我已经部分测试的可能解决方案似乎有效。 先决条件是你
1 /。使每个监视器的进程能够识别DPI,而不是使用清单(稍后会详细介绍)。
2 /。确定要查询的窗口的hWnd(WindowFromPoint()变体)
3 /。确定查询的hWnd的监视器DPI
4 /。确定流程的DPI
5 /。确定查询的hWnd的DPI
6 /。确定查询的hWnd的监视器原点和偏移量(MonitorFromWindow()和GetMonitorInfo())
接下来,取决于您的平台
Windows 10.0.14393 +
编写一个从顶层窗口中找到IAccessible(AccessibleObjectFromWindow())的函数,然后递归调用IAccessible :: accHitTest,直到到达最底部的IAccessible和可能的ChildID数据。返回,就好像你会调用AccessibleObjectFromPoint一样。
要成功调用它,您需要使用上面列表中提取的DPI和坐标将(x,y)坐标缩放到查询的hWnd的缩放系统中。注意监视器大小不同或监视器部分偏移,或高于和低于监视器的系统。
现在对于10.0.14393的重要部分 - 将您的线程设置为您正在查询的hWnd的DPI_AWARENESS_CONTEXT。现在打电话给你的新功能。现在还原你的线程以监控DPI意识,瞧,即使窗口没有最大化,它仍然有效。这就是你不能使用清单的原因。
如果您使用Windows 8.1到10.0.10586 ,那么您将面临更艰巨的任务。 如上所述,您不必调用accHitTest,而是必须递归调用AccessibleChildren并迭代调用IAccessible :: accLocation以确定您的测试点是否在每个子节点内。这很棘手,当你到达时,它会变得非常混乱Office等产品中的组合框,只能识别系统DPI。
这就是我现在能给你的全部。
要在多平台上成功完成(我必须从Vista工作到Windows-Current)唯一真正安全的做法是在C ++中编写一个包装器DLL,它可以在运行时确定它所在的操作系统并更改代码路径因此。您希望在C ++中执行此操作的原因是为了避免在.Net /非托管编组边界上传递IAccessible对象。您可以在不需要返回非托管端的对象上调用IUnknown :: Release。你可以在.Net中完成所有操作,但速度很慢。
P.S。还要注意Chrome返回无限的树木,父母是他们父母的孩子,需要进行一些狡猾的检查。此外,Chrome不会正确返回accRole,并且会为您提供HTML标记而不是VT_I4。
祝你好运答案 1 :(得分:0)
在您的IAccessible
递归函数中,一个可行的解决方案如下:
使用getwindowrect
捕获主窗口上的物理权限
在循环中使用accChild.accLocation
捕获每个对象的左侧和宽度
添加此简单测试
If l > rct2r.Right And l > arrIACC.x2 Then
arrIACC.x2 = l + w
End If
if dpi = 100 then no Object is furter out than physical right
if dpi > 100 then closebutton is...x pix offset
使用差异来重新缩放您正在使用的Width的所有值
arrIACC.w1 = CInt(((-rct2r.Left + arrIACC.w1) / arrIACC.x2) * rct2r.Right)
此解决方案来自我开发的Excel插件,我正在测试快速访问工具栏qat的宽度,无论任何DPI,我的结果都是+-5像素。