如何从其句柄中选择IE选项卡

Gab*_*aby 5 c# internet-explorer

我有Internet Explorer句柄,我有我想要选择的标签句柄.

我该如何选择此标签?

我知道如何通过索引(使用IEAccessible)选择一个选项卡,但我无法从句柄中获取tabIndex.Spy ++不会按顺序对它们进行排序.

Che*_*eso 9

有一个办法 破解办法做到这一点.不支持,并且取决于IE的版本以及操作系统的语言.

在IE实例中,名称为"Tab Row"的控件是包含所有各种选项卡的控件.给定与该事物相对应的IAccessible,很容易枚举子项,并获取选项卡.自动化应用程序可以检查每个选项卡上的URL,然后调用IAccessible.accDoDefaultAction(0),以通过URL激活选项卡.这是基本方法.

但我无法想象如何从SHDocVw.WebBrowserCOM对象直接获取IE实例的"Tab Row"控件,这是一个应用程序的功能SHDocVw.ShellWindowsClass.我尝试了一百万种方式,最后我能找到的最简单的方法就是:获取WebBrowser COM对象,从该对象获取HWND(这实际上是HWND的众多级别"up"),然后遍历在OS HWND层次结构中找到名为"DirectUIHWND"的HWND.从那里,沿着IAccessible树走,找到"Tab Row",然后选择选项卡并调用方法.

这听起来很难听,用这种方式编码也很痛苦.我无法找到一种方法只在HWND中或仅在IAccessible中进行遍历.我不知道为什么我需要同时做这两件事.


在代码中

首先,获取WebBrowser的HWND:

        SHDocVw.WebBrowser ietab = ... ?
        string urlOfTabToActivate = ietab.LocationURL;
        IntPtr hwnd = (IntPtr) ietab.HWND;
Run Code Online (Sandbox Code Playgroud)

然后获取控制WebBrowser的IE实例中的DirectUI事物的HWND:

        var directUi = GetDirectUIHWND(hwnd);
Run Code Online (Sandbox Code Playgroud)

这是hacky部分.该GetDirectUIHWND方法定义如下:

    private static IntPtr GetDirectUIHWND(IntPtr ieFrame)
    {
        // try IE 9 first:
        IntPtr intptr = FindWindowEx(ieFrame, IntPtr.Zero, "WorkerW", null);
        if (intptr == IntPtr.Zero)
        {
            // IE8 and IE7
            intptr = FindWindowEx(ieFrame, IntPtr.Zero, "CommandBarClass", null);
        }
        intptr = FindWindowEx(intptr, IntPtr.Zero, "ReBarWindow32", null);
        intptr = FindWindowEx(intptr, IntPtr.Zero, "TabBandClass", null);
        intptr = FindWindowEx(intptr, IntPtr.Zero, "DirectUIHWND", null);
        return intptr;
    }
Run Code Online (Sandbox Code Playgroud)

... FindWindowEx是一个dllimport:

    [DllImport("user32.dll", SetLastError = true)]
    private static extern IntPtr FindWindowEx(IntPtr hwndParent,
                                              IntPtr hwndChildAfter,
                                              string lpszClass,
                                              string lpszWindow);
Run Code Online (Sandbox Code Playgroud)

然后,获取该DirectUI事件的IAccessible:

        var iacc = AccessibleObjectFromWindow(directUi);
Run Code Online (Sandbox Code Playgroud)

...当然,AccessibleObjectFromWindow是一个DllImport,它周围有一些魔力:

    [DllImport("oleacc.dll")]
    internal static extern int AccessibleObjectFromWindow
        (IntPtr hwnd, uint id, ref Guid iid,
         [In, Out, MarshalAs(UnmanagedType.IUnknown)] ref object ppvObject);


    private static IAccessible AccessibleObjectFromWindow(IntPtr hwnd)
    {
        Guid guid = new Guid("{618736e0-3c3d-11cf-810c-00aa00389b71}"); // IAccessible
        object obj = null;
        uint id = 0U;
        int num = AccessibleObjectFromWindow(hwnd, id, ref guid, ref obj);
        var acc = obj as IAccessible;
        return acc;
    }
Run Code Online (Sandbox Code Playgroud)

好的,然后,沿着IAccessible树走,找到"Tab Row".在IE中,这是显示各种浏览器窗口的所有选项卡的东西.

        var tabRow = FindAccessibleDescendant(iacc, "Tab Row");
Run Code Online (Sandbox Code Playgroud)

......那个方法是:

    private static IAccessible FindAccessibleDescendant(IAccessible parent, String strName)
    {
        int c = parent.accChildCount;
        if (c == 0)
            return null;

        var children = AccChildren(parent);

        foreach (var child in children)
        {
            if (child == null) continue;
            if (strName.Equals(child.get_accName(0)))
                return child;

            var x = FindAccessibleDescendant(child, strName);
            if (x!=null) return x;
        }

        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

和...

    private static List<IAccessible> AccChildren(IAccessible accessible)
    {
        object[] res = GetAccessibleChildren(accessible);
        var list = new List<IAccessible>();
        if (res == null) return list;

        foreach (object obj in res)
        {
            IAccessible acc = obj as IAccessible;
            if (acc != null) list.Add(acc);
        }
        return list;
    }
Run Code Online (Sandbox Code Playgroud)

然后,在THAT中获取IAccessible,然后单击它:

        var tabs = AccChildren(tabRow);
        int tc = tabs.Count;
        int k = 0;

        // walk through the tabs and tick the chosen one
        foreach (var candidateTab in tabs)
        {
            k++;
            // the last tab is "New Tab", which we don't want
            if (k == tc) continue;

            // the URL on *this* tab
            string localUrl = UrlForTab(candidateTab);

            // same? if so, tick it. This selects the given tab among all
            // the others, if any.
            if (urlOfTabToActivate != null
                && localUrl.Equals(urlOfTabToActivate))
            {
                candidateTab.accDoDefaultAction(0);
                return;
            }
        }
Run Code Online (Sandbox Code Playgroud)

....在哪里UrlForTab....

    private static string UrlForTab(IAccessible tab)
    {
        try
        {
            var desc = tab.get_accDescription(0);
            if (desc != null)
            {
                if (desc.Contains("\n"))
                {
                    string url = desc.Substring(desc.IndexOf("\n")).Trim();
                    return url;
                }
                else
                {
                    return desc;
                }
            }
        }
        catch { }
        return "??";
    }
Run Code Online (Sandbox Code Playgroud)

呼.我找不到更清洁,更简单的方法来做到这一点.