我有Internet Explorer Handle,我有我想要选择的标签句柄。
如何选择此标签?
我知道如何通过索引(使用IEAccessible)选择选项卡,但我无法从句柄中获取tabIndex。 Spy ++没有按顺序对它们进行排序。
答案 0 :(得分:9)
有一种方式 hack 方式来做到这一点。不支持,并且取决于IE的版本以及操作系统的语言。
在IE实例中,名为“Tab Row”的控件是
包含所有各种标签的东西。鉴于IAccessible
对应那个东西,很容易枚举孩子,
并获取标签。自动化应用程序可以检查每个上的URL
选项卡,然后调用IAccessible.accDoDefaultAction(0)
,以激活
按标签的URL。这是基本方法。
但我无法想象如何直接获得“Tab Row”控件
一个IE实例,来自SHDocVw.WebBrowser
COM对象,它是
应用程序从SHDocVw.ShellWindowsClass
中获取的内容。我试了一下
百万种方式,最后是我能找到的最简单的方法
工作是这样的:获取WebBrowser COM对象,从中获取HWND
对象(实际上是HWND的多个级别“向上”),然后遍历OS HWND层次结构以找到HWND
名称为“DirectUIHWND”。从那里,走下IAccessible
树,找到“Tab Row”,然后选择选项卡并调用
方法
描述起来听起来很丑陋,以这种方式编码也很痛苦。一世 无法找到一种只在HWND中进行遍历的方法 仅在IAccessible中。我不知道为什么我需要这两个。
代码
首先,获取WebBrowser的HWND:
SHDocVw.WebBrowser ietab = ... ?
string urlOfTabToActivate = ietab.LocationURL;
IntPtr hwnd = (IntPtr) ietab.HWND;
然后获取控制WebBrowser的IE实例中的DirectUI事物的HWND:
var directUi = GetDirectUIHWND(hwnd);
这是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;
}
... FindWindowEx是一个dllimport:
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindowEx(IntPtr hwndParent,
IntPtr hwndChildAfter,
string lpszClass,
string lpszWindow);
然后,获取该DirectUI的IAccessible:
var iacc = AccessibleObjectFromWindow(directUi);
...当然,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;
}
好的,然后,沿着IAccessible树走,找到“Tab Row”。在IE中,这是显示各种浏览器窗口的所有选项卡的东西。
var tabRow = FindAccessibleDescendant(iacc, "Tab Row");
......那个方法是:
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;
}
}
和...
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;
}
然后,在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;
}
}
....其中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 "??";
}
呼。我找不到更清洁,更简单的方法来做到这一点。