« Windows Live Writer でMovable Typeに書いてみるてすと | メイン | WPFサーフェイスにWin32描画を行ってしまう WPF Win32 Renderer »

IE6/7対応のBHOでページのリロードを確実に取得する

Internet Explorer用のプラグイン拡張BHO(Browser Helper Object)を開発していると、いろいろ理不尽に思えることがたくさんあります。

その最たるものが、ページのリロードを通知してくれるイベントが無いこと。
DocumentComplete来るんじゃないの? と思ってると、そんなことは無いし、Webを漁っていくと、DownloadBegin/Completeイベントをカウントするとできるヨ! というサンプルがいくつか見つかりますが、これもIE7やいまどきのiframe使いまくりなページに出会うとエラー続出です。 

そんなわけで、イベントのタイミングを見極めて、これならわりと安定して動くんじゃない? という状態になったので、あまり縁がある人もいないでしょうが、ご参考までに。(キーイベントとかを拾った方がいいかもですけどね...)

メインフレームのDocumentCompleteが来ても、ブラウザがbusyだと、再度DocumentCompleteが発生する場合があるようです。
このあたりが対処療法的ではあるのですが、いちおうカウンターが暴走しないようにはなってます。

見やすいようにあえてswitch文で...。


// to detect Internet Expolorer page refreshing in BHO (with IE6/7)

inline bool IsMainFrame(IWebBrowser2 *pWebBrowser2)
{
return pWebBrowser2 == m_spWebBrowserMainFrame;
}

HRESULT Bho::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:
if (pDispParams->cArgs != 2)
return DISP_E_BADPARAMCOUNT;
if (pDispParams->rgvarg[1].vt == VT_DISPATCH
&& pDispParams->rgvarg[0].vt == (VT_BYREF | VT_VARIANT)
    && pDispParams->rgvarg[0].pvarVal->vt == VT_BSTR))
{
CComQIPtr<IWebBrowser2, &IID_IWebBrowser2>
spWebBrowserPage = V_DISPATCH(&pDispParams->rgvarg[1]);

VARIANT_BOOL fBusy;
spWebBrowserPage->get_Busy(&fBusy);
if (!fBusy || !IsMainFrame(spWebBrowserPage))
{
if (m_nPageCounter > 0)
m_nPageCounter--;

// Main frame document complete normally
OnDocumentComplete(spWebBrowserPage
, *pDispParams->rgvarg[0].pvarVal->bstrVal);
}
}
break;
case DISPID_BEFORENAVIGATE2:
if (pDispParams->cArgs != 7)
return DISP_E_BADPARAMCOUNT;
if (pDispParams->rgvarg[6].vt == VT_DISPATCH)
{
CComQIPtr<IWebBrowser2, &IID_IWebBrowser2>
spWebBrowserPage = V_DISPATCH(&pDispParams->rgvarg[6]);
if (IsMainFrame(spWebBrowserPage))
{
m_nPageCounter = 0;
if (m_fIsRefresh)
m_fIsRefresh = false;
}
}
m_nPageCounter++;
break;
case DISPID_DOWNLOADBEGIN:
m_nObjCounter++;
if (m_nPageCounter == 0)
m_fIsRefresh = true;
break;
case DISPID_DOWNLOADCOMPLETE:
if (m_nObjCounter > 0)
m_nObjCounter--;
if(m_fIsRefresh && m_nObjCounter == 0)
{
// Refrash main frame here!
m_fIsRefresh = false;
CComBSTR bstrUrl;
m_spWebBrowserMainFrame->get_LocationURL(&bstrUrl);
OnDocumentComplete(m_spWebBrowserMainFrame
, bstrUrl.m_str);
}
break;
case DISPID_ONQUIT:
OnQuit();
break;
default:
break;
}
return S_OK;
}





何か問題が見つかったり、新しい手口を見つけたら更新する予定。
ここおかしいよ、とかうまく動かない点などありましたらご一報を。

トラックバック

このエントリーのトラックバックURL:
http://labs.cybozu.co.jp/cgi-bin/mt-admin/mt-tbp.cgi/1399

コメントを投稿

(いままで、ここでコメントしたことがないときは、コメントを表示する前にこのブログのオーナーの承認が必要になることがあります。承認されるまではコメントは表示されません。そのときはしばらく待ってください。)

About

2007年07月17日 12:20に投稿されたエントリーのページです。

ひとつ前の投稿は「Windows Live Writer でMovable Typeに書いてみるてすと」です。

次の投稿は「WPFサーフェイスにWin32描画を行ってしまう WPF Win32 Renderer」です。

他にも多くのエントリーがあります。メインページアーカイブページも見てください。