|
タイトルは IHtmlDocument から HtmlDocument への変換になってますが、"Internet Explorer_Server" から IHtmlDocument2 相当の取得なども含んでます。見かけたサンプルでは、ObjectFromLresult() 関数で mshtml.IHtmlDocument2 への変換をしてしまうのがあったんですが、mshtml への参照をしたくなかった関係から、IDispatch な object への変換です。
そこから、GetTypeFromCLSID() メソッドで取得した型情報を利用して、いつものごとくリフレクションです。
HtmlDocument クラスのコンストラクタは internal なので、外部から呼び出せません。ということで、GetConstructors() メソッドを利用して取得し、Invoke() してます。GetConstructor() メソッドだと、これまた internal な型の引数をどうやって指定すればいいんでしょう?
これで、HtmlDocument クラスのインスタンスが作れた、と思いきや、一部のプロパティ ( Url とか ) は利用できません。リフレクションで直接とか、Window.Url プロパティなら取得できるんですけどね。この辺がダメな理由はちょっとよくわかってません...。
[DllImport("user32.dll",
EntryPoint = "GetClassNameA")]
private static extern int GetClassName(
IntPtr hwnd,
IntPtr lpClassName,
int nMaxCount);
[DllImport("user32.dll")]
private static extern bool EnumChildWindows(
IntPtr hWndParent,
EnumProc lpEnumFunc,
ref IntPtr lParam);
[DllImport("user32.dll",
EntryPoint = "RegisterWindowMessageA")]
private static extern int RegisterWindowMessage(
string lpString);
[DllImport("user32.dll",
EntryPoint = "SendMessageTimeoutA")]
private static extern IntPtr SendMessageTimeout(
IntPtr hwnd,
int msg,
IntPtr wParam,
IntPtr lParam,
uint fuFlags,
uint uTimeout,
out IntPtr lpdwResult);
[DllImport("OLEACC.dll")]
private static extern uint ObjectFromLresult(
IntPtr lResult,
ref Guid riid,
IntPtr wParam,
[MarshalAs(UnmanagedType.IDispatch)] ref object ppvObject);
private const int SMTO_ABORTIFHUNG = 0x2;
private Guid IID_IHTMLDocument =
new Guid("626FC520-A41E-11CF-A731-00A0C9082637");
private delegate bool EnumProc(IntPtr hWnd, ref IntPtr lParam);
private void button1_Click(object sender, EventArgs e)
{
Process[] processes;
IntPtr hWnd;
EnumProc proc;
int msg;
IntPtr result;
uint hr;
object doc;
Type t;
string buf;
Type thd;
HtmlDocument hdoc;
ConstructorInfo[] ci;
processes = Process.GetProcessesByName("iexplore");
if (processes.Length == 0)
{
return;
}
hWnd = processes[0].MainWindowHandle;
doc = null;
proc = new EnumProc(EnumChildProc);
EnumChildWindows(hWnd, proc, ref hWnd);
if (hWnd.Equals(IntPtr.Zero))
{
return;
}
msg = RegisterWindowMessage("WM_HTML_GETOBJECT");
if (msg == 0)
{
return;
}
SendMessageTimeout(
hWnd,
msg,
IntPtr.Zero,
IntPtr.Zero,
SMTO_ABORTIFHUNG,
1000,
out result);
if (result.Equals(IntPtr.Zero))
{
return;
}
hr = ObjectFromLresult(
result,
ref IID_IHTMLDocument,
IntPtr.Zero,
ref doc);
if (doc == null)
{
return;
}
t = Type.GetTypeFromCLSID(
new System.Guid(
"{626FC520-A41E-11CF-A731-00A0C9082637}"));
buf = t.InvokeMember(
"URL",
BindingFlags.GetProperty,
null,
doc,
null).ToString();
MessageBox.Show(buf, "HtmlDocument.URL");
thd = typeof(HtmlDocument);
ci = thd.GetConstructors(
BindingFlags.NonPublic | BindingFlags.Instance);
hdoc = (HtmlDocument)ci[0].Invoke(
new object[] { null, doc });
buf = hdoc.Window.Url.ToString();
MessageBox.Show(buf, "HtmlDocument.Window.Url");
// Error!
// buf = hdoc.Url.ToString();
}
private bool EnumChildProc(IntPtr hWnd, ref IntPtr lParam)
{
IntPtr p;
string buf;
p = Marshal.AllocHGlobal(256);
GetClassName(hWnd, p, 256);
buf = Marshal.PtrToStringAnsi(p);
Marshal.FreeHGlobal(p);
if (buf == "Internet Explorer_Server")
{
lParam = hWnd;
return false;
}
return true;
}
for Windows 7 な Windows SDK は見あたりませんが、ドキュメント的には、とりあえずリリースごとの API 一覧が参考になりそうです。
あとは、↓あたりの Developers Guide とかでしょうかね。ざっと見ておきたいのは。
Windows Update まで行って、ひととおりの環境構築はできました。実際、こんなもんです。あとは、XKeymacs 辺りなんですが、キーボードのリマップがうまくいきませんでした。おそらく、HKLM ではなくて HKCU を変更しているのが原因のようで。
HKLM で [Caps] -> [Ctrl] リマップする .reg ファイルを拾ってきて、それで OK でした。
とりあえず、Windows 7 RC をインストールして、Windows Update で更新。Windows Vista 辺りから、メーカーが提供するデバイスドライバも Windows Update に出てくるのでいい感じです。環境は、Thinkpad X61 ですが、ひととおりのドライバが入った模様。
その後、Daemon Tools Lite 4.30.4 をインストール。互換性うんぬんで怒られましたが、とりあえず動作的には問題ないようです。あとは、Office 2007、Visual Studio 2008 とインストール。さくさくいきますね。
ゴールデンウィーク直前に、Windows 7 RC の提供が開始されました。最近の Microsoft のリリース状況からすると、RC レベルであれば充分に使えそうな感じです。ということで、さっそく物理環境にインストール。
といいつつ、この記事は Windows Vista の方で書いてます。Emacs 環境の移行も含め、いろいろ試してみようと思います。
|