Browser Helper Objects を作ってみる
2008/10/13 コメントを残す
Browser Helper Objects (BHO) ってどうやって作るの?っていう相談を受けたのでネタにします。
今更 COM かよ!っていう感じもしますが、COM は今でも重要なテクノロジなんですね。
まず、MSDN だと、ここに情報があります。
- Visual Studio 2005 によるブラウザ ヘルパ オブジェクトのビルド
http://msdn.microsoft.com/ja-jp/library/bb250489(vs.85).aspx
この内容に沿って作成すると簡単なサンプルができます。
一緒に作成してみましょう!(ほとんど同じですが、VS 2008 を使ってみます。)
1) プロジェクトのセットアップ
ここで、作成するのは DLL になります。追加のオプションは必要ありません。
BHO は COM クラスになります。IE がホストになって、BHO の COM クラスをホスティングするわけです。
ATL シンプル オブジェクトを選択して、COM クラスを作成します。
ここでのポイントは、IObjectWithSite を選択しておくことです。
すると、VS はいろいろなファイルをジェネレートしてくれます。
なお、IObjectWithSite インターフェースについては、この辺をどうぞ。
- IObjectWithSite Interfase
http://msdn.microsoft.com/en-us/library/aa768220(VS.85).aspx
2) 基本の実装
ここでは、記載されている通りに進めてください。
HelloWorldBHO.h (記事の通りに)
HelloWorldBHO.cpp (記事の通りに)
ATL で作っているので、普通に CComPtr クラスを使っていますね。スマートポインタは偉大です。
なお、HelloWorld.cpp で DllMain にコードを追加していますが、
VS 2008 では、DllMain は dllmain.cpp という別のファイルに生成されますので注意してください。
3) BHO の登録
BHO は COM であるため、レジストリ登録が必要になります。
ここでのポイントは、Windows Explorer から BHO がロードされないようにしていることです。
BHO はそもそも、Internet Explorer と Windows Explorer に対する機能拡張になりますので
IE だけで使おうとなると、少し細工が必要になるわけです。
(*) Windows 2000 で Internet Explorer と Windows Explorer が統合された結果です
ForceRemove で記載している CLSID を間違えないようにしてください。
サイトに記載されている uuid をコピペして、自分で作成している uuid と置き換えないように。
一応、これでビルドができるようになったのですが、IE 動かしてみても何も起こりません。
先に進めてください。
4) イベントへの応答
イベントを処理するには、Invoke メソッドを使います。Invoke メソッドを実際に書いてもいいのですが
今どきの ATL では、BEGIN_SINK_MAP マクロという便利なものがあるんです。
BEGIN_SINK_MAP マクロで DISPID_DOCUMENTCOMPLETE を登録して、OnDocumentComplete メソッドで
実装しています。
ちなみに、BEGIN_SINK_MAP マクロを使わないと
STDMETHODIMP CHelloWorldBHO::Invoke(DISPID dispidMember,
REFIID riid, LCID lcid, WORD wFlags,
DISPPARAMS* pDispParams, VARIANT* pvarResult,
EXCEPINFO* pExcepInfo, UINT* puArgErr)
{
if (!pDispParams)
{
return E_INVALIDARG;
}
switch (dispidMember)
{
case DISPID_DOCUMENTCOMPLETE:
// ここに処理を書く
break;
case DISPID_BEFORENAVIGATE2:
// ここに処理を書く
break;・・・・
}
という巨大な switch 文を作成しなければなりません。使えるマクロは、どんどん使った方がよさそうです。
さあ、これで目で見えるような動きになった BHO ができました。
ビルドして IE を起動してみましょう。(テストの再実行 というところです)
こんな感じで記事と同じようにできました。
時間があったら、その後に続く記事の内容もやってみるといいと思います。
IE が発生させるイベントは、ここに記載されています。
- DWebBrowserEvents2 Interface
http://msdn.microsoft.com/en-us/library/aa768283(VS.85).aspx
記事で使っている DISPID_DOCUMENTCOMPLETE というイベントは
- DWebBrowserEvents2::DocumentComplete Event
http://msdn.microsoft.com/en-us/library/aa768282(VS.85).aspx
というもので、HTMLドキュメントのロードが終了したときに発生するイベントです。
Event DISPID に「DISPID_DOCUMENTCOMPLETE」という記述があります。
この DISPID に対して Invoke メソッドを使い、処理するイベントを実装するというわけです。
なお、余談ですが、C# で書くと、こんな感じになります。
using SHDocVw;
using mshtml;
using System.Runtime.InteropServices;namespace BHO_HelloWorld
{
public class WindowWrapper : IWin32Window
{
private IntPtr hWnd;
public WindowWrapper(IntPtr handle)
{
hWnd = handle;
}
public IntPtr Handle
{
get { return hWnd; }
}
}class BHO : IObjectWithSite
{
WebBrowser webBrowser;public void OnDocumentComplete(object pDisp, ref object URL)
{
WindowWrapper owner = new WindowWrapper(webBrowser.Handle);
MessageBox.Show(owner, "Hello World!", "BHO", MessageBoxButtons.OK);
}public void SetSite(object site)
{
if (site != null)
{
webBrowser = (WebBrowser)site;
webBrowser.DocumentComplete += new DWebBrowserEvents2_DocumentCompleteEventHandler(this.OnDocumentComplete);
}
else
{
webBrowser.DocumentComplete -= new DWebBrowserEvents2_DocumentCompleteEventHandler(this.OnDocumentComplete);
webBrowser = null;
}
}
}
}
今回はこれでおしまいです。