我正在尝试编写一个控制台应用程序,该应用程序将在Windows 10上任何打开的程序中导航AutomationElement树。我的应用程序实际上与我尝试过的每个打开的程序都能很好地工作...除了Chrome。 Chrome的某些安装有效,但有些则无效。差异似乎没有任何可辨别的原因。我在这篇博客文章中发现作者在其中解释说Chrome的AutomationElement树不可访问,并提供C#代码使其可访问。想通了,我会尝试的。
我必须重写大量的函数才能编译和运行它,如下所示(通过将我的代码与博客文章进行比较)。
public static void GetIAccessible2(int pid)
{
Guid guid = new Guid("618736E0-3C3D-11CF-810C-00AA00389B71");
Process proc = Process.GetProcessById(pid);
IntPtr hwnd = proc.MainWindowHandle;
IntPtr ptrToObj = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(Guid)));
uint OBJECT_ID = 0xFFFFFFFC; // client: 0xFFFFFFFC window: 0x00000000
object accessibleObject = new object();
int retAcc = Win32.AccessibleObjectFromWindow(hwnd, OBJECT_ID, ref guid, ref accessibleObject);
IntPtr accessibleObjectPointer = Marshal.GetIUnknownForObject(accessibleObject);
Guid iAccessibleGuid = new Guid(0x618736e0, 0x3c3d, 0x11cf, 0x81, 0xc, 0x0, 0xaa, 0x0, 0x38, 0x9b, 0x71);
IntPtr iAccessiblePtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(Guid)));
Guid iAccServiceProvider = new Guid("6d5140c1-7436-11ce-8034-00aa006009fa");
int retQuery = Marshal.QueryInterface(
accessibleObjectPointer,
ref iAccServiceProvider,
out iAccessiblePtr
);
Accessibility.IAccessible acc = (Accessibility.IAccessible)Marshal.GetTypedObjectForIUnknown(iAccessiblePtr, typeof(Accessibility.IAccessible));
IntPtr ppvObjectPointer = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(IntPtr)));
Win32.IServiceProvider serviceProvider = (Win32.IServiceProvider)acc;
Guid IID_IAccessible2 = new Guid(0xE89F726E, 0xC4F4, 0x4c19, 0xbb, 0x19, 0xb6, 0x47, 0xd7, 0xfa, 0x84, 0x78);
try
{
// This throws an error
// "interface not registered" error
serviceProvider.QueryService(ref IID_IAccessible2, ref IID_IAccessible2, out ppvObjectPointer);
}
catch (Exception er)
{
// Console.WriteLine(er.Message);
// "interface not registered" error
}
Marshal.FinalReleaseComObject(serviceProvider);
Marshal.FreeCoTaskMem(ppvObjectPointer);
Marshal.FreeCoTaskMem(accessibleObjectPointer);
Marshal.FinalReleaseComObject(acc);
proc = null;
acc = null;
}
我还必须创建他从头引用的Win32
类,因为该博客文章没有解释它的含义或来源。我发现以下两个链接对重新创建Win32
类很有帮助。
签名似乎是正确的,所以我认为我走在正确的轨道上。这是我的课。
public class Win32
{
[DllImport("oleacc.dll")]
internal static extern int AccessibleObjectFromWindow(
IntPtr hwnd,
uint id,
ref Guid iid,
[In, Out, MarshalAs(UnmanagedType.IUnknown)] ref object ppvObject);
[ComImport]
[Guid("6d5140c1-7436-11ce-8034-00aa006009fa")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IServiceProvider
{
void QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject);
}
}
我遇到的问题是我的try-catch
函数的GetIAccessible2()
中。到那时为止,一切似乎都运行良好。但是在那行上,我调用QueryService()
函数时,出现错误“接口未注册”。它并没有告诉我未注册什么接口,也没有如何注册。
坦率地说,这段代码中的大部分对我来说都是很神秘的,我惊讶地发现我已经走到了尽头。但是,我需要它才能真正起作用,并且还没有。
未注册什么接口,我该如何注册?
我将非常感谢您能提供的任何帮助(最好是简单的英语,提供所需的任何代码)!
谢谢!
[编辑]
我修复了我的错误。但是,我不确定它是否能修复Chrome。这是我为感兴趣的各方准备的新代码。
// Moved this into the Program class with the function.
// https://github.com/jongund/wpt-atta-msaa-iaccessible2-csharp/blob/master/beizhang/TestAdapterConsole/TestAdapterConsole/Program.cs
[DllImport("oleacc.dll")]
public static extern int AccessibleObjectFromWindow(IntPtr hwnd, uint dwObjectID, byte[] refID, out IntPtr pcObtained);
// Here is my new function
private static string GetChromeTitle()
{
// Chrome must be already open when this runs.
// https://github.com/jongund/wpt-atta-msaa-iaccessible2-csharp/blob/master/beizhang/TestAdapterConsole/TestAdapterConsole/Program.cs
// https://lukecodesit.galamdring.com/2018/04/uiautomation-and-chrome-enabling-via.html
Guid guid = new Guid("618736E0-3C3D-11CF-810C-00AA00389B71");
Guid guidIDispatch = Guid.NewGuid();
Process[] arrProcs = Process.GetProcessesByName("chrome");
foreach (Process chromeProc in arrProcs)
{
try
{
IntPtr ptrHwnd = chromeProc.MainWindowHandle;
IntPtr procbook = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(Guid)));
IntPtr procbookp = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(IntPtr)));
uint u = 0x00000000;
AccessibleObjectFromWindow(ptrHwnd, u, guid.ToByteArray(), out procbookp);
procbook = Marshal.ReadIntPtr(procbookp);
IntPtr iAccessiblePtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(Guid)));
Guid iAccessibleGuid = new Guid("6d5140c1-7436-11ce-8034-00aa006009fa");
Marshal.QueryInterface(procbookp, ref iAccessibleGuid, out iAccessiblePtr);
Accessibility.IAccessible acc = (Accessibility.IAccessible)Marshal.GetTypedObjectForIUnknown(iAccessiblePtr, typeof(Accessibility.IAccessible));
string sName = acc.get_accName();
IntPtr ppvObjectPointer = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(IntPtr)));
// https://docs.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.ole.interop.iserviceprovider.queryservice?view=visualstudiosdk-2017
Microsoft.VisualStudio.OLE.Interop.IServiceProvider iProvider = (Microsoft.VisualStudio.OLE.Interop.IServiceProvider)acc;
Guid IID_IAccessible2 = new Guid(0xE89F726E, 0xC4F4, 0x4c19, 0xbb, 0x19, 0xb6, 0x47, 0xd7, 0xfa, 0x84, 0x78);
iProvider.QueryService(ref IID_IAccessible2, ref IID_IAccessible2, out ppvObjectPointer);
return sName;
}
catch(Exception er)
{
Console.WriteLine(er.Message);
}
}
return string.Empty;
}