C # - Какой интерфейс не зарегистрирован и как мне его зарегистрировать? - PullRequest
1 голос
/ 05 июня 2019

Я пытаюсь написать консольное приложение, которое будет перемещаться по дереву AutomationElement в любой открытой программе в Windows 10. Мое приложение отлично работает с любой открытой программой, которую я пробовал ... за исключением 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(), я получаю сообщение об ошибке «интерфейс не зарегистрирован».Он не говорит мне, какой интерфейс не зарегистрирован, и как его зарегистрировать.

Честно говоря, большая часть этого кода довольно загадочна для меня, и я удивлен, что дошел до того, чтоиметь.Тем не менее, мне нужно, чтобы он действительно работал, а он пока не работает.

Какой интерфейс не зарегистрирован, и как мне его зарегистрировать?

Я бы хотелочень ценю любую помощь (желательно на простом английском языке, с любым необходимым кодом), которую вы можете предложить!

Заранее спасибо!

[EDIT]

Я исправил ошибку, которую яимел.Однако я не уверен, что это исправило 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;
}
...