第54回 「Googleツールバー」を2つ表示する (タブブラウザーを作る)

tabbrowser237.gif
前回はビューウインドウを中心にIEツールバーを複数利用する準備をした。今回はCMainFrame側を中心に修正を行う。

まずIEツールバーの親ウインドウとなるCDummyWndの中身を変更する。「Googleツールバー」以外のIEツールバーにも対応できるように_clsidIDeskBandを用意し、それを取得するための独自メッセージ処理を用意した。

またこれまでリバーのインデックス渡しにバグがあったので、きちんとIDからインデックスを取得して渡すように修正した。
	//■処理内容変更
	class	CDummyWnd	: public CWindowImpl<CDummyWnd>
	{
		IID		_clsidIDeskBand;	//IEツールバーのGUID
	public:
		UINT	_nBandID;			//リバーのID

		CDummyWnd(IID clsidIDeskBand)
		{
			_nBandID = -1;
			_clsidIDeskBand = clsidIDeskBand;
		}

		BEGIN_MSG_MAP(CDummyWnd)
			MESSAGE_HANDLER(WM_DNP_GETRBINDEX, OnDnpRbIndex)
			MESSAGE_HANDLER(WM_DNP_GETCLSID, OnDnpGetClsid)
			MESSAGE_HANDLER(WM_SIZE, OnSize)
		END_MSG_MAP()


		//リバー操作用のINDEX取得
		LRESULT OnDnpRbIndex(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
		{
			UINT*	pnIndex = (UINT*)wParam;

			if(pnIndex)
				*pnIndex = GetRebarIndex();

			return	0;
		}

		LRESULT OnDnpGetClsid(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
		{
			IID*	piid = (IID*)wParam;

			if(piid)
				*piid = _clsidIDeskBand;

			return	0;
		}


		UINT	GetRebarIndex(void)
		{
			UINT	nIndex = -1;

			if(_nBandID == -1 || IsWindow() == FALSE)
				return	nIndex;

			nIndex = ::SendMessage(::GetParent(m_hWnd),RB_IDTOINDEX,(WPARAM)_nBandID,NULL);

			return	nIndex;
		}


		LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
		{
			bHandled = FALSE;
			if(_nBandID == -1)
				return	0;

			//このウインドウの直下にあるchildウインドウ=IEツールバーをrebarに全体表示する

			CRect	rect;
			HWND	hWnd;

			//rebarサイズ取得
			rect.left	= 0;
			rect.top	= 0;
			rect.right	= LOWORD(lParam);
			rect.bottom	= HIWORD(lParam);

			//子ウインドウを検索してサイズ調節
			hWnd = NULL;
			while(1)
			{
				hWnd = ::FindWindowEx(m_hWnd,hWnd,NULL,NULL);
				if(hWnd == NULL)
					break;

				::MoveWindow(hWnd,rect.left,rect.top,rect.Width(),rect.Height(),FALSE);
			}

			return	0;
		}


		bool	ShowRebar(bool bVisible)
		{
			if(_nBandID == -1 || IsWindow() == FALSE)
				return	false;

			::SendMessage(::GetParent(m_hWnd),RB_SHOWBAND,(WPARAM)GetRebarIndex(),(LPARAM)(bVisible ? TRUE : FALSE));

			return	true;
		}
	};

tabbrowser238.gif そしてCDummyWndをCAtlArrayにより配列化、簡単にCDummyWndを作れるようにAddIEToolbar関数を用意した。
	CAtlArray<CDummyWnd*>	_apwndDummy;		//■変更


	//■追加 処理はOnCreateから移動&変更
	bool	AddIEToolbar(IID clsidIDeskBand)
	{
		CDummyWnd*	pwndDummy;

		pwndDummy = new CDummyWnd(clsidIDeskBand);

		//ダミーウインドウを生成し、リバーに割り当てる。これはIEツールバーに利用
		pwndDummy->Create(m_hWnd,CRect(0,0,500,24),0,WS_CHILD);
		AddSimpleReBarBand(*pwndDummy,0,TRUE);						//1行表示

		//IEツールバー用のrebarのインデックス取得。_wndDummyへ割り当てると同時にrebarを非表示に
		{
			UINT	nCount;

			nCount = (UINT)::SendMessage(m_hWndToolBar,RB_GETBANDCOUNT,NULL,NULL);
			pwndDummy->_nBandID = nCount + ATL_IDW_BAND_FIRST - 1;

			if(m_view.IsWindow() && m_view.GetPageCount())
			{
				//IEツールバーの生成
				//タブの数だけ一気に生成しているから効率が悪すぎる。
				//アクティブになったときに生成すべき
				{
					size_t	i;
					size_t	nSize;
					CTabBrowser100View*	pView;

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

						if(i == m_view.GetActivePage())
							pView->AddIEToolbar(*pwndDummy,true);		// IEツールバー生成
						else
							pView->AddIEToolbar(*pwndDummy,false);		// IEツールバー生成
					}
				}
				pwndDummy->ShowRebar(true);			//表示する
			}
			else
				pwndDummy->ShowRebar(false);		//非表示にする
		}

		_apwndDummy.Add(pwndDummy);

		return	true;
	}

tabbrowser234.gif CDummyWndの配列はnewによる確保にしたので、デストラクタでdeleteしておく。
	//■追加
	~CMainFrame()
	{
		size_t	i;
		size_t	nSize;

		nSize = _apwndDummy.GetCount();
		for(i = 0; i < nSize; i++)
		{
			if(_apwndDummy[i] == NULL)
				continue;
			delete	_apwndDummy[i];
			_apwndDummy[i] = NULL;
		}
	}

tabbrowser235.gif 後はこれまで_wndDummyにアクセスしていた部分を配列に沿ったものに修正する。 まずはリバーの表示/非表示を切り替える処理だ。
	//タブが選択されたときの処理
	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);	//ステータスバー解放
				}
			}

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


		bool		ret;
		CTabBrowser100View*	pView;
		size_t		i;						//■追加
		size_t		nSize;					//■追加
		bool		bVisible;				//■追加

		nSize = _apwndDummy.GetCount();		//■追加

		pView = GetActivePageView();		//アクティブビュー取得
		if(pView == NULL)
			bVisible = false;
		else
			bVisible = true;

		//■変更
		for(i = 0; i < nSize; i++)
		{
			if(_apwndDummy[i])
				_apwndDummy[i]->ShowRebar(bVisible);				//リバー表示
		}

		if(pView == NULL)
			return	0;

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

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

		return	0;
	}

tabbrowser236.gif タブの新規作成処理。今のところ新しいタブは必ずアクティブに開くので、生成時はAddIEToolbarにtrueを渡している。
	//タブの新規作成
	//nPosはタブを追加する場所。nPos<0(もしくはnPos=m_view.GetPageCount())で一番後ろ、
	//そのほかの数値はCTabView::InsertPageにそのまま渡す
	//
	//戻ったポインタは自動削除されるため、deleteの必要なし
	//
	CTabBrowser100View*	CreateNewTab(LPCTSTR pszURL,LPCTSTR pszTitle,int nPos=-1,int nImage=-1)
	{
		bool	ret;
		CTabBrowser100View*	pView;

		pView = new CTabBrowser100View(&m_view);	//タブビューのポインタを渡す
		if(pView == NULL)
			return	NULL;

		//ビューウインドウ生成
		if(pszURL == NULL || *pszURL == NULL)
			pView->Create(m_view, rcDefault, _T("about:blank"), WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_HSCROLL | WS_VSCROLL, 0);
		else
			pView->Create(m_view, rcDefault, pszURL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_HSCROLL | WS_VSCROLL, 0);
		if(pView->IsWindow() == FALSE)
		{
			delete	pView;
			return	NULL;		//ビューウインドウ生成失敗
		}

		//タブにビューを割り当てる
		if(nPos < 0)
			nPos = m_view.GetPageCount();
		if(pszTitle)
			ret = m_view.InsertPage(nPos,pView->m_hWnd,pszTitle,nImage,pView);
		else
			ret = m_view.InsertPage(nPos,pView->m_hWnd,_T(""),nImage,pView);

		if(ret == false)
		{
			delete	pView;
			return	NULL;		//タブへの追加失敗
		}

		//■処理変更
		//IEツールバーの生成
		{
			size_t	i;
			size_t	nSize;

			nSize = _apwndDummy.GetCount();
			for(i = 0; i < nSize; i++)
			{
				if(_apwndDummy[i])
					pView->AddIEToolbar(*_apwndDummy[i],true);		//IEツールバー生成
			}
		}

		return	pView;
	}

tabbrowser239.gif OnCreateで「Googleツールバー」のGUIDを利用してリバーを作る。今回はAddIEToolbarを2度呼ぶことで2つの「Googleツールバー」を表示することにした。
	LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
	{
		// コマンドバー ウィンドウの作成
		HWND hWndCmdBar = m_CmdBar.Create(m_hWnd, rcDefault, NULL, ATL_SIMPLE_CMDBAR_PANE_STYLE);
		// メニューのアタッチ
		m_CmdBar.AttachMenu(GetMenu());
		// コマンドバー画像の読み込み
		m_CmdBar.LoadImages(IDR_MAINFRAME);
		// 以前のメニューの削除
		SetMenu(NULL);

		HWND hWndToolBar = CreateSimpleToolBarCtrl(m_hWnd, IDR_MAINFRAME, FALSE, ATL_SIMPLE_TOOLBAR_PANE_STYLE);

		CreateSimpleReBar(ATL_SIMPLE_REBAR_NOBORDER_STYLE);
		AddSimpleReBarBand(hWndCmdBar);
		AddSimpleReBarBand(hWndToolBar, NULL, TRUE);

		_wndAddressBar.Create(m_hWnd,CRect(0,0,200,200),0,WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_CLIPCHILDREN,WS_EX_CLIENTEDGE);
		AddSimpleReBarBand(_wndAddressBar,0,TRUE);	//アドレスバーを1列で表示

		//■変更
		//Googleツールバー生成
		{
			GUID	rclsid;
			WCHAR	pszGUID[] = {L"{2318C2B1-4965-11d4-9B18-009027A5CD4F}"};		//GoogleツールバーのGUID

			::CLSIDFromString(pszGUID,&rclsid);

			AddIEToolbar(rclsid);
			AddIEToolbar(rclsid);		//2つ生成
		}


		CreateSimpleStatusBar();

		m_hWndClient = m_view.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, WS_EX_CLIENTEDGE);

		UIAddToolBar(hWndToolBar);
		UISetCheck(ID_VIEW_TOOLBAR, 1);
		UISetCheck(ID_VIEW_STATUS_BAR, 1);

		// メッセージ フィルターおよび画面更新用のオブジェクト登録
		CMessageLoop* pLoop = _Module.GetMessageLoop();
		ATLASSERT(pLoop != NULL);
		pLoop->AddMessageFilter(this);
		pLoop->AddIdleHandler(this);

		CMenuHandle menuMain = m_CmdBar.GetMenu();
		m_view.SetWindowMenu(menuMain.GetSubMenu(WINDOW_MENU_POSITION));

		_cTabImageList.Create(16,16,ILC_COLOR | ILC_MASK,1,10);
		m_view.SetImageList(_cTabImageList);

		return 0;
	}

tabbrowser240.gif 実際のIEツールバー生成処理を担っているビューウインドウ側のCIEToolbarInfoの中で、新しい独自メッセージによりGUIDを取得して利用するようにする。
		//■変更
		//IEツールバーを生成する
		bool	Create(IWebBrowser2* pIWebBrowser2,bool bVisible)
		{
			IID		rclsid = GUID_NULL;

			if(::IsWindow(_hWndRebarIE))
				::SendMessage(_hWndRebarIE,WM_DNP_GETCLSID,(WPARAM)&rclsid,NULL);

			return	CreateIEToolbar(pIWebBrowser2,_hWndRebarIE,&_pIDeskBand,rclsid,bVisible);
		}

tabbrowser241.gif ビューウインドウ側のAddIEToolbarで引数にbVisibleを用意した。
	//■変更
	bool	AddIEToolbar(HWND hWndIERebar,bool bVisible)
	{
		size_t	nIndex;

		nIndex = _aToolbarInfo.Add(CIEToolbarInfo(hWndIERebar));
		_aToolbarInfo[nIndex].Create(_pIWebBrowser2,bVisible);

		return	true;
	}

tabbrowser242.gif 最後に「stdafx.h」内に独自メッセージの定義を追加する。
#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)
#define	WM_DNP_SHOWZONECONFIGURE	(WM_APP + 10)
#define	WM_DNP_GETRBINDEX		(WM_APP + 11)
#define	WM_DNP_GETCLSID			(WM_APP + 12)		//■追加

tabbrowser243.gif
これでビルド/実行すると「Googleツールバー」が2つ表示されるようになった。

次回はInternet Explorerで現在利用可能なツールバーを列挙して使えるようにする。

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


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