« 2009年03月 | メイン | 2010年05月 »

前の10件 1  2  3  4  5  6  7

2009年04月 記事一覧

第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コントロールからステータスバーメッセージ更新のイベントが届くとエラーメッセージがすぐに消えてしまう。

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

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

2009年04月06日

第30回 ステータスバーにエラーメッセージが表示され続けるようにする (タブブラウザーを作る)

tabbrowser120.gif
前回はスクリプトエラーが発生したとき、ステータスバーにエラーメッセージが表示されるようにした。しかしエラーが起きたことを保存していなかったためすぐにエラーメッセージが消えてしまうという問題があった。

今回はエラーが起きたことを記憶して、常にエラーメッセージが表示されるようにする。

ビュークラスにエラーが起きたことを保存するための変数_bPageError を追加する。
class CTabBrowser100View : public CWindowImpl<CTabBrowser100View, CAxWindow>
	,public IDispEventImpl<SINKID_EVENTS, CTabBrowser100View, &DIID_DWebBrowserEvents2>
	,public CIEUtility
{
	CTabView*	_pTabView;		//タブビューを保持
	HWND		_hWndRebarIE;	//IEツールバー用のリバー

	bool		_bPageError;	//■追加 現在のページでスクリプトエラーなどがあればtrue、通常はfalse

public:
	DECLARE_WND_SUPERCLASS(NULL, CAxWindow::GetWndClassName())


	CTabBrowser100View(CTabView* pTabView,HWND hWndRebarIE)
	{
		_pTabView = pTabView;
		_nLastProgress		= 0;
		_nLastProgressMax	= -1;
		_hWndRebarIE = hWndRebarIE;
		_bPageError = false;			//■追加
	}

tabbrowser121.gif
そしてエラーが起きたときに_bPageError をtrueにして、エラーが起きたことを保存し、エラー用のステータスバー用メッセージが表示されるようにする。

_bPageError がtrueのままだと、一度エラーがおきたらずっとエラーメッセージが表示されたままになってしまう。そのためDownloadBeginイベントを受け取ったらfalseを設定してエラー情報をクリアする。
	//ステータスバーのメッセージ変更をメインウインドウへ通知
	void	ChangeStatusText(LPCTSTR pszText)
	{
		_strLastStatusText = pszText;		//いつでも参照できるようにクラスのメンバーに保存しておく

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

		GetLastStatusText(_strLastStatusText);		//■追加 この呼び出しによりエラー時にはエラー用メッセージに変わる

		//メインウインドウに変更を通知する
		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)
	{
		_bPageError = true;			//■追加 エラーが発生したことを保持
		ChangeStatusText(NULL);		//■変更
		return	0;
	}

	//最後にIEコントロールから受け取ったステータスバー用メッセージを返す
	void	GetLastStatusText(CAtlString& strText)
	{
		strText = _strLastStatusText;

		//■追加 表示する文字がないときで、現在ページにエラーがあればエラーメッセージを返す
		if(_bPageError && strText == _T(""))
			strText = _T("ページでエラーが発生しました。");
	}

	void __stdcall OnDownloadComplete()
	{
	}

	void __stdcall OnCommandStateChange(long lCommand,VARIANT_BOOL vbEnable)
	{
	}

	void __stdcall OnDownloadBegin(void)
	{
		_bPageError = false;		//■追加 エラー情報をリセット
	}

tabbrowser122.gif せっかくなのでスクリプトエラーだけでなく、NavigateErrorを受信したときもエラーメッセージを表示するようにした。
	void __stdcall OnNavigateError(IDispatch *pDisp,VARIANT *vURL,VARIANT *vTargetFrameName,VARIANT *vStatusCode,VARIANT_BOOL *vbCancel)
	{
		//■2行追加
		_bPageError = true;			//スクリプトエラー出なくてもエラーが発生したらtrueにする
		ChangeStatusText(NULL);
	}

tabbrowser123.gif
これでビルド/実行するとステータスバーにエラーメッセージが表示され続けるようになった。

もう少しスクリプトエラー関連を修正しておきたい気もするが保留して、次回はアドレスバーにクリップボードから張り付けたURLが途切れる問題などを修正する。

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

第31回 アドレスバーでキーボードショートカットが使えるようにする (タブブラウザーを作る)

tabbrowser124.gif
今までアドレスバー内で、[Ctrl]+[V]などのキーボードによる操作ができなかったり、横幅以上のサイズのURLが入力できないなどの致命的な問題点があった。今回はそれらを修正する。

まずはアドレスバーでキーボードショートカットが利用できない点。これはアクセラレーターが設定されているためで、その処理はCFrameWindowImpl<CMainFrame>::PreTranslateMessageで行われている(むしろそこではその処理しかしていない)。そのためアドレスバー内にフォーカスがある場合はCFrameWindowImpl<CMainFrame>::PreTranslateMessageが実行されないようにする。
	virtual BOOL PreTranslateMessage(MSG* pMsg)
	{
		if(_wndAddressBar.IsChild(::GetFocus()) == FALSE)		//■追加 アドレスバーにフォーカスがあるときはPreTranslateMessageを回さない(アドレスバーでCtrl+Cなどを使えるようにするため)
		{
			if(CFrameWindowImpl<CMainFrame>::PreTranslateMessage(pMsg))
				return TRUE;
		}

		return m_view.PreTranslateMessage(pMsg);
	}

tabbrowser125.gif
次に長い文字列を入力できない点。これは使っているコンボボックスにCBS_AUTOHSCROLLスタイルを設定していなかったためだ。ちなみにエディットコントロールの場合はES_AUTOHSCROLLスタイルを指定する。

また今回は外見に3D境界線をつける拡張スタイルのWS_EX_CLIENTEDGEなども追加しておいた。
		//■スタイル変更
		_wndAddressBar.Create(m_hWnd,CRect(0,0,200,200),0,WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_CLIPCHILDREN,WS_EX_CLIENTEDGE);

tabbrowser126.gif
これでビルド/実行するとアドレスバーでの上記2つの問題を修正できた。

次回はステータスバーにアイコンを表示する。

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

第32回 ステータスバーにアイコンを表示する (タブブラウザーを作る)

tabbrowser127.gif
開いているページでスクリプトエラーが発生したときにステータスバーにアイコンを表示する機能を実装する前段階として、今回はステータスバーにアイコンを表示するテストを行う。

Windowsにはエラー表示用のアイコンがOEMリソースとして用意されている。その利用を「stdafx.h」内の最初で定義する。
#define	OEMRESOURCE			//■追加 OEMアイコンを利用する

tabbrowser128.gif 次にOEMリソースからスモールアイコンを読み込み、管理するためのクラスCIconManagerを作る。今回は1つのアイコンのみを管理しているが、このクラスは今後順次機能を追加する予定だ。
//■追加
//アイコンを管理
//アイコンをAddする関数などは未実装。今後追加
class	CIconManager
{
protected:
	CAtlArray<HICON>	_ahIcon;		//アイコンリスト

public:
	CIconManager()
	{
		SetFixedIndexIcon();		//固定インデックスのアイコンを追加
	}

	~CIconManager()
	{
		Destroy();
	}

	enum	ICON_INDEX
	{
		ICON_WARNING_SM = 0,			//警告アイコン。スクリプトエラー時に利用
	};

	HICON	GetIcon(UINT nIconIndex)
	{
		if(nIconIndex >= _ahIcon.GetCount())
			return	NULL;

		return	_ahIcon[nIconIndex];
	}

protected:

	//固定インデックスのアイコンを追加
	//かならずICON_INDEXと同じ値になるようにする
	bool	SetFixedIndexIcon(void)
	{
		ATLASSERT(_ahIcon.GetCount() == 0);		//すでに設定されてる?
		if(_ahIcon.GetCount())
			return	false;

		size_t	nIndex;
		HICON	hIcon;

		//警告アイコン
		//LoadImageで32x32を読み込み、CopyImageで16x16に縮小。LoadImageのHICONはLR_SHAREDなのでDestroyIcon必要なし
		hIcon = (HICON)::LoadImage(NULL,MAKEINTRESOURCE(OIC_WARNING),IMAGE_ICON,0,0,LR_DEFAULTSIZE | LR_SHARED);
		hIcon = (HICON)::CopyImage(hIcon,IMAGE_ICON,::GetSystemMetrics(SM_CXSMICON),::GetSystemMetrics(SM_CYSMICON),LR_COPYFROMRESOURCE);
		nIndex = _ahIcon.Add(hIcon);
		ATLASSERT(nIndex == ICON_WARNING_SM);

		return	true;
	}

	//保持してるアイコンの破棄
	void	Destroy(void)
	{
		size_t	i;
		size_t	nSize;

		nSize = _ahIcon.GetCount();
		for(i = 0; i < nSize; i++)
		{
			if(_ahIcon[i] == NULL)
				continue;
			::DestroyIcon(_ahIcon[i]);
		}
		_ahIcon.RemoveAll();
	}
};


class CMainFrame : public CFrameWindowImpl<CMainFrame>, public CUpdateUI<CMainFrame>,
		public CMessageFilter, public CIdleHandler
{
	CAddressBarCtrl	_wndAddressBar;			// アドレスバー用コンボボックス

	CIconManager	_cIconList;		//■追加

tabbrowser129.gif そしてOnCreate内にアイコンをステータスバーに表示するためのテストコードを1行追加する。この1行のコードはアイコンが表示されることを確認したら削除する。
		//■追加アイコン表示。テスト用。確認したら削除すること
		::SendMessage(m_hWndStatusBar,SB_SETICON,0,(LPARAM)_cIconList.GetIcon(CIconManager::ICON_WARNING_SM));

tabbrowser130.gif
これでビルド/実行するとステータスバーにエラー表示用のアイコンが表示された。

次回はページにエラーが発生したときにこのアイコンが表示されるようにする。

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

第33回 ページエラー発生時にアイコンを表示する (タブブラウザーを作る)

tabbrowser132.gif
前回はステータスバーにアイコンを表示するテストを行った。今回はページにエラーが発生しているときのみアイコンが表示されるようにする。

まずビュークラスにエラーが発生したときにメインウインドウへそれを知らせる処理を追加する。 ここでは独自メッセージWM_DNP_SCRIPTERRORのWPARAMをエラー発生時TRUE、エラー解消時FALSEという意味付けを行い、メインウインドウへ送信するようにした。
	//■追加
	//エラー発生/解消時に呼ぶ
	//bError=trueならエラー発生
	void	SetErrorState(bool bError)
	{
		_bPageError = bError;			//エラーが発生したことを保持
		if(bError)
			ChangeStatusText(NULL);

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

		//メインウインドウにエラー発生を通知
		GetTopLevelWindow().SendMessage(WM_DNP_SCRIPTERROR,(WPARAM)(bError ? TRUE : FALSE));
	}

	//■追加
	bool	IsPageError(void)
	{
		return	_bPageError;
	}



	LRESULT OnDnpScriptError(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		//■処理変更
		SetErrorState(true);
		return	0;
	}


	//最後にIEコントロールから受け取ったステータスバー用メッセージを返す
	void	GetLastStatusText(CAtlString& strText)
	{
		strText = _strLastStatusText;

		//表示する文字がないときで、現在ページにエラーがあればエラーメッセージを返す
		if(_bPageError && strText == _T(""))
			strText = _T("ページでエラーが発生しました。");
	}

	void __stdcall OnDownloadComplete()
	{
	}

	void __stdcall OnCommandStateChange(long lCommand,VARIANT_BOOL vbEnable)
	{
	}

	void __stdcall OnDownloadBegin(void)
	{
		SetErrorState(false);		//■変更 エラー情報をリセット
	}

tabbrowser131.gif WM_DNP_SCRIPTERRORのWPARAMに意味付けを追加してしまったので、直接は関係ないがスクリプト検出用のクラスの処理でもWPARAMがTRUEになるように変更しておく。
    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,(WPARAM)TRUE,NULL);		//■変更

			return S_OK;
		}

		return E_NOTIMPL;
    }

tabbrowser133.gif 忘れずにNavigateErrorイベント発生時の処理にもメインウインドウへ通知がいくように変更しておく。
	void __stdcall OnNavigateError(IDispatch *pDisp,VARIANT *vURL,VARIANT *vTargetFrameName,VARIANT *vStatusCode,VARIANT_BOOL *vbCancel)
	{
		SetErrorState(true);		//■変更 スクリプトエラー出なくてもエラーが発生したらtrueにする
	}

tabbrowser134.gif そしてメインウインドウ側でスクリプトエラーが処理されるようにメッセージハンドラを追加する。
	BEGIN_MSG_MAP(CMainFrame)
		MESSAGE_HANDLER(WM_DNP_CREATENEWTAB, OnDnpCreateNewTab)
		MESSAGE_HANDLER(WM_DNP_CHANGEFOCUS, OnDnpChangeFocus)
		MESSAGE_HANDLER(WM_DNP_CHANGEADDRESS, OnDnpChangeAddress)
		MESSAGE_HANDLER(WM_DNP_CHANGESTATUSTEXT, OnDnpChangeStatusText)
		MESSAGE_HANDLER(WM_DNP_CHANGEPROGRESS, OnDnpChangeProgress)
		MESSAGE_HANDLER(WM_DNP_SCRIPTERROR, OnDnpScriptError)		//■追加
		NOTIFY_CODE_HANDLER(CBEN_ENDEDIT, OnAddressbarEnter)
		MESSAGE_HANDLER(WM_CREATE, OnCreate)
		MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
		COMMAND_ID_HANDLER(ID_APP_EXIT, OnFileExit)
		COMMAND_ID_HANDLER(ID_FILE_NEW, OnFileNew)
		COMMAND_ID_HANDLER(ID_VIEW_TOOLBAR, OnViewToolBar)
		COMMAND_ID_HANDLER(ID_VIEW_STATUS_BAR, OnViewStatusBar)
		COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)
		COMMAND_ID_HANDLER(ID_WINDOW_CLOSE, OnWindowClose)
		COMMAND_ID_HANDLER(ID_WINDOW_CLOSE_ALL, OnWindowCloseAll)
		COMMAND_ID_HANDLER(ID_FILE_PRINT, OnFileCommand)
		COMMAND_ID_HANDLER(ID_FILE_PRINT_PREVIEW, OnFileCommand)
		COMMAND_ID_HANDLER(ID_FILE_PRINT_SETUP, OnFileCommand)
		COMMAND_ID_HANDLER(ID_EDIT_COPY, OnFileCommand)
		COMMAND_ID_HANDLER(ID_EDIT_CUT, OnFileCommand)
		COMMAND_ID_HANDLER(ID_EDIT_PASTE, OnFileCommand)
		COMMAND_ID_HANDLER(ID_EDIT_SELECT_ALL, OnFileCommand)
		COMMAND_RANGE_HANDLER(ID_WINDOW_TABFIRST, ID_WINDOW_TABLAST, OnWindowActivate)
		COMMAND_ID_HANDLER(ID_IE_BACK, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_NEXT, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_STOP, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_REFRESH, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_ADDFAVORITE, OnIEAddFavorite)
		COMMAND_ID_HANDLER(ID_IE_ORGANIZE_FAVORITE, OnIEOrganizeFavorite)
		NOTIFY_CODE_HANDLER(TBVN_CONTEXTMENU, OnTabContextMenu)
		NOTIFY_CODE_HANDLER(TBVN_PAGEACTIVATED, OnTabPageActivated)
		MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)
		MESSAGE_HANDLER(WM_SIZE, OnSize)
		COMMAND_RANGE_HANDLER(ID_FAVORITE_FIRST,ID_FAVORITE_LAST,OnFavorite)
		CHAIN_MSG_MAP_MEMBER(_cFovMenu)
		CHAIN_MSG_MAP(CUpdateUI<CMainFrame>)
		CHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>)
	END_MSG_MAP()

tabbrowser135.gif 最後にタブが切り替わったときと、ビューウインドウからスクリプトエラーのメッセージが送られてきたときにステータスバーにアイコンが表示されるようにする。
	//タブが選択されたときの処理
	LRESULT OnTabPageActivated(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
	{
		if(pnmh == NULL)
			return	0;

		//全てのビューに対してタブ変更があったことを通知
		{
			int		i;
			int		nCount;
			CTabBrowser100View*	pView;

			int kk=m_view.GetActivePage();

			nCount = m_view.GetPageCount();
			for(i = 0; i < nCount; i++)
			{
				pView = GetPageView(i);
				if(pView == NULL)
					continue;

				if(pnmh->idFrom == i)
					pView->OnTabPageChange(true);
				else
					pView->OnTabPageChange(false);
			}
		}

		bool		ret;
		CTabBrowser100View*	pView;

		pView = GetActivePageView();		//アクティブビュー取得
		if(pView == NULL)
			return	0;

		//アドレスバーのURL変更
		{
			CAtlString	strURL;

			ret = pView->GetURL(strURL);		//URL取得
			if(ret)
				_wndAddressBar.SetWindowText(strURL);
		}

		//ステータスバーのテキスト変更
		{
			CAtlString	strText;

			pView->GetLastStatusText(strText);
			if(::IsWindow(m_hWndStatusBar))
				::SetWindowText(m_hWndStatusBar,strText);
		}

		//■追加
		//ステータスバーのエラーアイコン変更
		{
			CStatusBarCtrl	wndStatusBar = m_hWndStatusBar;

			if(wndStatusBar.IsWindow())
			{
				if(pView->IsPageError())
					wndStatusBar.SetIcon(0,_cIconList.GetIcon(CIconManager::ICON_WARNING_SM));
				else
					wndStatusBar.SetIcon(0,NULL);
			}
		}

		//プログレス変更
		{
			long	nProgress;
			long	nProgressMax;

			pView->GetLastProgress(nProgress,nProgressMax);
			RefreshProgressBar(nProgress,nProgressMax);
		}

		return	0;
	}


	//■追加
	//ステータスバーのエラーアイコン変更
	LRESULT OnDnpScriptError(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		BOOL	bPageError = (BOOL)wParam;
		CStatusBarCtrl	wndStatusBar = m_hWndStatusBar;

		if(wndStatusBar.IsWindow())
		{
			if(bPageError)
				wndStatusBar.SetIcon(0,_cIconList.GetIcon(CIconManager::ICON_WARNING_SM));
			else
				wndStatusBar.SetIcon(0,NULL);
		}

		return	0;
	}

tabbrowser136.gif
これでビルド/実行するとページにエラーがあるときだけステータスバーにアイコンが表示されるようになった。

だんだんビューからメインウインドウへの通知が増えてきてそろそろソースコードが崩壊しそうな雰囲気があるため整理したいところだがまだしばらく誤魔化しながら実装し続けることにする。

次回はページにエラーがあるときにステータスバーをダブルクリックすることでエラーの詳細情報が表示されるようにする。

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

第34回 ステータスバーのダブルクリックでスクリプトエラーの詳細情報を表示する (タブブラウザーを作る)

tabbrowser137.gif
前回は開いているページでスクリプトエラーが発生したときにステータスバーにアイコンが表示されるようにした。今回はステータスバーをダブルクリックしたときにエラーに関する情報を表示する。

IEコントロールでは私の知る限りエラーメッセージを後から表示するための機能は備わっていない。Internet Explorer 8などではエラーメッセージを内部で保管しておき、必要に応じてエラー情報をダイアログで表示していると思われる。

そのため今回は内部でエラー情報を保持してステータスバーがダブルクリックされた時にそれを表示することにする。まずスクリプトエラー検出用のインターフェースにエラーメッセージを表示するためのメソッドを追加する。
//スクリプトエラーの通知先ウインドウなどを設定するためのインターフェース
MIDL_INTERFACE("2C66181A-27D5-486e-A84A-3B8EDAE1951F")
IScriptErrorSetting : public IUnknown
{
public:
	STDMETHOD (put_hWndNotify)(HWND hWnd) = 0;		//エラーの通知先HWND(ビューのHWND)を指定
	STDMETHOD (ShowLastScriptError)(HWND hWnd) = 0;		//■追加
};

	CAtlString		_strErrorMessage;		//■追加 表示用のエラー情報

	//■追加
	STDMETHOD (ShowLastScriptError)(HWND hWnd)
	{
		if(_strErrorMessage == _T(""))
			return	E_FAIL;

		::MessageBox(hWnd,_strErrorMessage,_T("エラー情報"),MB_OK | MB_ICONWARNING);

		return	S_OK;
	}

tabbrowser138.gif そしてExecでスクリプトエラーを検出したら、その詳細情報を保存しておく。
    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,(WPARAM)TRUE,NULL);


			//■追加
			//エラー情報を保存
			//面倒なので表示用に整形して_strErrorMessageに代入している
			//本当はURIをチェックして同じならどんどん貯めておいた方がいい
			{
				_strErrorMessage = _T("");

				CComPtr<IHTMLDocument2>	pIHTMLDocument2;
				CComPtr<IHTMLWindow2>	pIHTMLWindow2;
				CComPtr<IHTMLEventObj>	pIHTMLEventObj;

				if(pvaIn && pvaIn->punkVal)
					pvaIn->punkVal->QueryInterface(IID_IHTMLDocument2,(void**)&pIHTMLDocument2);
				if(pIHTMLDocument2)
					pIHTMLDocument2->get_parentWindow(&pIHTMLWindow2);
				if(pIHTMLWindow2)
					pIHTMLWindow2->get_event(&pIHTMLEventObj);
				if(pIHTMLEventObj)
				{
					int			i;
					OLECHAR*	pwszName[] = {L"errorLine",L"errorCharacter",L"errorCode",L"errorMessage",L"errorUrl"};
					TCHAR*		pszHeader[] = {_T("ライン:"),_T("文字:"),_T("エラーコード:"),_T(""),_T("URI:")};

					for(i = 0; i < 5; i++)
					{
						DISPID		nDispID;
						HRESULT		hr;
						DISPPARAMS	sDispParams;
						CComVariant	vResult;

						//エラー情報のDISPID取得
						hr = pIHTMLEventObj->GetIDsOfNames(IID_NULL,&pwszName[i],1,LOCALE_SYSTEM_DEFAULT,&nDispID);
						if(FAILED(hr))
							continue;

						//エラー情報取得
						::ZeroMemory(&sDispParams,sizeof(DISPPARAMS));
						hr = pIHTMLEventObj->Invoke(nDispID,IID_NULL,LOCALE_SYSTEM_DEFAULT,DISPATCH_PROPERTYGET,&sDispParams,&vResult,NULL,NULL);
						if(FAILED(hr))
							continue;

						CAtlString	strBuff(vResult);

						_strErrorMessage += pszHeader[i];
						_strErrorMessage += strBuff;
						_strErrorMessage += _T("\n");
					}
				}
			}

			return S_OK;
		}

		return E_NOTIMPL;
    }

tabbrowser139.gif ビュークラスの中に上で最初に実装したスクリプトエラーを表示するための関数を用意する。
	//■追加
	bool	ShowScriptError(void)
	{
		if(_bPageError == false)
			return	false;			//現在エラー中ではない

		CComPtr<IScriptErrorSetting>	pIScriptErrorSetting;	//独自に作ったインターフェース

		if(_pHideScriptError)
			_pHideScriptError->QueryInterface(&pIScriptErrorSetting);
		if(pIScriptErrorSetting)
			pIScriptErrorSetting->ShowLastScriptError(m_hWnd);		//エラーメッセージの表示

		return	true;
	}

tabbrowser140.gif
最後にメインウインドウにステータスバーがダブルクリックされたときの処理を追加する。

ステータスバーがダブルクリックされるとメインウインドウにWM_NOTIFYが届くので、今回はそれを処理することにした。
		COMMAND_ID_HANDLER(ID_IE_ORGANIZE_FAVORITE, OnIEOrganizeFavorite)
		NOTIFY_CODE_HANDLER(TBVN_CONTEXTMENU, OnTabContextMenu)
		NOTIFY_CODE_HANDLER(TBVN_PAGEACTIVATED, OnTabPageActivated)
		NOTIFY_HANDLER(ATL_IDW_STATUS_BAR, NM_DBLCLK, OnStatusBarDblClk)			//■追加
		MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)
		MESSAGE_HANDLER(WM_SIZE, OnSize)
		COMMAND_RANGE_HANDLER(ID_FAVORITE_FIRST,ID_FAVORITE_LAST,OnFavorite)
		CHAIN_MSG_MAP_MEMBER(_cFovMenu)
		CHAIN_MSG_MAP(CUpdateUI<CMainFrame>)
		CHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>)
	END_MSG_MAP()



	//■追加
	//ステータスバーのダブルクリック処理
	LRESULT OnStatusBarDblClk(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
	{
		bHandled = FALSE;

		NMMOUSE*	pNmMouse = (NMMOUSE*)pnmh;
		CTabBrowser100View*	pView;

		if(pNmMouse == NULL)
			return	0;

		if(pNmMouse->dwItemSpec == 0)
		{
			//ゼロ番目のペインがダブルクリックされた
			pView = GetActivePageView();
			if(pView)
				pView->ShowScriptError();			//スクリプトエラー情報を表示する
		}

		return	0;
	}

tabbrowser141.gif
これでビルド/実行するとスクリプトエラー発生時にステータスバーをダブルクリックすることでエラーの詳細表示を見れるようになった。

次回はメニューバーにInternet Explorerにあるような項目を追加する。

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

2009年04月07日

第35回 Internet Exolorer風にメニュー項目を追加する (タブブラウザーを作る)

tabbrowser142.gif
今回はタブブラウザのメニューにInternet Explorerと同じような項目を追加する。項目を作るだけで実際に処理を実装するのはまだまだ先だ。

今回は一度にたくさんのメニュー項目を追加することになる。リソースエディタで1つずつ入力してもいいが、数が多いときは大変な作業になる。そこでrcファイルを直接編集して項目を追加する。

ソリューションエクスプローラーで「TabBrowser100.rc」の上で右クリックして現われるメニューから「コードの表示」を選択する。

tabbrowser143.gif するとリソースエディタが開かずに、直接rcファイルの中身が表示される。ここでメニューの項目をInternet Explorerと同じようなものに書き換える。今回はInternet Explorer 8と同じような配置になるようにした。
IDR_MAINFRAME MENU 
BEGIN
    POPUP "ファイル(&F)"
    BEGIN
        MENUITEM "新しいタブ(&T)\tCtrl+T",           ID_FILE_NEW
        MENUITEM "タブを複製(&B)\tCtrl+K",           ID_FILE_COPY_TAB
        MENUITEM "新規ウインドウ(&N)\tCtrl+N",         ID_FILE_NEW_WINDOW
        MENUITEM "新規セッション(&I)",                 ID_FILE_NEW_SESSION
        MENUITEM "開く(&O)...\tCtrl+O",           ID_FILE_OPEN
        MENUITEM "編集(&D)",                      ID_FILE_EDIT
        MENUITEM "上書き保存(&S)\tCtrl+S",           ID_FILE_SAVE
        MENUITEM "名前を付けて保存(&A)...",             ID_FILE_SAVE_AS
        MENUITEM "タブを閉じる(&C)\tCtrl+W",          ID_WINDOW_CLOSE
        MENUITEM SEPARATOR
        MENUITEM "ページ設定(&U)...",                ID_FILE_PRINT_SETUP
        MENUITEM "印刷(&P)...\tCtrl+P",           ID_FILE_PRINT
        MENUITEM "プレビュー(&V)...",                ID_FILE_PRINT_PREVIEW
        MENUITEM SEPARATOR
        POPUP "送信(&E)"
        BEGIN
            MENUITEM "ページを電子メールで(&P)...",           ID_FILE_SEND_PAGE
            MENUITEM "リンクを電子メールで(&L)...",           ID_FILE_SEND_LINK
            MENUITEM "ショートカットをデスクトップへ(&S)",         ID_FILE_CREATE_SHORTCUT
        END
        MENUITEM "インポートおよびエクスポート(&I)...",       ID_FILE_INPORT_EXPORT
        MENUITEM SEPARATOR
        MENUITEM "プロパティ(&R)",                   ID_FILE_PROPERTY
        MENUITEM "オフライン作業(&W)",                 ID_FILE_OFFLINE
        MENUITEM "終了(&X)",                      ID_APP_EXIT
    END
    POPUP "編集(&E)"
    BEGIN
        MENUITEM "切り取り(&T)\tCtrl+X",            ID_EDIT_CUT
        MENUITEM "コピー(&C)\tCtrl+C",             ID_EDIT_COPY
        MENUITEM "貼り付け(&P)\tCtrl+V",            ID_EDIT_PASTE
        MENUITEM SEPARATOR
        MENUITEM "全て選択(&A)\tCtrl+A",            ID_EDIT_SELECT_ALL
        MENUITEM SEPARATOR
        MENUITEM "このページの検索(&F)...\tCtrl+F",     ID_EDIT_FIND
    END
    POPUP "表示(&V)"
    BEGIN
        POPUP "ツール バー(&T)"
        BEGIN
            MENUITEM "ツール バー(&T)",                  ID_VIEW_TOOLBAR
            MENUITEM SEPARATOR
            MENUITEM "ツール バーを固定する(&L)",             ID_VIEW_FIXED
        END
        MENUITEM "クイックタブ(&Q)\tCtrl+Q",          ID_VIEW_QUICKTAB
        POPUP "エクスプローラー バー(&E)"
        BEGIN
            MENUITEM "お気に入り(&F)\tCtrl+Shift+I",     ID_VIEW_FAVORITE
            MENUITEM "履歴(&H)\tCtrl+Shift+H",        ID_VIEW_HISTORY
            MENUITEM "フィード(&D)\tCtrl+Shift+J",      ID_VIEW_FEED
        END
        MENUITEM "ステータス バー(&S)",                ID_VIEW_STATUS_BAR
        MENUITEM SEPARATOR
        MENUITEM "移動(&G)",                      ID_VIEW_GO
        MENUITEM "中止(&P)\tEsc",                 ID_IE_STOP
        MENUITEM "最新の状態に更新(&R)\tF5",            ID_IE_REFRESH
        MENUITEM SEPARATOR
        POPUP "拡大(&Z)"
        BEGIN
            MENUITEM "拡大\tCtrl +",                  ID_VIEW_ZOOM_PLUS
            MENUITEM "縮小\tCtrl -",                  ID_VIEW_ZOOM_MINUS
            MENUITEM SEPARATOR
            MENUITEM "400%",                        ID_VIEW_ZOOM_400
            MENUITEM "200%",                        ID_VIEW_ZOOM_200
            MENUITEM "150%",                        ID_VIEW_ZOOM_150
            MENUITEM "125%",                        ID_VIEW_ZOOM_125
            MENUITEM "100%",                        ID_VIEW_ZOOM_100
            MENUITEM " 75%",                        ID_VIEW_ZOOM_75
            MENUITEM " 50%",                        ID_VIEW_ZOOM_50
            MENUITEM SEPARATOR
            MENUITEM " カスタム...",                        ID_VIEW_ZOOM_CUSTOM
        END
        POPUP "文字の大きさ(&X)"
        BEGIN
            MENUITEM "最大(&G)",                      ID_VIEW_CHAR_MAX
            MENUITEM "大(&L)",                       ID_VIEW_CHAR_LARGE
            MENUITEM "中(&M)",                       ID_VIEW_CHAR_MIDDLE
            MENUITEM "小(&S)",                       ID_VIEW_CHAR_SMALL
            MENUITEM "最小(&A)",                      ID_VIEW_CHAR_MIN
        END
        POPUP "エンコード(&D)"
        BEGIN
            MENUITEM "自動選択",                        ID_VIEW_ENCODE_AUTO
            MENUITEM SEPARATOR
            MENUITEM SEPARATOR
            MENUITEM "ドキュメントの方向 - 左から右",            ID_VIEW_ENCODE_TO_RIGHT
            MENUITEM "ドキュメントの方向 - 右から左",            ID_VIEW_ENCODE_TO_LEFT
        END
        POPUP "スタイル(&Y)"
        BEGIN
            MENUITEM "スタイルなし(&N)",                  ID_VIEW_STYLE_NONE
            MENUITEM "既定のスタイル(&D)",                 ID_VIEW_STYLE_DEFAULT
        END
        MENUITEM "カーソル ブラウズ(&B)\tF7",           ID_VIEW_CURSOR_BROWSE
        MENUITEM SEPARATOR
        MENUITEM "ソース(&C)",                     ID_VIEW_SOURCE
        MENUITEM "セキュリティ報告(&S)",                ID_VIEW_SECURITY_REPORT
        MENUITEM "インターナショナル Web サイト アドレス(&I)",  ID_VIEW_DOMAIN
        MENUITEM "Web ページのプライバシー ポリシー(&V)...",  ID_VIEW_PRIVACY_POLICY
        MENUITEM "全画面表示(&F)\tF11",              ID_VIEW_FULL_SCREEN
    END
    POPUP "ウインドウ(&W)"
    BEGIN
        MENUITEM "閉じる(&C)\tCtrl+F4",            ID_WINDOW_CLOSE
        MENUITEM "全て閉じる(&A)",                   ID_WINDOW_CLOSE_ALL
    END
    POPUP "お気に入り(&A)"
    BEGIN
        MENUITEM "dummy",                       ID_FAVORITE_DUMMY
        MENUITEM "お気に入りに追加(&A)...",             ID_IE_ADDFAVORITE
        MENUITEM "お気に入りバーに追加(&B)",              ID_FAVORITE_ADD_TO_BAR
        MENUITEM "現在の全てのタブをお気に入りに追加(&T)...",    ID_FAVORITE_ADD_ALLTAB
        MENUITEM SEPARATOR
        MENUITEM "お気に入りの整理(&O)...",             ID_IE_ORGANIZE_FAVORITE
        MENUITEM SEPARATOR
    END
    POPUP "ツール(&T)"
    BEGIN
        MENUITEM "閲覧の履歴の削除(&D)...\tCtrl+Shift+Del", ID_TOOL_CLEAR_HISTORY
        MENUITEM "InPrivate ブラウズ(&I)\tCtrl+Shift+P", ID_TOOL_INPRIVATE_BROWSE
        MENUITEM "接続の問題を診断(&C)...",             ID_TOOL_CHECK_NETSTAT
        MENUITEM "最終閲覧セッションを再度開く(&S)",          ID_TOOL_OPEN_LAST_SESSION
        MENUITEM SEPARATOR
        MENUITEM "InPrivate フィルター\tCtrl+Shift+F", ID_TOOL_INPRIVATE_FILTER
        MENUITEM "InPrivate フィルター設定(&S)",       ID_TOOL_INPRIVATE_FILTER_OPTION
        MENUITEM SEPARATOR
        POPUP "ポップアップ ブロック(&P)"
        BEGIN
            MENUITEM "無効にする(&B)",                   ID_TOOL_POPUP_DISABLE
            MENUITEM "設定(&P)...",                   ID_TOOL_POPUP_OPTION
        END
        POPUP "SmartScreen フィルター機能(&T)"
        BEGIN
            MENUITEM "この Web サイトを確認する(&C)",         ID_TOOL_CHECK_THIS_SITE
            MENUITEM "SmartScreen フィルター機能を無効にする(&F)...", ID_TOOL_SMARTSCREEN_DISABLE
            MENUITEM "安全でない Web サイトを報告する(&R)",      ID_TOOL_SEND_REPORT
        END
        MENUITEM "アドオンの管理(&A)",                 ID_TOOL_MANAGE_ADDON
        MENUITEM SEPARATOR
        MENUITEM "このフィードの購読(&F)...",            ID_TOOL_FEED_ADD
        MENUITEM "フィード探索(&E)...",               ID_TOOL_FEED_FIND
        MENUITEM "Windows Update(&U)",          ID_TOOL_WINDOWS_UPDATE
        MENUITEM SEPARATOR
        MENUITEM "開発者ツール(&L)\tF12",             ID_TOOL_DEVELOP
        MENUITEM SEPARATOR
        MENUITEM "インターネット オプション(&O)",           ID_TOOL_INTERNET_OPTION
    END
    POPUP "ヘルプ(&H)"
    BEGIN
        MENUITEM "バージョン情報 TabBrowser100(&A)...", ID_APP_ABOUT
    END
END

tabbrowser144.gif 次に新しいメニュー用のIDを定義するために「resource.h」を開く。実際にIDを追加する前に、まず使われていない不要なIDを削除しておこう。
#define IDD_ABOUTBOX                    100
#define IDR_MAINFRAME                   128
#define IDM_TAB                         201
#define ID_WINDOW_CLOSE                 32772
#define ID_WINDOW_CLOSE_ALL             32773
#define ID_IE_BACK                      32775
#define ID_IE_NEXT                      32776
#define ID_IE_STOP                      32777
#define ID_IE_REFRESH                   32778
//#define ID_32779                        32779		//■削除
//#define ID_32780                        32780		//■削除
//#define ID_32781                        32781		//■削除
#define ID_FAVORITE_DUMMY               32782
//#define ID_32783                        32783		//■削除
//#define ID_32784                        32784		//■削除
#define ID_IE_ORGANIZE_FAVORITE         32785
#define ID_IE_ADDFAVORITE               32786
//#define ID_BUTTON32787                  32787		//■削除
#define ID_FAVORITE_FIRST               34000
#define ID_FAVORITE_LAST                54000

tabbrowser145.gif そして次に新しいIDの定義を追加する。
#define	ID_FILE_COPY_TAB					32787
#define	ID_FILE_NEW_WINDOW					32788
#define	ID_FILE_NEW_SESSION					32789
#define	ID_FILE_EDIT						32790
#define	ID_FILE_SEND_PAGE					32791
#define	ID_FILE_SEND_LINK					32792
#define	ID_FILE_CREATE_SHORTCUT				32793
#define	ID_FILE_INPORT_EXPORT				32794
#define	ID_FILE_PROPERTY					32795
#define	ID_FILE_OFFLINE						32796
#define	ID_VIEW_FIXED						32797
#define	ID_VIEW_QUICKTAB					32798
#define	ID_VIEW_FAVORITE					32799
#define	ID_VIEW_HISTORY						32800
#define	ID_VIEW_FEED						32801
#define	ID_VIEW_GO							32802
#define	ID_VIEW_ZOOM_PLUS					32803
#define	ID_VIEW_ZOOM_MINUS					32804
#define	ID_VIEW_ZOOM_400					32805
#define	ID_VIEW_ZOOM_200					32806
#define	ID_VIEW_ZOOM_150					32807
#define	ID_VIEW_ZOOM_125					32808
#define	ID_VIEW_ZOOM_100					32809
#define	ID_VIEW_ZOOM_75						32810
#define	ID_VIEW_ZOOM_50						32811
#define	ID_VIEW_ZOOM_CUSTOM					32812
#define	ID_VIEW_CHAR_MAX					32813
#define	ID_VIEW_CHAR_LARGE					32814
#define	ID_VIEW_CHAR_MIDDLE					32815
#define	ID_VIEW_CHAR_SMALL					32816
#define	ID_VIEW_CHAR_MIN					32817
#define	ID_VIEW_ENCODE_AUTO					32818
#define	ID_VIEW_ENCODE_TO_RIGHT				32819
#define	ID_VIEW_ENCODE_TO_LEFT				32820
#define	ID_VIEW_STYLE_NONE					32821
#define	ID_VIEW_STYLE_DEFAULT				32822
#define	ID_VIEW_CURSOR_BROWSE				32823
#define	ID_VIEW_SOURCE						32824
#define	ID_VIEW_SECURITY_REPORT				32825
#define	ID_VIEW_DOMAIN						32826
#define	ID_VIEW_PRIVACY_POLICY				32827
#define	ID_VIEW_FULL_SCREEN					32828
#define	ID_FAVORITE_ADD_TO_BAR				32829
#define	ID_FAVORITE_ADD_ALLTAB				32830
#define	ID_TOOL_CLEAR_HISTORY				32831
#define	ID_TOOL_INPRIVATE_BROWSE			32832
#define	ID_TOOL_CHECK_NETSTAT				32833
#define	ID_TOOL_OPEN_LAST_SESSION			32834
#define	ID_TOOL_INPRIVATE_FILTER			32835
#define	ID_TOOL_INPRIVATE_FILTER_OPTION		32836
#define	ID_TOOL_POPUP_DISABLE				32837
#define	ID_TOOL_POPUP_OPTION				32838
#define	ID_TOOL_CHECK_THIS_SITE				32839
#define	ID_TOOL_SMARTSCREEN_DISABLE			32840
#define	ID_TOOL_SEND_REPORT					32841
#define	ID_TOOL_MANAGE_ADDON				32842
#define	ID_TOOL_FEED_ADD					32843
#define	ID_TOOL_FEED_FIND					32844
#define	ID_TOOL_WINDOWS_UPDATE				32845
#define	ID_TOOL_DEVELOP						32846
#define	ID_TOOL_INTERNET_OPTION				32847

tabbrowser146.gif
手動でリソースIDを編集するときに一番気をつけなければいけないのが、APSTUDIO_INVOKEDで囲まれた部分の定義だ。

ここにはリソースエディタで新しくIDを作るときに、次の新しいIDで利用する番号が保存されている。ここの編集を忘れると、違う名前で同じ番号のIDがリソースエディタによって生成されてしまう。

新しく生成したIDのうちの最大の値よりも1つ大きい値を今回の場合は「_APS_NEXT_COMMAND_VALUE」を「32848」として定義しておく。
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        202
#define _APS_NEXT_COMMAND_VALUE         32848
#define _APS_NEXT_CONTROL_VALUE         1000
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif

tabbrowser147.gif
これでビルド/実行すると無事にメニュー項目が増えた。

今回のメニュー項目の追加では、キーボードショートカットを無視した。次回は今回追加したメニュー項目のキーボードショートカットを設定する。

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

第36回 キーボードショートカットを設定する (タブブラウザーを作る)

tabbrowser148.gif
前回はタブブラウザーに(機能は実装していないものの)メニュー項目を大量追加した。今回はメニューに割り当てられているショートカットキーの設定、未実装項目のグレーアウトをする。

キーボードショートカットの設定はリソースのアクセラレーターで行う。今回も数が多いのでリソースファイルを直接編集することにした。ソリューションエクスプローラーで「TabBrowser100.rc」を右クリックして現われるメニューから「コードの表示」を選択する。

tabbrowser149.gif リソースファイルが開いたら、「Accelerator」セクションにある定義をメニューに即したものに書き換える。今回は以下のようにした。
/////////////////////////////////////////////////////////////////////////////
//
// Accelerator
//

IDR_MAINFRAME ACCELERATORS 
BEGIN
    "T",            ID_FILE_NEW,                VIRTKEY, CONTROL
    "K",            ID_FILE_COPY_TAB,           VIRTKEY, CONTROL
    "N",            ID_FILE_NEW_WINDOW,         VIRTKEY, CONTROL
    "O",            ID_FILE_OPEN,               VIRTKEY, CONTROL
    "S",            ID_FILE_SAVE,               VIRTKEY, CONTROL
    "W",            ID_WINDOW_CLOSE,            VIRTKEY, CONTROL
    "P",            ID_FILE_PRINT,              VIRTKEY, CONTROL
    "X",            ID_EDIT_CUT,                VIRTKEY, CONTROL
    "C",            ID_EDIT_COPY,               VIRTKEY, CONTROL
    "V",            ID_EDIT_PASTE,              VIRTKEY, CONTROL
    "A",            ID_EDIT_SELECT_ALL,         VIRTKEY, CONTROL
    "F",            ID_EDIT_FIND,               VIRTKEY, CONTROL
    "Q",            ID_VIEW_QUICKTAB,           VIRTKEY, CONTROL
    "I",            ID_VIEW_FAVORITE,           VIRTKEY, CONTROL, SHIFT
    "H",            ID_VIEW_HISTORY,            VIRTKEY, CONTROL, SHIFT
    "J",            ID_VIEW_FEED,               VIRTKEY, CONTROL, SHIFT
    VK_ESCAPE,      ID_IE_STOP,                 VIRTKEY
    VK_F5,          ID_IE_REFRESH,              VIRTKEY
    VK_ADD,         ID_VIEW_ZOOM_PLUS,          VIRTKEY, CONTROL
    VK_SUBTRACT,    ID_VIEW_ZOOM_MINUS,         VIRTKEY, CONTROL
    VK_F7,          ID_VIEW_CURSOR_BROWSE,      VIRTKEY
    VK_F11,         ID_VIEW_FULL_SCREEN,        VIRTKEY
    VK_F4,          ID_WINDOW_CLOSE,            VIRTKEY, CONTROL
    VK_DELETE,      ID_TOOL_CLEAR_HISTORY,      VIRTKEY, CONTROL, SHIFT
    "P",            ID_TOOL_INPRIVATE_BROWSE,   VIRTKEY, CONTROL, SHIFT
    "F",            ID_TOOL_INPRIVATE_FILTER,   VIRTKEY, CONTROL, SHIFT
    VK_F12,         ID_TOOL_DEVELOP,            VIRTKEY
    VK_BACK,        ID_EDIT_UNDO,           VIRTKEY, ALT
    VK_DELETE,      ID_EDIT_CUT,            VIRTKEY, SHIFT
    VK_INSERT,      ID_EDIT_COPY,           VIRTKEY, CONTROL
    VK_INSERT,      ID_EDIT_PASTE,          VIRTKEY, SHIFT
    VK_F6,          ID_NEXT_PANE,           VIRTKEY 
    VK_F6,          ID_PREV_PANE,           VIRTKEY, SHIFT
END

tabbrowser150.gif
さらに追加したメニュー項目を選択できないようにグレー表示にする。

「MainFrm.h」を開き、追加したメニュー項目をUIアイテムとして登録、無効化する。向こうにするだけなので本来ならOnCreateでUIEnable設定するべきだが、今後修正が楽なように今回はOnIdleに配置した。
	virtual BOOL OnIdle()
	{
		CTabBrowser100View*	pView;

		pView = GetActivePageView();

		//「戻る」「進む」ボタンの状態設定
		{
			bool	bBack = false;
			bool	bNext = false;

			if(pView)
				pView->IsButtonEnable(bBack,bNext);

			UIEnable(ID_IE_BACK,bBack ? TRUE : FALSE);
			UIEnable(ID_IE_NEXT,bNext ? TRUE : FALSE);
		}

		//「編集」メニュー項目更新
		{
			bool	bCopy		= false;
			bool	bCut		= false;
			bool	bPaste		= false;
			bool	bSelectAll	= false;

			if(pView)
				pView->IsEnable_EditCommand(bCopy,bCut,bPaste,bSelectAll);

			UIEnable(ID_EDIT_COPY		,bCopy ? TRUE : FALSE);
			UIEnable(ID_EDIT_CUT		,bCut ? TRUE : FALSE);
			UIEnable(ID_EDIT_PASTE		,bPaste ? TRUE : FALSE);
			UIEnable(ID_EDIT_SELECT_ALL	,bSelectAll ? TRUE : FALSE);
		}


		//■追加 未実装メニュー項目を全部無効に設定
		{
			UIEnable(ID_FILE_COPY_TAB, FALSE);
			UIEnable(ID_FILE_NEW_WINDOW, FALSE);
			UIEnable(ID_FILE_NEW_SESSION, FALSE);
			UIEnable(ID_FILE_OPEN, FALSE);
			UIEnable(ID_FILE_EDIT, FALSE);
			UIEnable(ID_FILE_SAVE, FALSE);
			UIEnable(ID_FILE_SAVE_AS, FALSE);
			UIEnable(ID_FILE_SEND_PAGE, FALSE);
			UIEnable(ID_FILE_SEND_LINK, FALSE);
			UIEnable(ID_FILE_CREATE_SHORTCUT, FALSE);
			UIEnable(ID_FILE_INPORT_EXPORT, FALSE);
			UIEnable(ID_FILE_PROPERTY, FALSE);
			UIEnable(ID_FILE_OFFLINE, FALSE);
			UIEnable(ID_EDIT_FIND, FALSE);
			UIEnable(ID_VIEW_FIXED, FALSE);
			UIEnable(ID_VIEW_QUICKTAB, FALSE);
			UIEnable(ID_VIEW_FAVORITE, FALSE);
			UIEnable(ID_VIEW_HISTORY, FALSE);
			UIEnable(ID_VIEW_FEED, FALSE);
			UIEnable(ID_VIEW_GO, FALSE);
			UIEnable(ID_VIEW_ZOOM_PLUS, FALSE);
			UIEnable(ID_VIEW_ZOOM_MINUS, FALSE);
			UIEnable(ID_VIEW_ZOOM_400, FALSE);
			UIEnable(ID_VIEW_ZOOM_200, FALSE);
			UIEnable(ID_VIEW_ZOOM_150, FALSE);
			UIEnable(ID_VIEW_ZOOM_125, FALSE);
			UIEnable(ID_VIEW_ZOOM_100, FALSE);
			UIEnable(ID_VIEW_ZOOM_75, FALSE);
			UIEnable(ID_VIEW_ZOOM_50, FALSE);
			UIEnable(ID_VIEW_ZOOM_CUSTOM, FALSE);
			UIEnable(ID_VIEW_CHAR_MAX, FALSE);
			UIEnable(ID_VIEW_CHAR_LARGE, FALSE);
			UIEnable(ID_VIEW_CHAR_MIDDLE, FALSE);
			UIEnable(ID_VIEW_CHAR_SMALL, FALSE);
			UIEnable(ID_VIEW_CHAR_MIN, FALSE);
			UIEnable(ID_VIEW_ENCODE_AUTO, FALSE);
			UIEnable(ID_VIEW_ENCODE_TO_RIGHT, FALSE);
			UIEnable(ID_VIEW_ENCODE_TO_LEFT, FALSE);
			UIEnable(ID_VIEW_STYLE_NONE, FALSE);
			UIEnable(ID_VIEW_STYLE_DEFAULT, FALSE);
			UIEnable(ID_VIEW_CURSOR_BROWSE, FALSE);
			UIEnable(ID_VIEW_SOURCE, FALSE);
			UIEnable(ID_VIEW_SECURITY_REPORT, FALSE);
			UIEnable(ID_VIEW_DOMAIN, FALSE);
			UIEnable(ID_VIEW_PRIVACY_POLICY, FALSE);
			UIEnable(ID_VIEW_FULL_SCREEN, FALSE);
			UIEnable(ID_FAVORITE_ADD_TO_BAR, FALSE);
			UIEnable(ID_FAVORITE_ADD_ALLTAB, FALSE);
			UIEnable(ID_TOOL_CLEAR_HISTORY, FALSE);
			UIEnable(ID_TOOL_INPRIVATE_BROWSE, FALSE);
			UIEnable(ID_TOOL_CHECK_NETSTAT, FALSE);
			UIEnable(ID_TOOL_OPEN_LAST_SESSION, FALSE);
			UIEnable(ID_TOOL_INPRIVATE_FILTER, FALSE);
			UIEnable(ID_TOOL_INPRIVATE_FILTER_OPTION, FALSE);
			UIEnable(ID_TOOL_POPUP_DISABLE, FALSE);
			UIEnable(ID_TOOL_POPUP_OPTION, FALSE);
			UIEnable(ID_TOOL_CHECK_THIS_SITE, FALSE);
			UIEnable(ID_TOOL_SMARTSCREEN_DISABLE, FALSE);
			UIEnable(ID_TOOL_SEND_REPORT, FALSE);
			UIEnable(ID_TOOL_MANAGE_ADDON, FALSE);
			UIEnable(ID_TOOL_FEED_ADD, FALSE);
			UIEnable(ID_TOOL_FEED_FIND, FALSE);
			UIEnable(ID_TOOL_WINDOWS_UPDATE, FALSE);
			UIEnable(ID_TOOL_DEVELOP, FALSE);
			UIEnable(ID_TOOL_INTERNET_OPTION, FALSE);
		}

		UIUpdateToolBar();
		return FALSE;
	}

	BEGIN_UPDATE_UI_MAP(CMainFrame)
		UPDATE_ELEMENT(ID_VIEW_TOOLBAR, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_STATUS_BAR, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_IE_BACK, UPDUI_TOOLBAR)
		UPDATE_ELEMENT(ID_IE_NEXT, UPDUI_TOOLBAR)
		UPDATE_ELEMENT(ID_EDIT_COPY, UPDUI_TOOLBAR | UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_EDIT_CUT, UPDUI_TOOLBAR | UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_EDIT_PASTE, UPDUI_TOOLBAR | UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_EDIT_SELECT_ALL, UPDUI_TOOLBAR | UPDUI_MENUPOPUP)
		//■以下追加
		UPDATE_ELEMENT(ID_FILE_COPY_TAB, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_FILE_NEW_WINDOW, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_FILE_NEW_SESSION, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_FILE_OPEN, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_FILE_EDIT, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_FILE_SAVE, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_FILE_SAVE_AS, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_FILE_SEND_PAGE, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_FILE_SEND_LINK, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_FILE_CREATE_SHORTCUT, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_FILE_INPORT_EXPORT, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_FILE_PROPERTY, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_FILE_OFFLINE, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_EDIT_FIND, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_FIXED, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_QUICKTAB, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_FAVORITE, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_HISTORY, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_FEED, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_GO, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_ZOOM_PLUS, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_ZOOM_MINUS, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_ZOOM_400, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_ZOOM_200, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_ZOOM_150, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_ZOOM_125, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_ZOOM_100, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_ZOOM_75, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_ZOOM_50, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_ZOOM_CUSTOM, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_CHAR_MAX, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_CHAR_LARGE, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_CHAR_MIDDLE, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_CHAR_SMALL, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_CHAR_MIN, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_ENCODE_AUTO, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_ENCODE_TO_RIGHT, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_ENCODE_TO_LEFT, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_STYLE_NONE, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_STYLE_DEFAULT, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_CURSOR_BROWSE, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_SOURCE, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_SECURITY_REPORT, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_DOMAIN, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_PRIVACY_POLICY, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_FULL_SCREEN, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_FAVORITE_ADD_TO_BAR, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_FAVORITE_ADD_ALLTAB, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_TOOL_CLEAR_HISTORY, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_TOOL_INPRIVATE_BROWSE, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_TOOL_CHECK_NETSTAT, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_TOOL_OPEN_LAST_SESSION, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_TOOL_INPRIVATE_FILTER, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_TOOL_INPRIVATE_FILTER_OPTION, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_TOOL_POPUP_DISABLE, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_TOOL_POPUP_OPTION, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_TOOL_CHECK_THIS_SITE, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_TOOL_SMARTSCREEN_DISABLE, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_TOOL_SEND_REPORT, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_TOOL_MANAGE_ADDON, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_TOOL_FEED_ADD, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_TOOL_FEED_FIND, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_TOOL_WINDOWS_UPDATE, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_TOOL_DEVELOP, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_TOOL_INTERNET_OPTION, UPDUI_MENUPOPUP)
	END_UPDATE_UI_MAP()

tabbrowser151.gif
これでビルド/実行すると未実装なメニュー項目がグレーアウトし、選択できなくなった。

本当はさらにステータスバーへのメッセージ表示やTIPSが表示されるように、ストリングリソースの編集も行うべきだが、数が多く面倒なので保留しておく。

次回は「ファイル」メニューの「プロパティ」などいくつかのメニュー項目を実装する。

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

第37回 「プロパティ」「保存」「ページ内検索」「ショートカット作成」を実装する (タブブラウザーを作る)

tabbrowser152.gif
今回はいくつかの簡単に実現できるメニュー項目の実装を行う。

「ファイル」メニューの「上書き保存」「名前を付けて保存」「プロパティ」および「編集」メニューの「このページの検索」機能はIWebBrowser2::ExecWBを呼び出すことで実行できる。

「ファイル」メニューの「送信」にある「ショートカットをデスクトップへ」はIWebBrowser2からIShellBrowserを取り出してIOleCommandTarget::Execにより実行できる。

これらの実装をCIEUtilityに追加する。
	//■追加
	bool	Save(void)
	{
		if(_pIWebBrowser2 == NULL)
			return	false;
		return	SUCCEEDED(_pIWebBrowser2->ExecWB(OLECMDID_SAVE,MSOCMDEXECOPT_DODEFAULT,NULL,NULL)) ? true : false;
	}

	//■追加
	//mhtには対応しない
	bool	SaveAs(void)
	{
		CComVariant	vIn(L"");			//これでファイル名指定

		if(_pIWebBrowser2 == NULL)
			return	false;
		return	SUCCEEDED(_pIWebBrowser2->ExecWB(OLECMDID_SAVEAS,MSOCMDEXECOPT_DODEFAULT,&vIn,NULL)) ? true : false;
	}

	//■追加
	bool	ShowProperty(void)
	{
		if(_pIWebBrowser2 == NULL)
			return	false;
		return	SUCCEEDED(_pIWebBrowser2->ExecWB(OLECMDID_PROPERTIES,OLECMDEXECOPT_PROMPTUSER,NULL,NULL)) ? true : false;
	}

	//■追加
	bool	ShowFind(void)
	{
		if(_pIWebBrowser2 == NULL)
			return	false;
		return	SUCCEEDED(_pIWebBrowser2->ExecWB(OLECMDID_FIND,OLECMDEXECOPT_PROMPTUSER,NULL,NULL)) ? true : false;
	}

	//■追加
	HRESULT	ExecExplorer(IWebBrowser2* pIWebBrowser2,DWORD nCmdID,DWORD nCmdExecOpt,VARIANTARG *pvaIn,VARIANTARG *pvaOut)
	{
		HRESULT		hr;
		CComPtr<IShellBrowser>		pIShellBrowser;

		if(pIWebBrowser2 == NULL)
			return	E_FAIL;

		hr = IUnknown_QueryService(pIWebBrowser2,SID_STopLevelBrowser,IID_IShellBrowser,(void**)&pIShellBrowser);
		if(SUCCEEDED(hr))
			hr = IUnknown_Exec(pIShellBrowser,&CGID_Explorer,nCmdID,nCmdExecOpt,pvaIn,pvaOut);

		return	hr;
	}

	//■追加
	bool	CreateShortcut(void)
	{
		//定数はshlobj.hから
		#ifndef	SBCMDID_CREATESHORTCUT
			#define SBCMDID_CREATESHORTCUT		17
		#endif

		return	SUCCEEDED(ExecExplorer(_pIWebBrowser2,SBCMDID_CREATESHORTCUT,OLECMDEXECOPT_PROMPTUSER,NULL,NULL)) ? true : false;
	}

tabbrowser153.gif そして「MainFrm.h」でメニューが選択されたときに上で実装した関数が呼びだされるようにする。
		COMMAND_ID_HANDLER(ID_EDIT_PASTE, OnFileCommand)
		COMMAND_ID_HANDLER(ID_EDIT_SELECT_ALL, OnFileCommand)
		COMMAND_ID_HANDLER(ID_FILE_SAVE, OnFileCommand)				//■追加
		COMMAND_ID_HANDLER(ID_FILE_SAVE_AS, OnFileCommand)			//■追加
		COMMAND_ID_HANDLER(ID_FILE_CREATE_SHORTCUT, OnFileCommand)	//■追加
		COMMAND_ID_HANDLER(ID_FILE_PROPERTY, OnFileCommand)			//■追加
		COMMAND_ID_HANDLER(ID_EDIT_FIND, OnFileCommand)				//■追加
		COMMAND_RANGE_HANDLER(ID_WINDOW_TABFIRST, ID_WINDOW_TABLAST, OnWindowActivate)
		COMMAND_ID_HANDLER(ID_IE_BACK, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_NEXT, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_STOP, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_REFRESH, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_ADDFAVORITE, OnIEAddFavorite)
		COMMAND_ID_HANDLER(ID_IE_ORGANIZE_FAVORITE, OnIEOrganizeFavorite)
		NOTIFY_CODE_HANDLER(TBVN_CONTEXTMENU, OnTabContextMenu)
		NOTIFY_CODE_HANDLER(TBVN_PAGEACTIVATED, OnTabPageActivated)
		NOTIFY_HANDLER(ATL_IDW_STATUS_BAR, NM_DBLCLK, OnStatusBarDblClk)
		MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)
		MESSAGE_HANDLER(WM_SIZE, OnSize)
		COMMAND_RANGE_HANDLER(ID_FAVORITE_FIRST,ID_FAVORITE_LAST,OnFavorite)
		CHAIN_MSG_MAP_MEMBER(_cFovMenu)
		CHAIN_MSG_MAP(CUpdateUI<CMainFrame>)
		CHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>)
	END_MSG_MAP()


	LRESULT OnFileCommand(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& bHandled)
	{
		CTabBrowser100View*	pView;

		pView = GetActivePageView();
		if(pView == NULL)
		{
			bHandled = FALSE;
			return	0;
		}

		bHandled = TRUE;
		switch(wID)
		{
			///////////////////////
			//■追加ここから
		case	ID_FILE_SAVE:				//上書き保存
			pView->Save();
			break;

		case	ID_FILE_SAVE_AS:			//名前を付けて保存
			pView->SaveAs();
			break;

		case	ID_FILE_CREATE_SHORTCUT:	//デスクトップにリンク作成
			pView->CreateShortcut();
			break;

		case	ID_FILE_PROPERTY:			//プロパティ
			pView->ShowProperty();
			break;

		case	ID_EDIT_FIND:				//検索
			pView->ShowFind();
			break;
			//■追加ここまで
			///////////////////////

		case	ID_EDIT_COPY:				//コピー
			pView->Copy();
			break;

		case	ID_EDIT_CUT:				//切り取り
			pView->Cut();
			break;

		case	ID_EDIT_PASTE:				//貼り付け
			pView->Paste();
			break;

		case	ID_EDIT_SELECT_ALL:			//全てを選択
			pView->SelectAll();
			break;

		case	ID_FILE_PRINT:				//印刷
			pView->PrintOrPreview(true);
			break;

		case	ID_FILE_PRINT_PREVIEW:		//印刷プレビュー
			pView->PrintOrPreview(false);
			break;

		case	ID_FILE_PRINT_SETUP:		//印刷セットアップ
			pView->PrintSetup();
			break;

		default:
			bHandled = FALSE;
			break;
		}

		return	0;
	}

tabbrowser154.gif メニュー項目が無効化されているので、有効化しておく。本来であればコマンドを利用できるときのみ有効にするべきだが、その作業は今後行うことにして今は保留しておく。
		//未実装メニュー項目を全部無効に設定
		{
			UIEnable(ID_FILE_COPY_TAB, FALSE);
			UIEnable(ID_FILE_NEW_WINDOW, FALSE);
			UIEnable(ID_FILE_NEW_SESSION, FALSE);
			UIEnable(ID_FILE_OPEN, FALSE);
			UIEnable(ID_FILE_EDIT, FALSE);
//			UIEnable(ID_FILE_SAVE, FALSE);				//■コメントアウト 有効/無効設定必要
//			UIEnable(ID_FILE_SAVE_AS, FALSE);			//■コメントアウト 有効/無効設定必要
			UIEnable(ID_FILE_SEND_PAGE, FALSE);
			UIEnable(ID_FILE_SEND_LINK, FALSE);
//			UIEnable(ID_FILE_CREATE_SHORTCUT, FALSE);	//■コメントアウト 有効/無効設定必要
			UIEnable(ID_FILE_INPORT_EXPORT, FALSE);
//			UIEnable(ID_FILE_PROPERTY, FALSE);			//■コメントアウト 有効/無効設定必要
			UIEnable(ID_FILE_OFFLINE, FALSE);
//			UIEnable(ID_EDIT_FIND, FALSE);				//■コメントアウト 有効/無効設定必要
			UIEnable(ID_VIEW_FIXED, FALSE);
			UIEnable(ID_VIEW_QUICKTAB, FALSE);
			UIEnable(ID_VIEW_FAVORITE, FALSE);
			UIEnable(ID_VIEW_HISTORY, FALSE);
			UIEnable(ID_VIEW_FEED, FALSE);

tabbrowser155.gif
これで実行すると今回実装したメニューが利用できるようになった。

試してみると「保存」コマンドはInternet Explorer 8では.mhtファイルへの保存に対応しているが、今回の実装ではうまく動かない。ページが完全に読み込み終わる前にメニューを選択するとmhtファイルの選択欄が現れるが、ページが読み込まれた後にメニューを選択すると選択肢が消えてしまう。IE8だからなのかはわからないがどうも挙動がおかしい。それらの調査は今後行うことにして今は保留しておく。

次回はメニュー関連からは少し離れてステータスバーを少し見直す。

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

2009年04月08日

第38回 ステータスバー関連処理の実装を見直す (タブブラウザーを作る)

tabbrowser156.gif
これまでにステータスバーにIEコントロールからのメッセージを表示、スクリプトエラーがあったときにエラーメッセージとアイコンの表示、スクリプトエラー時にダブルクリックでエラーの詳細情報を表示する機能を実装した。

しかしその過程でかなりソースコードがゴチャゴチャして崩壊寸前にまで追い込まれている。これからステータスバー関連の処理を整理する。まずはその前段階としてMainFrm.h内のステータスバー関連処理をすべてコメントアウトしてしまう。

ステータスバーの処理はビューからメインウインドウへメッセージを送ることで開始していた。それらのメッセージマップをコメントアウトする。
	BEGIN_MSG_MAP(CMainFrame)
		MESSAGE_HANDLER(WM_DNP_CREATENEWTAB, OnDnpCreateNewTab)
		MESSAGE_HANDLER(WM_DNP_CHANGEFOCUS, OnDnpChangeFocus)
		MESSAGE_HANDLER(WM_DNP_CHANGEADDRESS, OnDnpChangeAddress)
//		MESSAGE_HANDLER(WM_DNP_CHANGESTATUSTEXT, OnDnpChangeStatusText)	//■コメントアウト
//		MESSAGE_HANDLER(WM_DNP_CHANGEPROGRESS, OnDnpChangeProgress)		//■コメントアウト
//		MESSAGE_HANDLER(WM_DNP_SCRIPTERROR, OnDnpScriptError)			//■コメントアウト
		NOTIFY_CODE_HANDLER(CBEN_ENDEDIT, OnAddressbarEnter)
		MESSAGE_HANDLER(WM_CREATE, OnCreate)
		MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
		COMMAND_ID_HANDLER(ID_APP_EXIT, OnFileExit)
		COMMAND_ID_HANDLER(ID_FILE_NEW, OnFileNew)
		COMMAND_ID_HANDLER(ID_VIEW_TOOLBAR, OnViewToolBar)
		COMMAND_ID_HANDLER(ID_VIEW_STATUS_BAR, OnViewStatusBar)
		COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)
		COMMAND_ID_HANDLER(ID_WINDOW_CLOSE, OnWindowClose)
		COMMAND_ID_HANDLER(ID_WINDOW_CLOSE_ALL, OnWindowCloseAll)
		COMMAND_ID_HANDLER(ID_FILE_PRINT, OnFileCommand)
		COMMAND_ID_HANDLER(ID_FILE_PRINT_PREVIEW, OnFileCommand)
		COMMAND_ID_HANDLER(ID_FILE_PRINT_SETUP, OnFileCommand)
		COMMAND_ID_HANDLER(ID_EDIT_COPY, OnFileCommand)
		COMMAND_ID_HANDLER(ID_EDIT_CUT, OnFileCommand)
		COMMAND_ID_HANDLER(ID_EDIT_PASTE, OnFileCommand)
		COMMAND_ID_HANDLER(ID_EDIT_SELECT_ALL, OnFileCommand)
		COMMAND_ID_HANDLER(ID_FILE_SAVE, OnFileCommand)
		COMMAND_ID_HANDLER(ID_FILE_SAVE_AS, OnFileCommand)
		COMMAND_ID_HANDLER(ID_FILE_CREATE_SHORTCUT, OnFileCommand)
		COMMAND_ID_HANDLER(ID_FILE_PROPERTY, OnFileCommand)
		COMMAND_ID_HANDLER(ID_EDIT_FIND, OnFileCommand)
		COMMAND_RANGE_HANDLER(ID_WINDOW_TABFIRST, ID_WINDOW_TABLAST, OnWindowActivate)
		COMMAND_ID_HANDLER(ID_IE_BACK, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_NEXT, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_STOP, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_REFRESH, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_ADDFAVORITE, OnIEAddFavorite)
		COMMAND_ID_HANDLER(ID_IE_ORGANIZE_FAVORITE, OnIEOrganizeFavorite)
		NOTIFY_CODE_HANDLER(TBVN_CONTEXTMENU, OnTabContextMenu)
		NOTIFY_CODE_HANDLER(TBVN_PAGEACTIVATED, OnTabPageActivated)
//		NOTIFY_HANDLER(ATL_IDW_STATUS_BAR, NM_DBLCLK, OnStatusBarDblClk)	//■コメントアウト
		MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)
//		MESSAGE_HANDLER(WM_SIZE, OnSize)									//■コメントアウト
		COMMAND_RANGE_HANDLER(ID_FAVORITE_FIRST,ID_FAVORITE_LAST,OnFavorite)
		CHAIN_MSG_MAP_MEMBER(_cFovMenu)
		CHAIN_MSG_MAP(CUpdateUI<CMainFrame>)
		CHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>)
	END_MSG_MAP()

tabbrowser157.gif そして関連した関数とメンバー変数をコメントアウトする。
class CMainFrame : public CFrameWindowImpl<CMainFrame>, public CUpdateUI<CMainFrame>,
		public CMessageFilter, public CIdleHandler
{
	CAddressBarCtrl	_wndAddressBar;			// アドレスバー用コンボボックス

	////■コメントアウト
	//CIconManager	_cIconList;

public:

	////■コメントアウト
	////ステータスバーのダブルクリック処理
	//LRESULT OnStatusBarDblClk(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
	//{
	//	bHandled = FALSE;

	//	NMMOUSE*	pNmMouse = (NMMOUSE*)pnmh;
	//	CTabBrowser100View*	pView;

	//	if(pNmMouse == NULL)
	//		return	0;

	//	if(pNmMouse->dwItemSpec == 0)
	//	{
	//		//ゼロ番目のペインがダブルクリックされた
	//		pView = GetActivePageView();
	//		if(pView)
	//			pView->ShowScriptError();			//スクリプトエラー情報を表示する
	//	}

	//	return	0;
	//}


	////■コメントアウト
	//LRESULT OnDnpChangeProgress(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	//{
	//	RefreshProgressBar((long)wParam,(long)lParam);
	//	return	0;
	//}


	////■コメントアウト
	//LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	//{
	//	bHandled = FALSE;

	//	if(_wndProgressBar.IsWindow())
	//		RefreshProgressBar();		//プログレスバー表示更新

	//	return	0;
	//}

	////■コメントアウト
	//CProgressBarCtrl	_wndProgressBar;			//ステータスバーに配置するプログレスバーコントロール

	////■コメントアウト
	////bVisible=falseならプログレスバーを消す
	////nProgress < 0、nProgressMax < 0ならプログレス設定はしない
	////nProgressMax < nProgressなら強制的に非表示にする
	//bool	RefreshProgressBar(int nProgress=-1,int nProgressMax=-1,bool bVisible=true)
	//{
	//	if(::IsWindow(m_hWndStatusBar) == FALSE)
	//		return	false;				//ステータスバーがない

	//	int		nProgressWidth = 100;			//■プログレスバーの幅は100px固定とする
	//	CRect	rect;
	//	CStatusBarCtrl	wndStatusBar = m_hWndStatusBar;

	//	if(nProgressMax < nProgress)
	//		bVisible = false;

	//	if(bVisible == false)
	//		nProgressWidth = 0;

	//	//ステータスバーのペインの作成/更新
	//	{
	//		int		pnParts[2];						//2つペインを作成(1つはデフォルト、もう1つはプログレスバー用)

	//		wndStatusBar.GetClientRect(&rect);
	//		pnParts[0] = rect.Width() - nProgressWidth;
	//		pnParts[1] = rect.Width();

	//		wndStatusBar.SetParts(sizeof(pnParts) / sizeof(pnParts[0]),pnParts);
	//	}


	//	//プログレスバーの生成/更新
	//	{
	//		wndStatusBar.GetRect(1,&rect);			//2つめのペインをプログレスバーに利用する

	//		if(_wndProgressBar.IsWindow() == FALSE)
	//			_wndProgressBar.Create(m_hWndStatusBar,rect,0,WS_CHILD);	//プログレスバーを生成
	//		else
	//			_wndProgressBar.MoveWindow(&rect);			//位置を移動

	//		if(bVisible)
	//		{
	//			if(_wndProgressBar.IsWindowVisible() == FALSE)
	//				_wndProgressBar.ShowWindow(SW_NORMAL);		//可視に
	//		}
	//		else
	//		{
	//			if(_wndProgressBar.IsWindowVisible())
	//				_wndProgressBar.ShowWindow(SW_HIDE);		//不可視に
	//		}

	//		//プログレスの設定
	//		if(nProgressMax >= 0)
	//			_wndProgressBar.SetRange(0,nProgressMax);
	//		if(nProgress >= 0)
	//			_wndProgressBar.SetPos(nProgress);
	//	}

	//	return	true;
	//}




	////■コメントアウト
	////ステータスバーの表示テキストの変更処理
	////アクティブなタブのIEでステータスバーのテキストが変わったときにメッセージが届く
	//LRESULT OnDnpChangeStatusText(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	//{
	//	LPCTSTR		pszText = (LPCTSTR)wParam;

	//	if(pszText == NULL)
	//		return	0;

	//	if(::IsWindow(m_hWndStatusBar))
	//		::SetWindowText(m_hWndStatusBar,pszText);

	//	return	0;
	//}

tabbrowser158.gif Visual Studioではコメントアウトしたい部分を選択して、[Ctrl+K]→[Ctrl+C]とキー操作をするとその部分がコメントアウトされる。逆にコメントを外したい場合は[Ctrl+U]とキー操作する。覚えておくと今回のようにコメントアウトする部分が多いときに便利だ。
	//タブが選択されたときの処理
	LRESULT OnTabPageActivated(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
	{
		if(pnmh == NULL)
			return	0;

		//全てのビューに対してタブ変更があったことを通知
		{
			int		i;
			int		nCount;
			CTabBrowser100View*	pView;

			int kk=m_view.GetActivePage();

			nCount = m_view.GetPageCount();
			for(i = 0; i < nCount; i++)
			{
				pView = GetPageView(i);
				if(pView == NULL)
					continue;

				if(pnmh->idFrom == i)
					pView->OnTabPageChange(true);
				else
					pView->OnTabPageChange(false);
			}
		}

		bool		ret;
		CTabBrowser100View*	pView;

		pView = GetActivePageView();		//アクティブビュー取得
		if(pView == NULL)
			return	0;

		//アドレスバーのURL変更
		{
			CAtlString	strURL;

			ret = pView->GetURL(strURL);		//URL取得
			if(ret)
				_wndAddressBar.SetWindowText(strURL);
		}

		////■コメントアウト
		////ステータスバーのテキスト変更
		//{
		//	CAtlString	strText;

		//	pView->GetLastStatusText(strText);
		//	if(::IsWindow(m_hWndStatusBar))
		//		::SetWindowText(m_hWndStatusBar,strText);
		//}

		////■コメントアウト
		////ステータスバーのエラーアイコン変更
		//{
		//	CStatusBarCtrl	wndStatusBar = m_hWndStatusBar;

		//	if(wndStatusBar.IsWindow())
		//	{
		//		if(pView->IsPageError())
		//			wndStatusBar.SetIcon(0,_cIconList.GetIcon(CIconManager::ICON_WARNING_SM));
		//		else
		//			wndStatusBar.SetIcon(0,NULL);
		//	}
		//}

		////■コメントアウト
		////プログレス変更
		//{
		//	long	nProgress;
		//	long	nProgressMax;

		//	pView->GetLastProgress(nProgress,nProgressMax);
		//	RefreshProgressBar(nProgress,nProgressMax);
		//}

		return	0;
	}


	////■コメントアウト
	////ステータスバーのエラーアイコン変更
	//LRESULT OnDnpScriptError(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	//{
	//	BOOL	bPageError = (BOOL)wParam;
	//	CStatusBarCtrl	wndStatusBar = m_hWndStatusBar;

	//	if(wndStatusBar.IsWindow())
	//	{
	//		if(bPageError)
	//			wndStatusBar.SetIcon(0,_cIconList.GetIcon(CIconManager::ICON_WARNING_SM));
	//		else
	//			wndStatusBar.SetIcon(0,NULL);
	//	}

	//	return	0;
	//}

tabbrowser159.gif
ビューウインドウ側からメッセージを送る部分はコメントアウトしていないが、これでビルド/実行するとステータスバー関連の機能がすべて使えなくなった。

次回はステータスバー関連機能の再実装を行う。

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

前の10件 1  2  3  4  5  6  7





usefullcode@gmail.com

About 2009年04月

2009年04月にブログ「UsefullCode.net」に投稿されたすべてのエントリーです。

前の記事は2009年03月です。

次の記事は2010年05月です。

他にも多くのエントリーがあります。メインページ記事一覧も見てください。