2010-10-13 6 views
5

Ich habe den Internet Explorer Handle und ich habe die Registerkarte Handle, die ich auswählen möchte.Wie kann ich eine IE Registerkarte von seiner Handle

Wie kann ich diese Registerkarte auswählen?

Ich weiß, wie man eine Registerkarte nach Index (mit IEAccessible) auswählen, aber ich kann nicht den tabIndex aus dem Griff. Der Spy ++ sortiert sie nicht in der richtigen Reihenfolge.

+0

Sie können nicht. Die Tab-Verwaltung ist ein internes IE-Implementierungsdetail, das auf keine unterstützte Weise verfügbar gemacht wird. –

Antwort

9

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.

+1

Tolles Beispiel, vielen Dank. Könnten Sie bitte auch ein Beispiel für die GetAccessibleChildren-Methode angeben? Es fehlt in Ihrem Beispiel. –

+1

Vlad, GetAccessibleChildren ist eine Windows-API-Funktion. Der Code funktioniert perfekt und hat mir sehr geholfen. Eigentlich habe ich den Code nach Delphi portiert. Es gibt jedoch einen kleinen Fehler: "Tab Row" ist lokalisiert. Da ich eine französische Version von IE verwende, musste ich "Tab Row" zu "Onglet Ligne" ändern. Ich frage mich, ob es einen Weg gibt, um dies von woanders zu bekommen, um ein großes Problem für jeden IE zu verursachen, der keine Version ist. – fpiette

Verwandte Themen