Es gibt eine
Weg
hack
Weg, es zu tun. Nicht unterstützt und abhängig von der Version von IE sowie der Sprache des Betriebssystems.
In einer IE-Instanz ist das Steuerelement mit dem Namen "Tab Row" die Sache, die alle verschiedenen Registerkarten enthält. Angesichts einer IAccessible entsprechend dieser Sache, ist es einfach, die Kinder, aufzuzählen und die Registerkarten zu erhalten. Eine Automatisierungs-App kann die URL auf jeder Registerkarte überprüfen und dann IAccessible.accDoDefaultAction(0)
aufrufen, um eine Registerkarte per URL zu aktivieren. Das ist der grundlegende Ansatz.
Aber ich konnte nicht verstehen, wie direkt die „Tab Row“ Steuer eine IE-Instanz erhalten, von einem SHDocVw.WebBrowser
COM-Objekt, das ist was eine App aus SHDocVw.ShellWindowsClass
bekommt. Ich versuchte es ein Millionen Wege, und schließlich der einfachste Weg, ich könnte zum Arbeiten finden, ist dies: Holen Sie sich das WebBrowser COM-Objekt, erhalten Sie die HWND von diesem Objekt (das ist wirklich die HWND zahlreiche Ebenen "nach oben") , dann durchlaufen Sie die OS HWND-Hierarchie, um den HWND mit dem Namen "DirectUIHWND" zu finden. Gehen Sie von dort aus den Baum IAccessible , um die "Tab Row" zu finden, wählen Sie dann die Registerkarte und rufen Sie die Methode auf.
Es klingt hässlich zu beschreiben, und es tat weh, es so zu kodieren. I konnte einen Weg, die Traversierung nur in HWNDs oder nur in IAccessible tun. Ich habe keine Ahnung, warum ich beides machen musste.
In-Code
Zuerst das HWND des Web-Browsers erhalten:
SHDocVw.WebBrowser ietab = ... ?
string urlOfTabToActivate = ietab.LocationURL;
IntPtr hwnd = (IntPtr) ietab.HWND;
Dann das HWND der DirectUI Sache in der IE-Instanz erhalten, dass WebBrowser-Kontrollen:
var directUi = GetDirectUIHWND(hwnd);
Dies ist der Hacky-Teil. Die GetDirectUIHWND
Methode ist wie folgt definiert:
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;
}
... wo FindWindowEx ein Dllimport ist:
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindowEx(IntPtr hwndParent,
IntPtr hwndChildAfter,
string lpszClass,
string lpszWindow);
Dann die IAccessible für das DirectUI Ding:
var iacc = AccessibleObjectFromWindow(directUi);
.. .wo, ist natürlich AccessibleObjectFromWindow ein DllImport, mit etwas Magie um ihn herum:
[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;
}
Ok, dann, Sie gehen den IAccessible Baum, die "Tab Row" zu finden. In IE werden alle Registerkarten für die verschiedenen Browserfenster angezeigt.
var tabRow = FindAccessibleDescendant(iacc, "Tab Row");
... wo diese Methode ist:
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;
}
}
Und ...
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;
}
Dann innerhalb, dass die IAccessible erhalten, und klicken Sie darauf:
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;
}
}
.... wo UrlForTab
ist ....
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 "??";
}
Puh. Ich könnte keinen saubereren, einfacheren Weg finden, dies zu tun.
Sie können nicht. Die Tab-Verwaltung ist ein internes IE-Implementierungsdetail, das auf keine unterstützte Weise verfügbar gemacht wird. –