none
VisualStudio2013: C# IE11(複数タブ状態)において表示されているタブのタイトルやURL情報を取得する方法は? RRS feed

  • 質問

  • お世話になります。 C# にてアクティブなウィンドウのタイトルやプロセスIDなどの情報をタイマーイベントを利用して逐次ファイルに出力するツールを作成しています。
    その中で InternetExplorer、IE11(複数タブ表示中)の場合、複数タブ中の表示されているウィンドウのタイトルや URL情報を取得したいのですが可能でしょうか?
    複数タブの全てのタブの情報を取得するようなサンプルは見つかりましたが表示中のタブだけとなると、どのタブなのか(左から何番目など?)を認識する必要がありますが、
    この部分のやり方がわかりません。 参考になるような情報/サンプルなどございましたら、ご教示の程よろしくお願い致します。

    2016年12月12日 6:28

回答

  • こんな?

    using System;
    using System.Collections.Generic;
    using System.Runtime.InteropServices;
    using System.Windows.Automation; //UIAutomationClient.dllとUIAutomationTypes.dllを参照
    using SHDocVw; //Microsoft Internet Controlsを参照
    using mshtml; //Microsoft HTML Object Libraryを参照
    
    namespace ConsoleApplication1
    {
        class Program
        {
            [STAThread()]
            static void Main(string[] args)
            {
                var allIE = GetAllIEWindows();
    
                foreach (IntPtr hwnd in allIE.Keys)
                {
                    Console.WriteLine("****************************");
                    Console.ForegroundColor = ConsoleColor.Green;
                    Console.WriteLine("HWND={0:X}", hwnd);
                    foreach (Item item in allIE[hwnd])
                    {
                        if (item.IsActive)
                        {
                            Console.ForegroundColor = ConsoleColor.Red;
                        }
                        else
                        {
                            Console.ForegroundColor = ConsoleColor.White;
                        }
    
                        Console.WriteLine("{0}\t{1}", item.Title, item.URL);
    
                    }
                    Console.ForegroundColor = ConsoleColor.White;
                    Console.WriteLine();
                }
                Console.ReadKey();
            }
    
            [ComImport]
            [Guid("6d5140c1-7436-11ce-8034-00aa006009fa")]
            [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
            interface IServiceProvider
            {
                void QueryService(ref Guid guidService, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out object obj);
            }
    
            private enum SendMessageTimeoutFlags : uint
            {
                SMTO_NORMAL = 0x0000,
                SMTO_BLOCK = 0x0001,
                SMTO_ABORTIFHUNG = 0x0002,
                SMTO_NOTIMEOUTIFNOTHUNG = 0x0008,
                SMTO_ERRORONEXIT = 0x0020
            }
    
            [DllImport("user32.dll")]
            public static extern uint RegisterWindowMessage(string lpString);
            [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
            private static extern IntPtr SendMessageTimeout(IntPtr windowHandle, uint Msg, IntPtr wParam, IntPtr lParam, SendMessageTimeoutFlags flags, uint timeout, out IntPtr result);
            [DllImport("oleacc.dll", PreserveSig = false)]
            [return: MarshalAs(UnmanagedType.Interface)]
            private static extern object ObjectFromLresult(IntPtr lResult, [MarshalAs(UnmanagedType.LPStruct)] Guid refiid, IntPtr wParam);
    
            class Item
            {
                public Item(SHDocVw.IWebBrowser2 browser)
                {
                    this.Title = browser.LocationName;
                    this.URL = browser.LocationURL;
                    this.ComPtr = Marshal.GetIUnknownForObject(browser);
                }
                public string Title { get; private set; }
                public string URL { get; private set; }
                public bool IsActive { get; set; }
    
                public IntPtr ComPtr { get; private set; }
    
                public bool IsSameBrowser(SHDocVw.IWebBrowser2 browser)
                {
                    return this.ComPtr == Marshal.GetIUnknownForObject(browser);
                }
    
                public override string ToString()
                {
                    return Title + "\t" + URL;
                }
            }
    
    
    
            /// <summary>全てのIEで表示されているページ情報を取得<summary>
            /// <returns></returns>
            private static Dictionary<IntPtr, List<Item>> GetAllIEWindows()
            {
                Dictionary<IntPtr, List<Item>> dic = new Dictionary<IntPtr, List<Item>>();
                SHDocVw.ShellWindows windows = new SHDocVw.ShellWindows();
                try
                {
                    foreach (dynamic w in windows)
                    {
                        try
                        {
                            SHDocVw.IWebBrowser2 webBrowser2 = w as SHDocVw.IWebBrowser2;
                            if (string.Equals(System.IO.Path.GetFileName(webBrowser2.FullName), "iexplore.exe", StringComparison.InvariantCultureIgnoreCase))
                            {
                                Item item = new Item(webBrowser2);
                                IntPtr hwnd = new IntPtr(webBrowser2.HWND);
    
                                List<Item> list;
                                if (!dic.TryGetValue(hwnd, out list))
                                {
                                    list = new List<Item>();
                                    dic.Add(hwnd, list);
                                }
                                list.Add(item);
                            }
                        }
                        finally
                        {
                            Marshal.ReleaseComObject(w);
                        }
                    }
    
                    foreach (IntPtr hwndWindow in dic.Keys)
                    {
    
                        var browser = GetBrowser(hwndWindow);
                        if (browser != null)
                        {
                            foreach (Item item in dic[hwndWindow])
                            {
                                item.IsActive = item.IsSameBrowser(browser);//現在アクティブタブで表示されているか
                            }
    
                            Marshal.ReleaseComObject(browser);
                        }
                    }
                }
                finally
                {
                    Marshal.ReleaseComObject(windows);
                }
                return dic;
            }
    
            private static uint WM_HTML_GETOBJECT = RegisterWindowMessage("WM_HTML_GETOBJECT");
    
            /// <summary>IEのウィンドウに現在表示されているページを表示しているWebBrowserを取得</summary>
            private static SHDocVw.IWebBrowser2 GetBrowser(IntPtr hwndWindow)
            {
                if (WM_HTML_GETOBJECT != 0)
                {
                    //IEの表示しているWebBrowerのハンドルを調べる(EnumChildWindowで掘ってもいいです)
                    var root = System.Windows.Automation.AutomationElement.FromHandle(hwndWindow);
                    var conditionServer = new PropertyCondition(AutomationElement.ClassNameProperty, "Internet Explorer_Server");
                    var server = root.FindFirst(TreeScope.Subtree, conditionServer);
                    var hwndServer = new IntPtr((int)server.GetCurrentPropertyValue(AutomationElement.NativeWindowHandleProperty, false));
    
                    //ハンドルからIHtmlDocumentを取得
                    IntPtr lRes;
                    SendMessageTimeout(hwndServer, WM_HTML_GETOBJECT, IntPtr.Zero, IntPtr.Zero, SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, 1000, out lRes);
                    if (lRes != IntPtr.Zero)
                    {
                        var obj = ObjectFromLresult(lRes, typeof(mshtml.IHTMLDocument).GUID, IntPtr.Zero);
                        var doc = obj as mshtml.IHTMLDocument2;
                        try
                        {
                            //IHTMLDocumentからIWebBrowser2を取得
                            var ww = doc.parentWindow as mshtml.IHTMLWindow2;
                            var isp = ww as IServiceProvider;
                            if (isp != null)
                            {
                                object obj2;
                                Guid guidApp = typeof(SHDocVw.IWebBrowserApp).GUID;
                                Guid guidWB = typeof(SHDocVw.IWebBrowser2).GUID;
                                isp.QueryService(ref guidApp, ref guidWB, out obj2);
                                var wb2 = obj2 as SHDocVw.IWebBrowser2;
                                return wb2;
                            }
                        }
                        finally
                        {
                            Marshal.ReleaseComObject(doc);
                        }
                    }
                }
                return null;
            }
        }
    }
    #UIAutomationで選択タブまで行けたと思ったらOSによっては取れなかった…

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2016年12月12日 13:38

すべての返信

  • こんな?

    using System;
    using System.Collections.Generic;
    using System.Runtime.InteropServices;
    using System.Windows.Automation; //UIAutomationClient.dllとUIAutomationTypes.dllを参照
    using SHDocVw; //Microsoft Internet Controlsを参照
    using mshtml; //Microsoft HTML Object Libraryを参照
    
    namespace ConsoleApplication1
    {
        class Program
        {
            [STAThread()]
            static void Main(string[] args)
            {
                var allIE = GetAllIEWindows();
    
                foreach (IntPtr hwnd in allIE.Keys)
                {
                    Console.WriteLine("****************************");
                    Console.ForegroundColor = ConsoleColor.Green;
                    Console.WriteLine("HWND={0:X}", hwnd);
                    foreach (Item item in allIE[hwnd])
                    {
                        if (item.IsActive)
                        {
                            Console.ForegroundColor = ConsoleColor.Red;
                        }
                        else
                        {
                            Console.ForegroundColor = ConsoleColor.White;
                        }
    
                        Console.WriteLine("{0}\t{1}", item.Title, item.URL);
    
                    }
                    Console.ForegroundColor = ConsoleColor.White;
                    Console.WriteLine();
                }
                Console.ReadKey();
            }
    
            [ComImport]
            [Guid("6d5140c1-7436-11ce-8034-00aa006009fa")]
            [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
            interface IServiceProvider
            {
                void QueryService(ref Guid guidService, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out object obj);
            }
    
            private enum SendMessageTimeoutFlags : uint
            {
                SMTO_NORMAL = 0x0000,
                SMTO_BLOCK = 0x0001,
                SMTO_ABORTIFHUNG = 0x0002,
                SMTO_NOTIMEOUTIFNOTHUNG = 0x0008,
                SMTO_ERRORONEXIT = 0x0020
            }
    
            [DllImport("user32.dll")]
            public static extern uint RegisterWindowMessage(string lpString);
            [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
            private static extern IntPtr SendMessageTimeout(IntPtr windowHandle, uint Msg, IntPtr wParam, IntPtr lParam, SendMessageTimeoutFlags flags, uint timeout, out IntPtr result);
            [DllImport("oleacc.dll", PreserveSig = false)]
            [return: MarshalAs(UnmanagedType.Interface)]
            private static extern object ObjectFromLresult(IntPtr lResult, [MarshalAs(UnmanagedType.LPStruct)] Guid refiid, IntPtr wParam);
    
            class Item
            {
                public Item(SHDocVw.IWebBrowser2 browser)
                {
                    this.Title = browser.LocationName;
                    this.URL = browser.LocationURL;
                    this.ComPtr = Marshal.GetIUnknownForObject(browser);
                }
                public string Title { get; private set; }
                public string URL { get; private set; }
                public bool IsActive { get; set; }
    
                public IntPtr ComPtr { get; private set; }
    
                public bool IsSameBrowser(SHDocVw.IWebBrowser2 browser)
                {
                    return this.ComPtr == Marshal.GetIUnknownForObject(browser);
                }
    
                public override string ToString()
                {
                    return Title + "\t" + URL;
                }
            }
    
    
    
            /// <summary>全てのIEで表示されているページ情報を取得<summary>
            /// <returns></returns>
            private static Dictionary<IntPtr, List<Item>> GetAllIEWindows()
            {
                Dictionary<IntPtr, List<Item>> dic = new Dictionary<IntPtr, List<Item>>();
                SHDocVw.ShellWindows windows = new SHDocVw.ShellWindows();
                try
                {
                    foreach (dynamic w in windows)
                    {
                        try
                        {
                            SHDocVw.IWebBrowser2 webBrowser2 = w as SHDocVw.IWebBrowser2;
                            if (string.Equals(System.IO.Path.GetFileName(webBrowser2.FullName), "iexplore.exe", StringComparison.InvariantCultureIgnoreCase))
                            {
                                Item item = new Item(webBrowser2);
                                IntPtr hwnd = new IntPtr(webBrowser2.HWND);
    
                                List<Item> list;
                                if (!dic.TryGetValue(hwnd, out list))
                                {
                                    list = new List<Item>();
                                    dic.Add(hwnd, list);
                                }
                                list.Add(item);
                            }
                        }
                        finally
                        {
                            Marshal.ReleaseComObject(w);
                        }
                    }
    
                    foreach (IntPtr hwndWindow in dic.Keys)
                    {
    
                        var browser = GetBrowser(hwndWindow);
                        if (browser != null)
                        {
                            foreach (Item item in dic[hwndWindow])
                            {
                                item.IsActive = item.IsSameBrowser(browser);//現在アクティブタブで表示されているか
                            }
    
                            Marshal.ReleaseComObject(browser);
                        }
                    }
                }
                finally
                {
                    Marshal.ReleaseComObject(windows);
                }
                return dic;
            }
    
            private static uint WM_HTML_GETOBJECT = RegisterWindowMessage("WM_HTML_GETOBJECT");
    
            /// <summary>IEのウィンドウに現在表示されているページを表示しているWebBrowserを取得</summary>
            private static SHDocVw.IWebBrowser2 GetBrowser(IntPtr hwndWindow)
            {
                if (WM_HTML_GETOBJECT != 0)
                {
                    //IEの表示しているWebBrowerのハンドルを調べる(EnumChildWindowで掘ってもいいです)
                    var root = System.Windows.Automation.AutomationElement.FromHandle(hwndWindow);
                    var conditionServer = new PropertyCondition(AutomationElement.ClassNameProperty, "Internet Explorer_Server");
                    var server = root.FindFirst(TreeScope.Subtree, conditionServer);
                    var hwndServer = new IntPtr((int)server.GetCurrentPropertyValue(AutomationElement.NativeWindowHandleProperty, false));
    
                    //ハンドルからIHtmlDocumentを取得
                    IntPtr lRes;
                    SendMessageTimeout(hwndServer, WM_HTML_GETOBJECT, IntPtr.Zero, IntPtr.Zero, SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, 1000, out lRes);
                    if (lRes != IntPtr.Zero)
                    {
                        var obj = ObjectFromLresult(lRes, typeof(mshtml.IHTMLDocument).GUID, IntPtr.Zero);
                        var doc = obj as mshtml.IHTMLDocument2;
                        try
                        {
                            //IHTMLDocumentからIWebBrowser2を取得
                            var ww = doc.parentWindow as mshtml.IHTMLWindow2;
                            var isp = ww as IServiceProvider;
                            if (isp != null)
                            {
                                object obj2;
                                Guid guidApp = typeof(SHDocVw.IWebBrowserApp).GUID;
                                Guid guidWB = typeof(SHDocVw.IWebBrowser2).GUID;
                                isp.QueryService(ref guidApp, ref guidWB, out obj2);
                                var wb2 = obj2 as SHDocVw.IWebBrowser2;
                                return wb2;
                            }
                        }
                        finally
                        {
                            Marshal.ReleaseComObject(doc);
                        }
                    }
                }
                return null;
            }
        }
    }
    #UIAutomationで選択タブまで行けたと思ったらOSによっては取れなかった…

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2016年12月12日 13:38
  • gekka 様
    少し間が空き失礼しました。 サンプルのご提供誠にありがとうございました。 (- - )の環境にて稼働を確認しました。
    IEアクティブタブ情報を取得するメソッドがあるものと思っていましたが、これ程長大な処理が必要になるとは驚きです。
    要所に書かれているコメントも内容を理解する上で大変助かります。 重ねてになりますが本当にありがとうございました。


    • 編集済み (-_- ) 2016年12月15日 4:17
    2016年12月15日 4:15