2

I am trying to get a list of all the open IE tab titles or search for a specific tab title.

I've been using this but does not work for every tab for some reason:

// Get a handle to an application window.
    [DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
    public static extern IntPtr FindWindow(string lpClassName,
        string lpWindowName);

IntPtr explorerHandle = FindWindow("IEFrame", "Google - Internet Explorer");

        // Verify that we found the Window.
        if (explorerHandle == IntPtr.Zero)
        {
            MessageBox.Show("Didn't find an instance of IE");
            return;
        }

I am particularly looking for tabs which have "This page can’t be displayed" in the title.

Any suggestions?

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
sd_dracula
  • 3,796
  • 28
  • 87
  • 158

1 Answers1

3

The last time I needed to do something like that I used this code: (It's working !)

    [DllImport("user32.Dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool EnumChildWindows(IntPtr parentHandle, Win32Callback callback, IntPtr lParam);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    static public extern IntPtr GetClassName(IntPtr hWnd, System.Text.StringBuilder lpClassName, int nMaxCount);

    [DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
    public static extern IntPtr FindWindow(string lpClassName,
      string lpWindowName);

    public delegate bool Win32Callback(IntPtr hwnd, IntPtr lParam);
    private static bool EnumWindow(IntPtr handle, IntPtr pointer)
    {
        GCHandle gch = GCHandle.FromIntPtr(pointer);
        List<IntPtr> list = gch.Target as List<IntPtr>;
        if (list == null)
            throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
        list.Add(handle);
        return true;
    }
    public static List<IntPtr> GetChildWindows(IntPtr parent)
    {
        List<IntPtr> result = new List<IntPtr>();
        GCHandle listHandle = GCHandle.Alloc(result);
        try
        {
            Win32Callback childProc = new Win32Callback(EnumWindow);
            EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
        }
        finally
        {
            if (listHandle.IsAllocated)
                listHandle.Free();
        }
        return result;
    }
    public static string GetWinClass(IntPtr hwnd)
    {
        if (hwnd == IntPtr.Zero)
            return null;
        StringBuilder classname = new StringBuilder(100);
        IntPtr result = GetClassName(hwnd, classname, classname.Capacity);
        if (result != IntPtr.Zero)
            return classname.ToString();
        return null;
    }
    public static IEnumerable<IntPtr> EnumAllWindows(IntPtr hwnd, string childClassName)
    {
        List<IntPtr> children = GetChildWindows(hwnd);
        if (children == null)
            yield break;
        foreach (IntPtr child in children)
        {
            if (GetWinClass(child) == childClassName)
                yield return child;
            foreach (var childchild in EnumAllWindows(child, childClassName))
                yield return childchild;
        }
    }

And to use it :

  IntPtr handle = FindWindow("IEFrame", "Google");
  var hwndChilds = EnumAllWindows(handle, "Frame Tab");

hwndChilds is a list of IntPtr to all of Frame Tab.

EDIT : I complete my answer with the next steps to get the title of your tabs.

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, [Out] StringBuilder lParam);

    [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
    public static extern IntPtr GetParent(IntPtr hWnd);


    public static string GetWindowTextRaw(IntPtr hwnd)
        {
            uint WM_GETTEXT = 0x000D;
            uint WM_GETTEXTLENGTH = 0x000E;
            // Allocate correct string length first
            int length = (int)SendMessage(hwnd, WM_GETTEXTLENGTH, IntPtr.Zero, null);
            StringBuilder sb = new StringBuilder(length + 1);
            SendMessage(hwnd, WM_GETTEXT, (IntPtr)sb.Capacity, sb);
            return sb.ToString();
        }

You can test it with :

  static void Main(string[] args)
  {
        IntPtr handle = FindWindow("IEFrame", "Google");
        var hwndChild = EnumAllWindows(handle, "Frame Tab");
        foreach (var intPtr in hwndChild)
        {
            var ptr = GetParent(intPtr);
            var text = GetWindowTextRaw(ptr);
            Console.WriteLine(text);
        }
        Console.ReadLine();        
  }

and the result :

enter image description here

If you need more explanations don't hesitate to ask. You can find all pInvoke signatures on http://www.pinvoke.net/

Have a great day !

Quentin Roger
  • 6,410
  • 2
  • 23
  • 36
  • It didn't quite work for me. I had 8 tabs open, 3 of them google and the Bing one was the primary focus. It gave me the following output: `Bing - Internet Explorer Bing - Internet Explorer Bing - Internet Explorer Bing - Internet Explorer Bing - Internet Explorer Bing - Internet Explorer Bing - Internet Explorer Bing - Internet Explorer` .What if I simply want to scan through each tab title and not look for one in particular? – sd_dracula Jun 10 '16 at 14:32
  • I tested it on windows 7 seven and IE 11. I ll try on win 10 – Quentin Roger Jun 10 '16 at 15:51