当ブログでは、EdgeからタイトルとURLを取得するコードについて、いくつか記事を書いてきました。
しかし、現時点(2018年8月)ではEdgeのアップデートに伴いこれらの記事にあるコードが動作しなくなっているため、今回コードを書き直すことにしました。
テスト環境
- Microsoft Windows 10 Pro Insider Preview バージョン:10.0.16257 ビルド 16257 64ビット版
- Microsoft.MicrosoftEdge 41.16257.1.0
C#コード
using System; using System.Text; using System.Runtime.InteropServices; namespace GetUrlAndTitleFromEdge { class Program { [Flags] private enum SendMessageTimeoutFlags : uint { SMTO_NORMAL = 0x0000, SMTO_BLOCK = 0x0001, SMTO_ABORTIFHUNG = 0x0002, SMTO_NOTIMEOUTIFNOTHUNG = 0x0008, SMTO_ERRORONEXIT = 0x0020 } private delegate bool Win32Callback(IntPtr hWnd, ref IntPtr lParam); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool EnumWindows(Win32Callback lpEnumFunc, ref IntPtr lParam); [DllImport("user32.dll", SetLastError = true)] private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow); [DllImport("user32.dll", CharSet = CharSet.Auto)] private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); [DllImport("oleacc.dll", PreserveSig=false)] [return: MarshalAs(UnmanagedType.Interface)] private static extern object ObjectFromLresult(UIntPtr lResult, [MarshalAs(UnmanagedType.LPStruct)] Guid refiid, IntPtr wParam); [DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)] private 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 UIntPtr result); public static void Main(string[] args) { IntPtr hWin = IntPtr.Zero; Win32Callback proc = new Win32Callback(EnumWindowsProc); EnumWindows(proc, ref hWin); Console.Write("Press any key to continue . . . "); Console.ReadKey(true); } private static bool EnumWindowsProc(IntPtr hWnd, ref IntPtr lParam) { IntPtr hChild = IntPtr.Zero; StringBuilder buf = new StringBuilder(1024); GetClassName(hWnd, buf, buf.Capacity); if (buf.ToString() == "TabWindowClass") { //get 'Internet Explorer_Server' window hChild = FindWindowEx(hWnd, IntPtr.Zero, "Internet Explorer_Server", ""); if (hChild != IntPtr.Zero) { dynamic doc = null; doc = GetHTMLDocumentFromWindow(hChild); if (doc != null) { Console.WriteLine(doc.Title + ", " + doc.url); //get document title & url } } } return true; } //get HTMLDocument object private static object GetHTMLDocumentFromWindow(IntPtr hWnd) { UIntPtr lRes; object doc = null; Guid IID_IHTMLDocument2 = new Guid("332C4425-26CB-11D0-B483-00C04FD90119"); uint nMsg = RegisterWindowMessage("WM_HTML_GETOBJECT"); if (nMsg != 0) { SendMessageTimeout(hWnd, nMsg, IntPtr.Zero, IntPtr.Zero, SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, 1000, out lRes); if (lRes != UIntPtr.Zero) { doc = ObjectFromLresult(lRes, IID_IHTMLDocument2, IntPtr.Zero); } } return doc; } } }
仕組みは下記記事のVBAマクロと同じで、TabWindowClassクラスのウィンドウを決め打ちして、その下にあるInternet Explorer_ServerクラスのウィンドウからHTMLDocumentを取得しているだけです。
上記記事でも書いていますが、今回の方法はMicrosoftが推奨している方法では無く、いつ使えなくなるかも分からないため、可能であれば正式にサポートされている「WebDriver」を使うことをお薦めします。
この記事へのコメントはありません。