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

前の10件 1  2  3  4  5  6  7

2009年04月 記事一覧

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

tabbrowser160.gif
前回はステータスバー関連処理を見直す前段階として「MainFrm.h」内の処理をコメントアウトした。今回はコメントアウトした処理を参考にしながらステータスバー関連処理を新しく作り直す。

まず「MainFrm.h」からCIconManagerを移動してくる。そしてスタータスバー用のクラスCIELikeStatusbarを作る。処理内容はCMainFrameから移動してきたものに少し変更を加えた程度だ。
#include "atlcoll.h"

//■CMainFrameから移動
//アイコンを管理
//アイコンを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	CIELikeStatusbar	: public CWindowImpl<CIELikeStatusbar>
{

	//■CMainFrameから移動
	CIconManager	_cIconList;

	//■CMainFrameから移動
	CProgressBarCtrl	_wndProgressBar;			//ステータスバーに配置するプログレスバーコントロール


	CAtlString	_strText;

	//■CTabBrowser100Viewから移動
	long	_nLastProgress;			//最後に受け取ったプログレス情報
	long	_nLastProgressMax;		//最後に受け取ったプログレス最大値

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

public:

	CIELikeStatusbar()
	{
		_nLastProgress		= -1;
		_nLastProgressMax	= -1;
		_bPageError = false;
	}


	BEGIN_MSG_MAP(CIELikeStatusbar)
		MESSAGE_HANDLER(WM_SIZE, OnSize)		//■CMainFrameから移動
	END_MSG_MAP()


	//■CMainFrameから移動
	LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		bHandled = FALSE;

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

		return	0;
	}


	//■CMainFrameから移動。m_hWndStatusBarをm_hWndに変更
	//bVisible=falseならプログレスバーを消す
	//nProgress < 0、nProgressMax < 0ならプログレス設定はしない
	//nProgressMax < nProgressなら強制的に非表示にする
	bool	RefreshProgressBar(int nProgress=-1,int nProgressMax=-1,bool bVisible=true)
	{
		//■追加
		if((nProgress >= 0 && nProgressMax  >= 0) || (nProgressMax < nProgress))
		{
			//状態を保存しておく
			_nLastProgress		= nProgress;
			_nLastProgressMax	= nProgressMax;
		}

		if(::IsWindow(m_hWnd) == FALSE)
			return	false;				//ステータスバー表示してない

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

		if(_nLastProgressMax < _nLastProgress)		//■変更
			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_hWnd,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(_nLastProgress >= 0)
				_wndProgressBar.SetRange(0,_nLastProgressMax);
			if(_nLastProgress >= 0)
				_wndProgressBar.SetPos(_nLastProgress);
		}

		return	true;
	}




	//ステータスバー表示更新
	bool	Refresh(bool bCapture)
	{
		if(bCapture == false)
		{
			if(_wndProgressBar.IsWindow())
			{
				if(_wndProgressBar.IsWindowVisible())
					_wndProgressBar.ShowWindow(SW_HIDE);		//不可視に
			}
			return	true;
		}

		if(IsWindow() == FALSE)
			return	false;

		//ステータスバーのテキスト変更
		{
			SetText(_strText);
		}

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

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

		//プログレス変更
		{
			RefreshProgressBar(_nLastProgress,_nLastProgressMax);
		}

		return	true;
	}


	bool	SetText(LPCTSTR pszText)
	{
		_strText = pszText;

		if(IsWindow() == FALSE)
			return	true;

		SetWindowText(pszText);

		return	true;
	}

	bool	SetPageError(bool bError)
	{
		_bPageError = bError;			//エラーが発生したことを保持

		if(IsWindow())
		{
			CStatusBarCtrl	wndStatusBar = m_hWnd;

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

		return	true;
	}
};

tabbrowser162.gif そしてビュークラス内のステータスバー関連処理をCIELikeStatusbarを利用するものに変更しいらない部分を削除する。
	//■処理内容変更
	//ステータスバーのメッセージ変更
	void	ChangeStatusText(LPCTSTR pszText)
	{
		_strLastStatusText = pszText;		//いつでも参照できるようにクラスのメンバーに保存しておく

		GetLastStatusText(_strLastStatusText);

		_wndStatusbar.SetText(_strLastStatusText);
	}

	void __stdcall OnStatusTextChange(BSTR bstrText)
	{
		ChangeStatusText((CAtlString)bstrText);
	}


	//■処理内容変更
	//エラー発生/解消時に呼ぶ
	//bError=trueならエラー発生
	void	SetErrorState(bool bError)
	{
		_bPageError = bError;

		if(bError)
			ChangeStatusText(NULL);

		_wndStatusbar.SetPageError(bError);
	}

	//■削除
	//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);		//エラー情報をリセット
	}


	//■削除
	//long	_nLastProgress;			//最後に受け取ったプログレス情報
	//long	_nLastProgressMax;		//最後に受け取ったプログレス最大値



	//■処理内容変更
	void __stdcall OnProgressChange(long lProgress,long lProgressMax)
	{
		if(lProgress < 0 || (lProgressMax == 0 && lProgress == 0))	//MSDNには記述がないが(0,0)で終わることが多いため(0,0)でも非表示
			lProgressMax = lProgress - 1;		//lProgressMax < lProgress にしておく -> 自動的にプログレスバーが消える

		_wndStatusbar.RefreshProgressBar(lProgress,lProgressMax);
	}


	//■削除
	////最後にIEコントロールから受け取ったプログレス情報を返す
	//void	GetLastProgress(long& nProgress,long& nProgressMax)
	//{
	//	nProgress		= _nLastProgress;
	//	nProgressMax	= _nLastProgressMax;
	//}

tabbrowser161.gif コンストラクタの不要部分も忘れずにコメントアウトしておく。
	CTabBrowser100View(CTabView* pTabView,HWND hWndRebarIE)
	{
		_pTabView = pTabView;
//		_nLastProgress		= 0;		//■削除
//		_nLastProgressMax	= -1;		//■削除
		_hWndRebarIE = hWndRebarIE;
		_bPageError = false;
	}

tabbrowser163.gif 今回の修正ではビュークラス側から直接ステータスバーに文字表示などを行っている。そのままだと複数のタブ(ビュー)が開いているときに、複数のビューからステータスバーにアクセスしてしまうことになるので、タブ(ビュー)がアクティブなときだけステータスバーへのアクセスが有効になるようにする。
	CIELikeStatusbar	_wndStatusbar;		//■追加


	//■追加
	//メインウインドウから呼ばれる
	//bCapture=trueでこのビューがステータスバーを制御する
	//bCapture=falseでこのビューがステータスバーを解放する
	bool	SetStatusBar(HWND hWnd,bool bCapture)
	{
		if(bCapture)
		{
			if(_wndStatusbar.IsWindow())
				return	false;
			_wndStatusbar.SubclassWindow(hWnd);
			_wndStatusbar.Refresh(true);
		}
		else
		{
			if(_wndStatusbar.IsWindow())
				_wndStatusbar.UnsubclassWindow();
			_wndStatusbar.Refresh(false);
		}

		return	true;
	}

tabbrowser164.gif 「MainFrm.h」内でアクティブなビューにだけステータスバーを渡す。
	//タブが選択されたときの処理
	LRESULT OnTabPageActivated(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
	{
		if(pnmh == NULL)
			return	0;

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

			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);
					pView->SetStatusBar(m_hWndStatusBar,false);	//ステータスバー解放
				}
			}

			//■3行追加
			pView = GetActivePageView();
			if(pView)
				pView->SetStatusBar(m_hWndStatusBar,true);		//ステータスバーセット
		}


		bool		ret;
		CTabBrowser100View*	pView;

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

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

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

		return	0;
	}

tabbrowser165.gif
これでビルド/実行すると再びステータスバーへの表示が行われるようになった。

しかしまだステータスバーのダブルクリックに関する処理を再実装していない。次回はそれを行う。

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

第40回 ステータスバーダブルクリック処理を再実装する (タブブラウザーを作る)

tabbrowser166.gif
前回はステータスバーへメッセージやアイコンを表示する部分を再実装した。今回はスクリプトエラーが発生しているときにステータスバーのダブルクリックでエラーの詳細情報を表示する処理を再実装する。

ステータスバー用のクラスCIELikeStatusbarへダブルクリックを検出するためのメッセージ処理を追加する。これまではメインウインドウでNM_DBLCLKを処理することで簡単にダブルクリックされたペインまで取得できた。しかし今回はペインのRECTからダブルクリックされたペインを計算している。
class	CIELikeStatusbar	: public CWindowImpl<CIELikeStatusbar>
{
	CIconManager	_cIconList;

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


	CAtlString	_strText;

	long	_nLastProgress;			//最後に受け取ったプログレス情報
	long	_nLastProgressMax;		//最後に受け取ったプログレス最大値

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

	HWND	_hWndNotify;	//■追加 ダブルクリック通知先。通常ビューウインドウのHWND
public:

	CIELikeStatusbar()
	{
		_hWndNotify			= NULL;		//■追加
		_nLastProgress		= -1;
		_nLastProgressMax	= -1;
		_bPageError = false;
	}


	BEGIN_MSG_MAP(CIELikeStatusbar)
		MESSAGE_HANDLER(WM_SIZE, OnSize)
		MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDblClk)		//■追加
	END_MSG_MAP()


	//■追加
	//ステータスバーのダブルクリック処理
	LRESULT OnLButtonDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		int		i;
		RECT	rect;
		BOOL	ret;
		POINT	pt;

		CStatusBarCtrl	wndStatusBar = m_hWnd;

		if(_hWndNotify == NULL || ::IsWindow(_hWndNotify) == FALSE)
			return	0;		//通知先が死んでいたらこれ以降処理しない

		::GetCursorPos(&pt);
		ScreenToClient(&pt);

		i = 0;
		while(1)
		{
			ret = wndStatusBar.GetRect(i,&rect);
			if(ret == FALSE)
				break;

			if(::PtInRect(&rect,pt))
			{
				//i番目のペインがダブルクリックされた
				if(i == 0)
					::SendMessage(_hWndNotify,WM_DNP_SHOWSCRIPTERROR,NULL,NULL);

				break;
			}

			i++;
		}

		return	0;
	}

	//■追加
	BOOL	SubclassWindow(HWND hWnd,HWND hWndNotify)
	{
		_hWndNotify = hWndNotify;

		return	__super::SubclassWindow(hWnd);
	}

tabbrowser167.gif そしてステータスバークラスから送られてきた独自メッセージのハンドラをビュークラスに追加する。
	BEGIN_MSG_MAP(CTabBrowser100View)
		MESSAGE_HANDLER(WM_DNP_SCRIPTERROR, OnDnpScriptError)
		MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
		MESSAGE_HANDLER(WM_DNP_SHOWSCRIPTERROR, OnShowScriptError)		//■追加
	END_MSG_MAP()

tabbrowser168.gif また、サブクラス化するときにビュークラスのHWNDがステータスバーにわたるようにしておく。
	//■追加
	LRESULT OnShowScriptError(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		ShowScriptError();
		return	0;
	}

	CIELikeStatusbar	_wndStatusbar;


	//メインウインドウから呼ばれる
	//bCapture=trueでこのビューがステータスバーを制御する
	//bCapture=falseでこのビューがステータスバーを解放する
	bool	SetStatusBar(HWND hWnd,bool bCapture)
	{
		if(bCapture)
		{
			if(_wndStatusbar.IsWindow())
				return	false;
			_wndStatusbar.SubclassWindow(hWnd,m_hWnd);			//■変更
			_wndStatusbar.Refresh(true);
		}
		else
		{
			if(_wndStatusbar.IsWindow())
				_wndStatusbar.UnsubclassWindow();
			_wndStatusbar.Refresh(false);
		}

		return	true;
	}

tabbrowser169.gif 最後に「stdafx.h」で新しい独自メッセージWM_DNP_SHOWSCRIPTERRORを追加する。また不要になって使われていないメッセージを削除しておいた。
#define	WM_DNP_CHANGEFOCUS		(WM_APP + 1)
#define	WM_DNP_CREATENEWTAB		(WM_APP + 2)
#define	WM_DNP_CHANGEADDRESS	(WM_APP + 3)
//#define	WM_DNP_CHANGESTATUSTEXT	(WM_APP + 4)		//■削除
//#define	WM_DNP_CHANGEPROGRESS	(WM_APP + 5)		//■削除
#define	WM_DNP_SCRIPTERROR		(WM_APP + 6)
#define	WM_DNP_SHOWSCRIPTERROR	(WM_APP + 7)		//■追加

tabbrowser170.gif
これでビルド/実行すると再びスクリプトエラーの詳細情報を見れるようになった。

だんだんソースコードが増えてきたので、次回は少しソースコードを整理する。

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

第41回 ソースコードを少し整理する (タブブラウザーを作る)

前に一度ソースコードを整理したが、またゴチャゴチャしてきたので再び軽く整理する。




コメントアウト処理を削除

ステータスバー関連処理の再実装をするときにCMainFrame内の処理をたくさんコメントアウトした。それがそのまま残っているのでそれらを削除した。

コメントアウトされている部分で、メニュー項目を無効にする処理でコメントに「//有効/無効設定必要」と置いている部分は削除せずに残しておいた。




クラスを独立したヘッダーファイルへ

今までTabBrowser100View.hの中に多くのクラスを実装した。それらを全部独立した「.h」ファイルに分けた。基本的にカット&ペーストでいいが、#includeの定義を忘れないように。




内部処理をprivate宣言に

CIELikeStatusbarとCTabBrowser100View内の関数や変数はそのほとんどをpublic宣言にしていた。そのためどれが内部使用のみでどれが外部から呼ばれるのかがまったくわからなくなっていた。

そのため内部利用のみのものはprivate、外部から呼ばれるものはpublic宣言に変更しておいた。












次回は今後の機能拡張のためにステータスバーにペインを増やす。


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

2009年04月09日

第42回 ステータスバーにペインを用意する (タブブラウザーを作る)

tabbrowser171.gif
前回まで少し機能拡張を休んでソースコードの整理を行っていた。今回はCIELikeStatusbarクラスを修正してステータスバーのペインを増やす。

ステータスバーでは複数のペインを扱うと、どのペインがどのインデックスなのかごちゃごちゃして分かりにくくなることがある。それを防ぐため今回はenumでペインを定義してしまう。
	//■処理変更
	LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		bHandled = FALSE;

		UpdateLayout();

		return	0;
	}


	//■追加
	//ステータスバーペインのインデックス
	enum	ENUM_PAIN
	{
		PAIN_DEFAULT = 0,			//メッセージ表示やアイコン表示
		PAIN_PROGRESS,				//プログレスバー表示
		PAIN_RESERVED,				//
		PAIN_POPUP,					//ポップアップブロック有効/無効
		PAIN_ADDON,					//アドオンの管理
		PAIN_PRIVACY_REPORT,		//クッキーアイコンやプライバシーレポート表示
		PAIN_SECURITY_REPORT,		//SSLアイコンやセキュリティレポート表示
		PAIN_SECURITY,				//SmartFilterなどの設定
		PAIN_ZONE,					//現在のゾーン表示
		PAIN_BLOCKED,				//ブロックされた項目の表示
		PAIN_ZOOM,					//ズーム設定


		PAIN_LAST					//インデックス数を示す。必ずenumの最後に配置すること
	};

tabbrowser172.gif 指定されたペインの横幅を返す関数を用意する。ペインのスペルがPAINになったりPANEになったり統一感がないが、細かいことは気にせずそのうち修正することにして今回は保留しておく。
	//■追加
	//ペインの「幅」を返す
	int	GetPaneWidth(UINT nIndex)
	{
		if(nIndex >= PAIN_LAST)
			return	0;

		switch(nIndex)
		{
		case	PAIN_DEFAULT:
			{
				int		i;
				int		nWidth;
				CRect	rect;

				//PAIN_DEFAULT以外の部分の幅を計算
				nWidth = 0;
				for(i = 1; i < PAIN_LAST; i++)
					nWidth += GetPaneWidth(i);

				//ステータスバー幅から合計幅を引いた値がPAIN_DEFAULTの幅
				GetClientRect(&rect);
				nWidth = rect.Width() - nWidth;

				if(nWidth >= 0)
					return	nWidth;

				return	0;			//マイナスになるならゼロを返す
			}
			break;

		case	PAIN_PROGRESS:
			if(_nLastProgressMax < _nLastProgress)
				return	0;
			return	100;

		case	PAIN_RESERVED:
		case	PAIN_POPUP:
		case	PAIN_ADDON:
		case	PAIN_PRIVACY_REPORT:
		case	PAIN_SECURITY_REPORT:
		case	PAIN_SECURITY:
			return	20;

		case	PAIN_ZONE:
			return	100;

		case	PAIN_BLOCKED:
			return	30;

		case	PAIN_ZOOM:
			return	60;
		}

		ATLASSERT(0);
		return	0;
	}

tabbrowser173.gif ステータスバーのレイアウトを設定する関数。ステータスバーのレイアウトはSetParts(SB_SETPARTS)で設定できるが、この関数の引数に渡す整数配列は、ペインの「幅」ではなく、右側の「座標」になることに注意。GetPaneWidthの引数をそのまま渡すことはできない。
	//■追加
	//ステータスバーレイアウト設定
	bool	UpdateLayout(void)
	{
		if(IsWindow() == FALSE)
			return	false;				//ステータスバー表示してない

		//ステータスバーのペイン作成
		//本当は現在のペイン数などを見て更新した方がいいのだろうけど、面倒だからそのまま設定
		{
			int		i;
			int		pnParts[PAIN_LAST];
			int		nOffset;
			CStatusBarCtrl	wndStatusBar = m_hWnd;

			nOffset = 0;
			for(i = 0; i < PAIN_LAST; i++)
			{
				pnParts[i] = GetPaneWidth(i) + nOffset;
				nOffset = pnParts[i];						//pnPartsは「幅」ではなく座標を入れる必要があるので、幅から座標に変換するためnOffsetを利用
			}

			//ペイン作成
			wndStatusBar.SetParts(PAIN_LAST,pnParts);
		}

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

		return	true;
	}

tabbrowser174.gif これまではプログレスバーの進行状況設定時にステータスバーのペインを設定していた。これからはUpdateLayoutがその役を担うことになるので、ペイン作成関連処理を削除し、またきちんとUpdateLayoutが呼ばれるようにしておく。
	//bVisible=falseならプログレスバーを消す
	//nProgress < 0、nProgressMax < 0ならプログレス設定はしない
	//nProgressMax < nProgressなら強制的に非表示にする
	bool	RefreshProgressBar(int nProgress=-1,int nProgressMax=-1,bool bVisible=true)
	{
		if((nProgress >= 0 && nProgressMax  >= 0) || (nProgressMax < nProgress))
		{
			//状態を保存しておく
			_nLastProgress		= nProgress;
			_nLastProgressMax	= nProgressMax;
		}

		if(::IsWindow(m_hWnd) == FALSE)
			return	false;				//ステータスバー表示してない

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

		if(_nLastProgressMax < _nLastProgress)
			bVisible = false;


		//■追加
		if(bVisible == false)
		{
			int		nRet;
			int		pnParts[PAIN_LAST];

			nRet = wndStatusBar.GetParts(PAIN_LAST,pnParts);

			if(nRet > PAIN_PROGRESS)
			{
				if(pnParts[PAIN_PROGRESS] != pnParts[PAIN_PROGRESS - 1])
					UpdateLayout();
			}
		}


		//■削除
		//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_hWnd,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(_nLastProgress >= 0)
				_wndProgressBar.SetRange(0,_nLastProgressMax);
			if(_nLastProgress >= 0)
				_wndProgressBar.SetPos(_nLastProgress);
		}

		return	true;
	}

tabbrowser175.gif 外部から呼ばれるステータスバー更新用関数内でもUpdateLayoutが呼ばれるようにしておく。UpdateLayout内ではプログレスバーの設定もしているのでRefresh内のプログレスバー更新処理は削除した。
	//ステータスバー表示更新
	bool	Refresh(bool bCapture)
	{
		if(bCapture == false)
		{
			if(_wndProgressBar.IsWindow())
			{
				if(_wndProgressBar.IsWindowVisible())
					_wndProgressBar.ShowWindow(SW_HIDE);		//不可視に
			}
			return	true;
		}

		if(IsWindow() == FALSE)
			return	false;

		//■追加
		UpdateLayout();		//レイアウト調整

		//ステータスバーのテキスト変更
		{
			SetText(_strText);
		}

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

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

		//■削除
		////プログレス変更
		//{
		//	RefreshProgressBar(_nLastProgress,_nLastProgressMax);
		//}

		return	true;
	}

tabbrowser176.gif
これでビルド/実行するとステータスバーにペインが増えた。

次回はステータスバーがダブルクリックされたときにプライバシーレポートの表示をする。

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

第43回 プライバシーレポートを表示する (タブブラウザーを作る)

tabbrowser177.gif
前回はステータスバーにいくつかのペインを作った。今回はそのペインのダブルクリックで開いているページのプライバシーレポートを表示する。

「プライバシーレポート」はInternet Explrer 6から追加された機能で、そのページに含まれるクッキーなどの情報が表示される。

まず内部で利用するための独自メッセージを定義する。次回のことも考え今回はプライバシーレポートに加え、セキュリティレポート用のメッセージも追加した。
#define	WM_DNP_CHANGEFOCUS		(WM_APP + 1)
#define	WM_DNP_CREATENEWTAB		(WM_APP + 2)
#define	WM_DNP_CHANGEADDRESS	(WM_APP + 3)
#define	WM_DNP_SCRIPTERROR		(WM_APP + 6)
#define	WM_DNP_SHOWSCRIPTERROR	(WM_APP + 7)
#define	WM_DNP_SHOWPRIVACYREPORT	(WM_APP + 8)		//■追加
#define	WM_DNP_SHOWPSECURITYREPORT	(WM_APP + 9)		//■追加

tabbrowser178.gif CIELikeStatusbarのダブルクリック処理部分を変更する。switchによる分岐にし、先ほど用意した独自メッセージをビューウインドウに飛ばすように設定する。
	//ステータスバーのダブルクリック処理
	LRESULT OnLButtonDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		int		i;
		RECT	rect;
		BOOL	ret;
		POINT	pt;

		CStatusBarCtrl	wndStatusBar = m_hWnd;

		if(_hWndNotify == NULL || ::IsWindow(_hWndNotify) == FALSE)
			return	0;		//通知先が死んでいたらこれ以降処理しない

		::GetCursorPos(&pt);
		ScreenToClient(&pt);

		i = 0;
		while(1)
		{
			ret = wndStatusBar.GetRect(i,&rect);
			if(ret == FALSE)
				break;

			if(::PtInRect(&rect,pt))
			{
				//i番目のペインがダブルクリックされた

				//■処理内容変更。switch化した
				switch(i)
				{
				case	PAIN_DEFAULT:
					::SendMessage(_hWndNotify,WM_DNP_SHOWSCRIPTERROR,NULL,NULL);
					break;

				case	PAIN_PRIVACY_REPORT:
					::SendMessage(_hWndNotify,WM_DNP_SHOWPRIVACYREPORT,NULL,NULL);
					break;

				case	PAIN_SECURITY_REPORT:
					::SendMessage(_hWndNotify,WM_DNP_SHOWPSECURITYREPORT,NULL,NULL);
					break;

				case	PAIN_PROGRESS:
				case	PAIN_RESERVED:
				case	PAIN_POPUP:
				case	PAIN_ADDON:
				case	PAIN_SECURITY:
				case	PAIN_ZONE:
				case	PAIN_BLOCKED:
				case	PAIN_ZOOM:
					break;
				}

				break;
			}

			i++;
		}

		return	0;
	}

tabbrowser179.gif そしてビューウインドウ内でメッセージを受け取り、レポートを表示する関数が実行されるようにする。
	BEGIN_MSG_MAP(CTabBrowser100View)
		MESSAGE_HANDLER(WM_DNP_SCRIPTERROR, OnDnpScriptError)
		MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
		MESSAGE_HANDLER(WM_DNP_SHOWSCRIPTERROR, OnShowScriptError)
		MESSAGE_HANDLER(WM_DNP_SHOWPRIVACYREPORT, OnShowPrivacyReport)		//■追加
		MESSAGE_HANDLER(WM_DNP_SHOWPSECURITYREPORT, OnShowSecurityReport)	//■追加
	END_MSG_MAP()


private:


	//■追加
	LRESULT OnShowPrivacyReport(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		ShowPrivacyReport(m_hWnd);
		return	0;
	}

	//■追加
	LRESULT OnShowSecurityReport(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		ShowSecurityReport(m_hWnd);
		return	0;
	}

tabbrowser180.gif
CIEUtilityの中にレポートを表示する関数を追加する。

プライバシーレポートの表示にはshdocvw.dllからエクスポートされるDoPrivavcyDlgという関数を使う。引数にIEnumPrivacyRecordsとURLが必要なのでそれをIWebBrowser2から取得し渡している。
	//■追加
	//IE6以上で実装されているプライバシーレポートの表示
	bool	ShowPrivacyReport(HWND hWnd)
	{
		HRESULT		hr;
		CComBSTR	bstr;
		HINSTANCE	hDLL;
		CComPtr<IServiceProvider>		pIServiceProvider;
		CComPtr<IEnumPrivacyRecords>	pIEnumPrivacyRecords;
		HRESULT (WINAPI* pfnDoPrivacyDlg)(HWND,LPOLESTR,IEnumPrivacyRecords*,BOOL) = NULL;

		if(_pIWebBrowser2 == NULL)
			return	false;

		//IEnumPrivacyRecords取得
		_pIWebBrowser2->QueryInterface(&pIServiceProvider);
		if(pIServiceProvider)
			pIServiceProvider->QueryService(__uuidof(IEnumPrivacyRecords),IID_IEnumPrivacyRecords,(void**)&pIEnumPrivacyRecords);
		if(pIEnumPrivacyRecords == NULL)
			return	false;

		//URL取得
		hr = _pIWebBrowser2->get_LocationURL(&bstr);
		if(FAILED(hr))
			return	false;

		hDLL = ::LoadLibrary(_T("shdocvw.dll"));
		if(hDLL == NULL)
			return	false;

		//DoPrivacyDlg取得
		(FARPROC&)pfnDoPrivacyDlg = ::GetProcAddress(hDLL,"DoPrivacyDlg");
		if(pfnDoPrivacyDlg == NULL)
		{
			::FreeLibrary(hDLL);
			return	false;
		}

		hr = pfnDoPrivacyDlg(hWnd,bstr,pIEnumPrivacyRecords,FALSE);

		::FreeLibrary(hDLL);

		return	SUCCEEDED(hr) ? true : false;
	}

	//■追加
	bool	ShowSecurityReport(HWND hWnd)
	{
		return	true;
	}

tabbrowser181.gif
これでステータスバーのプライバシーレポート用のペインをダブルクリックすることでプライバシーレポートが表示されるようになった。

次回はセキュリティレポートが表示されるようにする。

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

第44回 セキュリティレポートを表示する (タブブラウザーを作る)

tabbrowser182.gif
前回はステータスバーのダブルクリックによりプライバシーレポートが表示されるようにした。

今回はセキュリティレポートの表示を行う。セキュリティレポート用にダブルクリック処理などは前回すでに用意したので実装が必要なのは実際に表示する部分だけとなる。

セキュリティレポートはwininet.dllからエクスポートされているInternetShowSecurityInfoByURLWもしくはInternetShowSecurityInfoByURLAにURLを指定して呼び出すことで表示される。
	//■処理変更
	bool	ShowSecurityReport(HWND hWnd)
	{
		HRESULT		hr;
		CComBSTR	bstrURL;

		if(_pIWebBrowser2 == NULL)
			return	false;

		//URL取得
		hr = _pIWebBrowser2->get_LocationURL(&bstrURL);
		if(FAILED(hr))
			return	false;

		return	ShowSecurityReport(hWnd,(CAtlString)bstrURL);
	}


	//■追加
	bool	ShowSecurityReport(HWND hWnd,LPCTSTR pszURL)
	{
		bool		ret;
		HMODULE		hDLL;

		BOOL (WINAPI* pfnInternetShowSecurityInfoByURLW)(const WCHAR*,HWND);
		BOOL (WINAPI* pfnInternetShowSecurityInfoByURLA)(const char*,HWND);

		if(pszURL == NULL)
			return	false;

		hDLL = ::LoadLibrary(_T("wininet.dll"));
		if(hDLL == NULL)
			return	false;

		ret = false;
		(FARPROC&)pfnInternetShowSecurityInfoByURLW = ::GetProcAddress(hDLL,"InternetShowSecurityInfoByURLW");
		if(pfnInternetShowSecurityInfoByURLW)
		{
	#ifdef	_UNICODE
			pfnInternetShowSecurityInfoByURLW(pszURL,hWnd);
	#else
			CAtlStringW	ustrURL;
			ustrURL = pszURL;
			pfnInternetShowSecurityInfoByURLW(ustrURL.GetBuffer(0),hWnd);
	#endif
			ret = true;
		}

		if(ret == false)
		{
			(FARPROC&)pfnInternetShowSecurityInfoByURLA = ::GetProcAddress(hDLL,"InternetShowSecurityInfoByURLA");
			if(pfnInternetShowSecurityInfoByURLA)
			{
	#ifdef	_UNICODE
				CAtlStringA	strBuff;
				strBuff = pszURL;
				pfnInternetShowSecurityInfoByURLA(strBuff.GetBuffer(0),hWnd);
	#else
				pfnInternetShowSecurityInfoByURLA(pszURL,hWnd);
	#endif
				ret = true;
			}
		}

		::FreeLibrary(hDLL);

		return	ret;
	}

tabbrowser183.gif
これでステータスバーのセキュリティレポート用のペインをダブルクリックすることでセキュリティレポートが表示されるようになった。

次回はプライバシー状態やセキュリティ状態に応じてステータスバーにアイコンが表示されるようにする。

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

第45回 セキュリティやプライバシーアイコンを表示する (タブブラウザーを作る)

tabbrowser184.gif
ここ数回の実装でステータスバーをダブルクリックすることでプライバシーレポートとセキュリティレポートを表示できるようになった。

今回はステータスバーにこれらの状態を示すアイコンを表示する。まずは表示するためのアイコンを作る。リソースウインドウの「Icon」で右クリックして現われるメニューから「Iconを挿入」を選択する。


実際にInternet Explorerで利用しているアイコンをプログラム内からロードして使うようにしてもいい。しかしInternet Explorer 6と7/8では格納されている場所も形式も変更されたためちょっと実装が面倒なので今回は自分で作ることにした。

tabbrowser185.gif
今回はステータスバーへ表示するアイコンを作るため、32x32サイズは不要となる。そのため32x32の上で右クリックをして現われるメニューから「イメージタイプの削除」を選択して消してしまう。

tabbrowser186.gif
そしてアイコンを作成する。まずはプライバシーインパクト状態のアイコンを作った。IDは「IDI_PRIVACY」とした。

tabbrowser187.gif
同様の手順で「IDI_SECURITY」というセキュア状態用のアイコンも作っておく。

tabbrowser188.gif そしてCIconManager内で作成した2つのアイコンがロードされるようにする。
	enum	ICON_INDEX
	{
		ICON_WARNING_SM = 0,			//警告アイコン。スクリプトエラー時に利用
		ICON_SECURITY_SM,				//■追加 鍵のアイコン。セキュリティロック時利用
		ICON_PRIVACY_SM,				//■追加 プライバシーのアイコン。クッキー存在時などに利用
	};

	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);

		//■追加
		{
			//鍵のアイコン
			//LoadIconのは自動でDestroyされる
			hIcon = ::LoadIcon(::_Module.m_hInst,MAKEINTRESOURCE(IDI_SECURITY));
			hIcon = (HICON)::CopyImage(hIcon,IMAGE_ICON,::GetSystemMetrics(SM_CXSMICON),::GetSystemMetrics(SM_CYSMICON),LR_COPYFROMRESOURCE | LR_COPYDELETEORG | LR_COPYRETURNORG);
			nIndex = _ahIcon.Add(hIcon);
			ATLASSERT(nIndex == ICON_SECURITY_SM);
		}

		//■追加
		{
			//プライバシーのアイコン
			//LoadIconのは自動でDestroyされる
			hIcon = ::LoadIcon(::_Module.m_hInst,MAKEINTRESOURCE(IDI_PRIVACY));
			hIcon = (HICON)::CopyImage(hIcon,IMAGE_ICON,::GetSystemMetrics(SM_CXSMICON),::GetSystemMetrics(SM_CYSMICON),LR_COPYFROMRESOURCE | LR_COPYDELETEORG | LR_COPYRETURNORG);
			nIndex = _ahIcon.Add(hIcon);
			ATLASSERT(nIndex == ICON_PRIVACY_SM);
		}

		return	true;
	}

tabbrowser189.gif 次にCIELikeStatusbarに現在のページの状態を保存するための変数を追加する。この付近の流れはスクリプトエラーが発生したときのアイコン表示とまったく同じ処理になる。
	bool	_bPageError;	//現在のページでスクリプトエラーなどがあればtrue、通常はfalse
	bool	_bPrivate;		//■追加 現在のページがプライバシーインパクト状態ならtrue、通常はfalse
	bool	_bSecure;		//■追加 現在のページがセキュアならtrue、通常はfalse

	HWND	_hWndNotify;	//ダブルクリック通知先。通常ビューウインドウのHWND
public:

	CIELikeStatusbar()
	{
		_hWndNotify			= NULL;
		_nLastProgress		= -1;
		_nLastProgressMax	= -1;
		_bPageError = false;
		_bPrivate = false;		//■追加
		_bSecure = false;		//■追加
	}

tabbrowser190.gif CIELikeStatusbarに実際にページ状態に応じてアイコンを表示する処理をおく。
	//ステータスバー表示更新
	bool	Refresh(bool bCapture)
	{
		if(bCapture == false)
		{
			if(_wndProgressBar.IsWindow())
			{
				if(_wndProgressBar.IsWindowVisible())
					_wndProgressBar.ShowWindow(SW_HIDE);		//不可視に
			}
			return	true;
		}

		if(IsWindow() == FALSE)
			return	false;

		UpdateLayout();		//レイアウト調整

		//ステータスバーのテキスト変更
		{
			SetText(_strText);
		}

		//■処理変更
		//ステータスバーのアイコン変更
		{
			SetPageError(_bPageError);
			SetPrivacy(_bPrivate);
			SetSecure(_bSecure);
		}

		return	true;
	}

	//■追加
	//アイコンをステータスバーに設定/消去
	//nPainは表示するペイン
	//nIconIndexはCIconManager上でのインデックス
	//bSet=trueならアイコン設定。bSet=falseならnIconIndexを無視してアイコンを消去
	bool	SetIcon(int nPain,UINT nIconIndex,bool bSet)
	{
		if(IsWindow() == FALSE)
			return	false;

		BOOL	ret;
		CStatusBarCtrl	wndStatusBar = m_hWnd;

		if(bSet)
			ret = wndStatusBar.SetIcon(nPain,_cIconList.GetIcon(nIconIndex));
		else
			ret = wndStatusBar.SetIcon(nPain,NULL);

		return	ret ? true : false;
	}

	bool	SetPageError(bool bError)
	{
		_bPageError = bError;			//エラーが発生したことを保持

		//■処理変更
		return	SetIcon(PAIN_DEFAULT,CIconManager::ICON_WARNING_SM,_bPageError);
	}

	//■追加
	bool	SetPrivacy(bool bPrivate)
	{
		_bPrivate = bPrivate;			//状態保持

		return	SetIcon(PAIN_PRIVACY_REPORT,CIconManager::ICON_PRIVACY_SM,_bPrivate);
	}

	//■追加
	bool	SetSecure(bool bSecure)
	{
		_bSecure = bSecure;			//状態保持

		return	SetIcon(PAIN_SECURITY_REPORT,CIconManager::ICON_SECURITY_SM,_bSecure);
	}

tabbrowser191.gif
最後にビューウインドウからステータスバー側にページの状態が伝わるようにする。

プライバシー状態やセキュリティ状態はIEコントロールからそれぞれDISPID_PRIVACYIMPACTEDSTATECHANGE、DISPID_SETSECURELOCKICONで届く。しかしどちらもMSDNライブラリの説明は間違えているようなので注意が必要だ。
	//■処理内容実装
	//MSDNにはVT_BOOLとあるが、BOOLとの間違え
	void __stdcall OnPrivacyImpactedStateChange(BOOL bPrivacyImpacted)
	{
		if(bPrivacyImpacted == FALSE)
			_wndStatusbar.SetPrivacy(false);
		else
			_wndStatusbar.SetPrivacy(true);
	}

	//■処理内容実装
	//MSDNにはVARIANTとあるが、longとの間違え
	void __stdcall OnSetSecureLockIcon(long lSecureLockIcon)
	{
		//本当ならlSecureLockIconは種類がいっぱいあるが、とりあえずセキュアかそうでないかのみで処理

		if(lSecureLockIcon == secureLockIconUnsecure)
			_wndStatusbar.SetSecure(false);
		else
			_wndStatusbar.SetSecure(true);
	}

tabbrowser192.gif
これでビルド/実行するとステータスバーにSSL通信時は鍵、クッキーなどを利用したべージでは変な目のアイコンが表示されるようになった。

次回は「信頼済みサイト」や「インターネット」などのゾーン情報を取得してステータスバーに表示する。

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

第46回 現在のゾーン情報を表示する (タブブラウザーを作る)

tabbrowser193.gif
今回はステータスバーにアクセスしているURLに応じて「インターネット」や「コンピュータ」「信頼済みサイト」などのインターネットゾーン表示をする。

今回のゾーン情報の取得はInternet Explorer 6 SP2以降のCOMインターフェースを利用する。そのためまずは「stdafx.h」でIE6 SP2以降を示す0x603を_WIN32_IEの値として定義する。
#define WINVER			0x0500
#define _WIN32_WINNT	0x0501
#define _WIN32_IE		0x0603		//■変更 IE6SP2以降
#define _RICHEDIT_VER	0x0200

tabbrowser194.gif そしてビュークラス内に実際のゾーン取得処理を実装する。IInternetSecurityManagerをCoCreateし、URLを渡すことでゾーン値を取得、それをステータスバーへセットする。
	//■追加
	//ゾーンの取得
	bool	GetZone(LPCTSTR pszURL,DWORD& dwZone)
	{
		HRESULT		hr;
		CAtlStringW	ustrURL(pszURL);
		CComPtr<IInternetSecurityManager>	pIInternetSecurityManager;

		dwZone = URLZONE_INVALID;
		pIInternetSecurityManager.CoCreateInstance(CLSID_InternetSecurityManager,NULL,CLSCTX_INPROC_SERVER);
		if(pIInternetSecurityManager == NULL)
			return	false;

		hr = pIInternetSecurityManager->MapUrlToZone(ustrURL,&dwZone,0);

		return	SUCCEEDED(hr) ? true : false;
	}


	//メインウインドウへアドレス変更を通知する
	bool	NotifyChangeURL(LPCTSTR pszURL)
	{
		//■追加
		//インターネットゾーンの取得
		{
			DWORD	dwZone;

			GetZone(pszURL,dwZone);
			_wndStatusbar.SetZone(dwZone);		//ステータスバーへ設定
		}

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

		GetTopLevelWindow().SendMessage(WM_DNP_CHANGEADDRESS,(WPARAM)pszURL);

		return	true;
	}

tabbrowser195.gif ステータスバー側で受け取った値を保持しておくための変数を用意しておく。
class	CIELikeStatusbar	: public CWindowImpl<CIELikeStatusbar>
{
	CIconManager	_cIconList;

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


	CAtlString	_strText;

	long	_nLastProgress;			//最後に受け取ったプログレス情報
	long	_nLastProgressMax;		//最後に受け取ったプログレス最大値

	bool	_bPageError;	//現在のページでスクリプトエラーなどがあればtrue、通常はfalse
	bool	_bPrivate;		//現在のページがプライバシーインパクト状態ならtrue、通常はfalse
	bool	_bSecure;		//現在のページがセキュアならtrue、通常はfalse
	DWORD	_dwZone;		//■追加 現在のページのゾーン

	HWND	_hWndNotify;	//ダブルクリック通知先。通常ビューウインドウのHWND
public:

	CIELikeStatusbar()
	{
		_hWndNotify			= NULL;
		_nLastProgress		= -1;
		_nLastProgressMax	= -1;
		_bPageError = false;
		_bPrivate = false;
		_bSecure = false;
		_dwZone = URLZONE_INVALID;		//■追加
	}

tabbrowser196.gif そしてビューウインドウ側から受け取ったゾーン値を保存しておくと同時に、DWORD値から表示用の文字列へ変換してステータスバーへ表示する。
	//ステータスバー表示更新
	bool	Refresh(bool bCapture)
	{
		if(bCapture == false)
		{
			if(_wndProgressBar.IsWindow())
			{
				if(_wndProgressBar.IsWindowVisible())
					_wndProgressBar.ShowWindow(SW_HIDE);		//不可視に
			}
			return	true;
		}

		if(IsWindow() == FALSE)
			return	false;

		UpdateLayout();		//レイアウト調整

		//ステータスバーのテキスト変更
		{
			SetText(_strText);
		}

		//ステータスバーのアイコン変更
		{
			SetPageError(_bPageError);
			SetPrivacy(_bPrivate);
			SetSecure(_bSecure);
		}

		//■追加
		//ゾーン設定
		{
			SetZone(_dwZone);
		}

		return	true;
	}


	//■追加
	bool	SetZone(DWORD dwZone)
	{
		_dwZone = dwZone;

		if(IsWindow() == FALSE)
			return	true;			//trueを返す

		//ゾーンのテキストをステータスバーに表示
		{
			ZONEATTRIBUTES	sZoneAttributes;
			CComPtr<IInternetZoneManager>	pIInternetZoneManager;

			::ZeroMemory(&sZoneAttributes,sizeof(ZONEATTRIBUTES));
			sZoneAttributes.cbSize = sizeof(ZONEATTRIBUTES);

			pIInternetZoneManager.CoCreateInstance(CLSID_InternetZoneManager,NULL,CLSCTX_INPROC_SERVER);
			if(pIInternetZoneManager)
				pIInternetZoneManager->GetZoneAttributes(dwZone,&sZoneAttributes);

			CAtlString		strZone = sZoneAttributes.szDisplayName;
			CStatusBarCtrl	wndStatusBar = m_hWnd;

			wndStatusBar.SetText(PAIN_ZONE,strZone);
		}

		return	true;
	}

tabbrowser197.gif
これでビルド/実行するとステータスバーに開いているページのゾーン名が表示されるようになった。

次回はゾーン名に加えてゾーン用のアイコンを表示する。

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

第47回 現在のゾーンのアイコンを表示する (タブブラウザーを作る)

tabbrowser198.gif
前回はステータスバーへ現在のインターネットゾーン名を表示した。今回はゾーン用のアイコンを表示する。

ありがたいことにゾーン名を取得するときに利用したIInternetZoneManager::GetZoneAttributesはゾーン名に加えて、表示用のアイコンファイル名も教えてくれる。今回はこの情報を元にアイコンを表示する。

まずはファイルからアイコンを読み込むようにCIconManagerに機能を実装する。ステータスバーにアイコンを表示するたびにファイルからアイコンをロードしていたのでは効率が悪いので、_acItemという配列を用意してそこに一度読み込んだアイコンファイルの情報を格納しておくことにした。
//アイコンを管理
//アイコンをAddする関数などは未実装。今後追加
class	CIconManager
{
protected:
	CAtlArray<HICON>	_ahIcon;		//アイコンリスト

	//■追加
	//ファイルからアイコンを読み込むときのキャッシュ用クラス
	class	CItem
	{
	public:
		CItem()
		{
			nIconIndex = -1;
		}

		CItem(LPCTSTR pszFile,UINT nIndex)
		{
			strIconFile = pszFile;
			nIconIndex = nIndex;
		}

		CAtlString	strIconFile;
		UINT		nIconIndex;
	};

	CAtlArray<CItem>	_acItem;	//■追加 ファイルから読み込んだアイコンキャッシュ情報

	//■追加
	//キャッシュ情報からアイコンを取得する
	bool	GetIcon(LPCTSTR pszFile,HICON& hIcon)
	{
		size_t	i;
		size_t	nSize;

		nSize = _acItem.GetCount();
		for(i = 0; i < nSize; i++)
		{
			if(_acItem[i].strIconFile != pszFile)
				continue;

			hIcon = GetIcon(_acItem[i].nIconIndex);
			return	true;
		}

		hIcon = NULL;
		return	false;
	}

	//■追加
	//キャッシュおよび_ahIconへアイコンを追加する
	//ファイルから読み込んだ場合は必ずこの関数で追加すること
	bool	AddIcon(LPCTSTR pszFile,HICON hIcon)
	{
		UINT	nIndex;

		nIndex = _ahIcon.Add(hIcon);
		_acItem.Add(CItem(pszFile,nIndex));

		return	true;
	}

tabbrowser199.gif そしてファイルから実際にアイコンを読み込む処理を実装する。IInternetZoneManager::GetZoneAttributesが教えてくれるアイコンファイルは「xxx.dll#12345」のようにファイル名+リソース名という形で取得できる。そのままでは処理できないので一度「#」で分割して読み込む。
	//■追加
	//ファイルやファイルのリソースからアイコンを取得
	HICON	GetIcon(LPCTSTR pszIconFile)
	{
		bool		ret;
		int			nFind;
		HICON		hIcon;

		ret = GetIcon(pszIconFile,hIcon);
		if(ret)
			return	hIcon;

		//LoadIconのは自動でDestroyされる
		hIcon = (HICON)::LoadImage(NULL,pszIconFile,IMAGE_ICON,0,0,LR_LOADFROMFILE | LR_DEFAULTCOLOR | LR_DEFAULTSIZE);
		if(hIcon)
			hIcon = (HICON)::CopyImage(hIcon,IMAGE_ICON,::GetSystemMetrics(SM_CXSMICON),::GetSystemMetrics(SM_CYSMICON),LR_COPYFROMRESOURCE | LR_COPYDELETEORG | LR_COPYRETURNORG);
		if(hIcon)
		{
			AddIcon(pszIconFile,hIcon);
			return	hIcon;
		}

		//アイコンがロードできなかった場合は...
		//「c:¥xxx.dll#0010」のようなリソース指定としてトライ

		HMODULE		hDLL;
		CAtlString	strFile(pszIconFile);

		nFind = strFile.ReverseFind(_T('#'));
		if(nFind < 0)
			return	NULL;		//リソース名ではなかった

		hDLL = ::LoadLibrary(strFile.Left(nFind));
		if(hDLL == NULL)
			return	NULL;

		//LoadIconのは自動でDestroyされる
		hIcon = (HICON)::LoadImage(hDLL,(LPCTSTR)::_tcstoi64(strFile.Right(strFile.GetLength() - nFind - 1),NULL,10),IMAGE_ICON,0,0,LR_DEFAULTCOLOR | LR_DEFAULTSIZE);
		if(hIcon)
			hIcon = (HICON)::CopyImage(hIcon,IMAGE_ICON,::GetSystemMetrics(SM_CXSMICON),::GetSystemMetrics(SM_CYSMICON),LR_COPYFROMRESOURCE | LR_COPYDELETEORG | LR_COPYRETURNORG);

		::FreeLibrary(hDLL);

		AddIcon(pszIconFile,hIcon);		//NULLでも登録してしまう

		return	hIcon;
	}

tabbrowser200.gif そして最後にステータスバークラスの中でゾーン用のアイコンを表示する処理を追加する。
	bool	SetZone(DWORD dwZone)
	{
		_dwZone = dwZone;

		if(IsWindow() == FALSE)
			return	true;			//trueを返す

		//ゾーンのテキストをステータスバーに表示
		{
			ZONEATTRIBUTES	sZoneAttributes;
			CComPtr<IInternetZoneManager>	pIInternetZoneManager;

			::ZeroMemory(&sZoneAttributes,sizeof(ZONEATTRIBUTES));
			sZoneAttributes.cbSize = sizeof(ZONEATTRIBUTES);

			pIInternetZoneManager.CoCreateInstance(CLSID_InternetZoneManager,NULL,CLSCTX_INPROC_SERVER);
			if(pIInternetZoneManager)
				pIInternetZoneManager->GetZoneAttributes(dwZone,&sZoneAttributes);

			CAtlString		strZone = sZoneAttributes.szDisplayName;
			CStatusBarCtrl	wndStatusBar = m_hWnd;

			//■追加
			//ゾーンアイコン表示
			{
				HICON	hIcon = NULL;

				if(sZoneAttributes.szIconPath && *sZoneAttributes.szIconPath)
					hIcon = _cIconList.GetIcon(sZoneAttributes.szIconPath);
				wndStatusBar.SetIcon(PAIN_ZONE,hIcon);
			}

			wndStatusBar.SetText(PAIN_ZONE,strZone);
		}

		return	true;
	}

tabbrowser201.gif
これでビルド/実行するとステータスバーにゾーンのアイコンが表示されるようになった。ステータスバーの幅が狭すぎてゾーン名がはみ出てしまったのはご愛敬。そのうちに修正することにして今は保留しておく。

次回はステータスバーのゾーン情報表示部分をダブルクリックしたときにゾーン設定画面が開くようにする。

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

第48回 ゾーン設定ウインドウを開く (タブブラウザーを作る)

tabbrowser202.gif
前回までにステータスバーに現在開いているページのゾーン名やゾーンのアイコンを表示した。今回はその部分をダブルクリックしたときにゾーン設定画面が開くようにする。

処理の流れはステータスバーのダブルクリックからプライバシーレポートを表示したときと同じようになる。まず「stdafx.h」内にステータスバーからビューウインドウへダブルクリックされたときに送るための独自メッセージを追加する。
#define	WM_DNP_SHOWZONECONFIGURE	(WM_APP + 10)		//■追加

tabbrowser203.gif そしてステータスバーがダブルクリックされたときにビューウインドウへメッセージを送信する。
	//ステータスバーのダブルクリック処理
	LRESULT OnLButtonDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		int		i;
		RECT	rect;
		BOOL	ret;
		POINT	pt;

		CStatusBarCtrl	wndStatusBar = m_hWnd;

		if(_hWndNotify == NULL || ::IsWindow(_hWndNotify) == FALSE)
			return	0;		//通知先が死んでいたらこれ以降処理しない

		::GetCursorPos(&pt);
		ScreenToClient(&pt);

		i = 0;
		while(1)
		{
			ret = wndStatusBar.GetRect(i,&rect);
			if(ret == FALSE)
				break;

			if(::PtInRect(&rect,pt))
			{
				//i番目のペインがダブルクリックされた

				switch(i)
				{
				case	PAIN_DEFAULT:
					::SendMessage(_hWndNotify,WM_DNP_SHOWSCRIPTERROR,NULL,NULL);
					break;

				case	PAIN_PRIVACY_REPORT:
					::SendMessage(_hWndNotify,WM_DNP_SHOWPRIVACYREPORT,NULL,NULL);
					break;

				case	PAIN_SECURITY_REPORT:
					::SendMessage(_hWndNotify,WM_DNP_SHOWPSECURITYREPORT,NULL,NULL);
					break;

					//■変更
				case	PAIN_ZONE:
					::SendMessage(_hWndNotify,WM_DNP_SHOWZONECONFIGURE,NULL,NULL);
					break;

				case	PAIN_PROGRESS:
				case	PAIN_RESERVED:
				case	PAIN_POPUP:
				case	PAIN_ADDON:
				case	PAIN_SECURITY:
				case	PAIN_BLOCKED:
				case	PAIN_ZOOM:
					break;
				}

				break;
			}

			i++;
		}

		return	0;
	}

tabbrowser204.gif さらにビューウインドウ側でステータスバーから送られてきたメッセージ用のハンドラを追加する。
	BEGIN_MSG_MAP(CTabBrowser100View)
		MESSAGE_HANDLER(WM_DNP_SCRIPTERROR, OnDnpScriptError)
		MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
		MESSAGE_HANDLER(WM_DNP_SHOWSCRIPTERROR, OnShowScriptError)
		MESSAGE_HANDLER(WM_DNP_SHOWPRIVACYREPORT, OnShowPrivacyReport)
		MESSAGE_HANDLER(WM_DNP_SHOWPSECURITYREPORT, OnShowSecurityReport)
		MESSAGE_HANDLER(WM_DNP_SHOWZONECONFIGURE, OnShowZoneConfigure)		//■追加
	END_MSG_MAP()


private:


	LRESULT OnShowZoneConfigure(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		ShowZoneConfigure(m_hWnd);
		return	0;
	}

tabbrowser205.gif 最後に実際にゾーン設定画面を開く処理を実装する。ゾーン設定画面はshlwapi.dllからnoname@383でエクスポートされているZoneConfigureWという関数により開く。
	//■追加
	//ゾーン設定の表示
	bool	ShowZoneConfigure(HWND hWnd,LPCTSTR pszURL)
	{
		HMODULE	hDLL;
		void (WINAPI* pfnZoneConfigureW)(HWND,LPCWSTR) = NULL;

		hDLL = ::LoadLibrary(_T("shlwapi.dll"));
		if(hDLL == NULL)
			return	false;

		(FARPROC&)pfnZoneConfigureW = ::GetProcAddress(hDLL,(LPCSTR)383);
		if(pfnZoneConfigureW)
			(*pfnZoneConfigureW)(NULL,(CAtlStringW)pszURL);

		::FreeLibrary(hDLL);

		return	pfnZoneConfigureW ? true : false;
	}

	//■追加
	//ゾーン設定の表示
	bool	ShowZoneConfigure(HWND hWnd)
	{
		HRESULT		hr;
		CComBSTR	bstrURL;

		if(_pIWebBrowser2 == NULL)
			return	false;

		//URL取得
		hr = _pIWebBrowser2->get_LocationURL(&bstrURL);
		if(FAILED(hr))
			return	false;

		return	ShowZoneConfigure(hWnd,(CAtlString)bstrURL);
	}

tabbrowser206.gif
これでビルド/実行してステータスバーのゾーン情報の部分をダブルクリックするとゾーン設定画面が開いた。

次回はリンクをクリックしたときに鳴るクリック音を消す設定をする。

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

前の10件 1  2  3  4  5  6  7





usefullcode@gmail.com

About 2009年04月

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

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

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

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