第29回 スクリプトエラー発生時にステータスバーにエラーメッセージを表示する (タブブラウザーを作る)

tabbrowser115.gif
前回は表示しているページのjavascriptなどでエラーが発生してもエラーダイアログが表示されないようにした。今回はエラーが発生したときにステータスバーにエラーが出た旨のメッセージが表示されるようにする。

まず内部でエラー通知用に利用する独自メッセージを「stdafx.h」に追加する。
#define	WM_DNP_SCRIPTERROR		(WM_APP + 6)			//■追加

tabbrowser116.gif 次に、前回作成したスクリプトエラーを消すためのクラスに独自インターフェースを実装して、スクリプトエラーの発生がビューに通知されるようにしておく。
#include "DnpDocHostUIHandlerImpl.h"

//■追加
//スクリプトエラーの通知先ウインドウなどを設定するためのインターフェース
MIDL_INTERFACE("2C66181A-27D5-486e-A84A-3B8EDAE1951F")
IScriptErrorSetting : public IUnknown
{
public:
	STDMETHOD (put_hWndNotify)(HWND hWnd) = 0;		//エラーの通知先HWND(ビューのHWND)を指定
};


//スクリプトエラーを消すためのUIHandler
class CHideScriptError :
	public CComObjectRootEx<CComSingleThreadModel>
	,public IDnpDocHostUIHandlerImpl
	,public	IDispatchImpl<IDispatch>
	,public IOleCommandTarget
	,public IScriptErrorSetting			//■追加
{
protected:
	HWND	_hWndNotify;				//■追加
public:

	//■追加
	CHideScriptError()
	{
		_hWndNotify = NULL;
	}

	BEGIN_COM_MAP(CHideScriptError)
		COM_INTERFACE_ENTRY(IScriptErrorSetting)		//■追加
		COM_INTERFACE_ENTRY(IDispatch)
		COM_INTERFACE_ENTRY(IDocHostUIHandler)
		COM_INTERFACE_ENTRY(IOleCommandTarget)
	END_COM_MAP()

	//■追加
	//エラーの通知先HWND(ビューのHWND)を指定
	STDMETHOD (put_hWndNotify)(HWND hWnd)
	{
		_hWndNotify = hWnd;
		return	S_OK;
	}

    STDMETHODIMP QueryStatus( const GUID* pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT* pCmdText ) 
	{
		return E_NOTIMPL; 
    }

    STDMETHODIMP Exec( const GUID* pguidCmdGroup, DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG* pvaIn, VARIANTARG* pvaOut)
    {
		//コマンドがスクリプトエラーを示すものなら、エラー表示を無効にする
		if(nCmdID == OLECMDID_SHOWSCRIPTERROR)
		{
			(*pvaOut).vt		= VT_BOOL;
			(*pvaOut).boolVal	= VARIANT_TRUE;

			//■追加
			if(_hWndNotify && ::IsWindow(_hWndNotify))
				::SendMessage(_hWndNotify,WM_DNP_SCRIPTERROR,NULL,NULL);

			return S_OK;
		}

		return E_NOTIMPL;
    }
};

tabbrowser117.gif
そしてビュー側で送られてきたスクリプトエラーメッセージを受信したらステータスバーに表示するようにする。

ステータスバーへのメッセージ表示は以前に作成した処理を利用した。
	BEGIN_MSG_MAP(CTabBrowser100View)
		MESSAGE_HANDLER(WM_DNP_SCRIPTERROR, OnDnpScriptError)		//■追加
		MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
	END_MSG_MAP()
	//■追加
	//ステータスバーのメッセージ変更をメインウインドウへ通知
	void	ChangeStatusText(LPCTSTR pszText)
	{
		_strLastStatusText = pszText;		//いつでも参照できるようにクラスのメンバーに保存しておく

		if(_pTabView == NULL || _pTabView->GetActivePage() != _pTabView->PageIndexFromHwnd(m_hWnd))
			return;			//このビューがアクティブでなければこれ以降処理しない

		//メインウインドウに変更を通知する
		GetTopLevelWindow().SendMessage(WM_DNP_CHANGESTATUSTEXT,(WPARAM)(LPCTSTR)_strLastStatusText);
	}

	//■内部処理変更
	void __stdcall OnStatusTextChange(BSTR bstrText)
	{
		ChangeStatusText((CAtlString)bstrText);
	}

	//■追加
	LRESULT OnDnpScriptError(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		ChangeStatusText(_T("ページでエラーが発生しました。"));		//固定文字列を表示している!エラーとそうでないのと見分けがつかない
		return	0;
	}

tabbrowser118.gif 最後にスクリプトエラーを検出するクラスにビューウインドウのハンドルを渡しておく。
	//UIHandlerの変更。
	//■■本当はもともと入っていたUIhandlerを取得/保持してそれも併せて使うようにすべき
	bool	ChangeUIHandler(void)
	{
		HRESULT	hr = E_FAIL;

		CComPtr<IDispatch>	pIDispatch;
		CComPtr<ICustomDoc>	pICustomDoc;
		CComPtr<IScriptErrorSetting>	pIScriptErrorSetting;	//■追加 独自に作ったインターフェース

		if(_pHideScriptError == NULL)
			_pHideScriptError = new CComObject<CHideScriptError>;

		//■4行追加 スクリプトエラー発生時の通知先としてこのビューウインドウを登録する
		if(_pHideScriptError)
			_pHideScriptError->QueryInterface(&pIScriptErrorSetting);
		if(pIScriptErrorSetting)
			pIScriptErrorSetting->put_hWndNotify(m_hWnd);

		if(_pIWebBrowser2)
			hr = _pIWebBrowser2->get_Document(&pIDispatch);
		if(pIDispatch)
			hr = pIDispatch->QueryInterface(IID_ICustomDoc,(void **)&pICustomDoc);
		if(pICustomDoc)
			hr = pICustomDoc->SetUIHandler(_pHideScriptError);

		return	SUCCEEDED(hr) ? true : false;
	}

tabbrowser119.gif
これでビルド/実行するとスクリプトエラーが発生したときにステータスバーにメッセージがひょじされるようになった。

とは言うものの、マウスカーソルがリンクの上に乗るなどしてIEコントロールからステータスバーメッセージ更新のイベントが届くとエラーメッセージがすぐに消えてしまう。

次回はエラーメッセージがすぐに消えてしまわないように修正する。

プロジェクトファイルをダウンロード


カテゴリー「タブブラウザーを作る」 のエントリー