C#-未注册哪个接口,我该如何注册?

时间:2019-06-05 20:01:46

标签: c# google-chrome microsoft-ui-automation automationelement iaccessible

我正在尝试编写一个控制台应用程序,该应用程序将在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;
}

0 个答案:

没有答案