当ブログでは、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」を使うことをお薦めします。


















この記事へのコメントはありません。