第53回 IE用ツールバーを複数利用するための準備をする (タブブラウザーを作る)

tabbrowser228.gif
これまでInternet Explorer用のツールバーとして「Googleツールバー」のみを固定表示していた。これをこれから数回のステップでInternet Explorerのようにインストールされているツールバーを自由に選択/利用できるできるようにする。

まずはビューウインドウ側を少し修正する。単純にメンバー変数として定義していたHWNDとIDeskBand*をCIEToolbarInfoの中に追い出す。
class CTabBrowser100View : public CWindowImpl<CTabBrowser100View, CAxWindow>
	,public IDispEventImpl<SINKID_EVENTS, CTabBrowser100View, &DIID_DWebBrowserEvents2>
	,public CIEUtility
{
	CTabView*	_pTabView;		//タブビューを保持
//	HWND		_hWndRebarIE;	//■削除 IEツールバー用のリバー

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


	CAtlString	_strLastStatusText;					//最後に送られてきたステータステキストを保管
	CComPtr<IDocHostUIHandler>	_pHideScriptError;
	CIELikeStatusbar			_wndStatusbar;		//ステータスバー
//	CComPtr<IDeskBand>			_pIDeskBand;		//■削除 Googleツールバー

	//■追加
	class	CIEToolbarInfo
	{
	public:
		IDeskBand*	_pIDeskBand;
		HWND		_hWndRebarIE;	//IEツールバー用のリバー


		CIEToolbarInfo()
		{
			_hWndRebarIE	= NULL;
			_pIDeskBand		= NULL;
		}

		CIEToolbarInfo(HWND hWndRebar)
		{
			_hWndRebarIE = hWndRebar;
			_pIDeskBand		= NULL;
		}

		//■CMainFrame内から移動&変更
		//Googleツールバーを生成する
		bool	Create(IWebBrowser2* pIWebBrowser2,bool bVisible)
		{
			GUID	rclsid;
			WCHAR	pszGUID[] = {L"{2318C2B1-4965-11d4-9B18-009027A5CD4F}"};		//GoogleツールバーのGUID

			::CLSIDFromString(pszGUID,&rclsid);

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

	protected:

		//■CMainFrame内から移動&変更
		//hWndParentはCDummyWnd(Googleツールバーの親となるウインドウハンドル)
		//clsidIDeskBandはGoogleツールバーのCLSIDを指定する
		bool	CreateIEToolbar(IWebBrowser2* pIWebBrowser2,HWND hWndParent,IDeskBand** ppIDeskBand,const IID& clsidIDeskBand,bool bVisible)
		{
			HRESULT	hr;

			if(ppIDeskBand == NULL || pIWebBrowser2 == NULL)
				return	false;
			if(*ppIDeskBand)
			{
				ATLASSERT(0);
				(*ppIDeskBand)->Release();
				*ppIDeskBand = NULL;
			}

			hr = ::CoCreateInstance(clsidIDeskBand,NULL,CLSCTX_INPROC_SERVER,IID_IDeskBand,(void**)ppIDeskBand);
			if(FAILED(hr) || *ppIDeskBand == NULL)
				return	false;

			CComPtr<IObjectWithSite>	pIObjectWithSite;

			(*ppIDeskBand)->QueryInterface(IID_IObjectWithSite,(void**)&pIObjectWithSite);

			//デスクバンドをホスト用クラスに割り当てる
			{
				CComPtr<IIEToolbar>	pIIEToolbar;

				pIIEToolbar = new CComObject<CIEToolbar>;

				pIIEToolbar->put_hwnd(hWndParent);
				if(pIWebBrowser2)
					pIIEToolbar->put_IWebBrowser2(pIWebBrowser2);
				if(pIObjectWithSite)
					hr = pIObjectWithSite->SetSite(pIIEToolbar);

				if(SUCCEEDED(hr) && bVisible)
					hr = (*ppIDeskBand)->ShowDW(TRUE);		//表示
			}

			DESKBANDINFO	sDeskBandInfo;

			//別に必要ないが情報をたくさん取得
			::ZeroMemory(&sDeskBandInfo,sizeof(DESKBANDINFO));
			sDeskBandInfo.dwMask = DBIM_MINSIZE | DBIM_MAXSIZE | DBIM_INTEGRAL | DBIM_ACTUAL | DBIM_TITLE | DBIM_MODEFLAGS | DBIM_BKCOLOR;
			hr = (*ppIDeskBand)->GetBandInfo(0,DBIF_VIEWMODE_NORMAL,&sDeskBandInfo);

			CRect	rect(0,0,1500,sDeskBandInfo.ptMinSize.y);		//サイズの一時設定(後で自動調整)

			//rebar情報の設定
			{
				HWND	hWndRebar;
				UINT	nIndex;

				hWndRebar = ::GetParent(hWndParent);
				nIndex = -1;
				::SendMessage(hWndParent,WM_DNP_GETRBINDEX,(WPARAM)&nIndex,NULL);
				if(nIndex != -1 && hWndRebar)
				{
					REBARBANDINFO	info;

					//MinSizeのみをリバーへ設定。本来ならもっと情報を設定すべき
					::ZeroMemory(&info,sizeof(REBARBANDINFO));
					info.cbSize	= sizeof(REBARBANDINFO);
					info.fMask	= RBBIM_CHILDSIZE;
					::SendMessage(hWndRebar,RB_GETBANDINFO,nIndex,(LPARAM)&info);
					info.cyMinChild	= sDeskBandInfo.ptMinSize.y;
					info.cyChild	= sDeskBandInfo.ptMinSize.y;
					info.cxMinChild	= sDeskBandInfo.ptMinSize.x;
					::SendMessage(hWndRebar,RB_SETBANDINFO,nIndex,(LPARAM)&info);

					//位置調整
					::SendMessage(hWndRebar,RB_GETRECT,nIndex,(LPARAM)&rect);
					::SendMessage(hWndParent,WM_SIZE,SIZE_RESTORED,MAKELPARAM(rect.Width(),rect.Height()));
				}
			}

			return	true;
		}
	};

tabbrowser229.gif 今回はツールバー情報をCAtlArrayとして実装することにした。
	CAtlArray<CIEToolbarInfo>	_aToolbarInfo;		//■追加


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


	CTabBrowser100View(CTabView* pTabView)		//■変更
	{
		_pTabView = pTabView;
//		_hWndRebarIE = hWndRebarIE;				//■削除
		_bPageError = false;
	}

tabbrowser230.gif
CAtlArrayにより単純にCIEToolbarInfoを配列化しているのでCIEToolbarInfoではCComPtrを使わずにIDeskBand*を利用した。そのためビューウインドウが破棄されるときにReleaseしておく。

さらに配列化したのでOnTabPageChangeでもそれらが呼び出されるように変更する。
	//ビューを閉じるときの処理
	LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		bHandled = FALSE;

		if(_pIWebBrowser2)
			Unadvise(_pIWebBrowser2);	//IEからの切断
		_pIWebBrowser2 = NULL;

		//■追加 IEツールバーの削除
		{
			size_t	i;
			size_t	nSize;

			nSize = _aToolbarInfo.GetCount();
			for(i = 0; i < nSize; i++)
			{
				if(_aToolbarInfo[i]._pIDeskBand == NULL)
					continue;

				_aToolbarInfo[i]._pIDeskBand->ShowDW(FALSE);	//非表示
				_aToolbarInfo[i]._pIDeskBand->CloseDW(0);		//終了
				_aToolbarInfo[i]._pIDeskBand->Release();		//リリース
				_aToolbarInfo[i]._pIDeskBand = NULL;
			}
		}

		return	0;
	}



public:



	//■変更
	//メインウインドウから呼ばれる
	//タブの選択変更があったときメインウインドウから呼ばれる
	bool	OnTabPageChange(bool bActivated)
	{
		size_t	i;
		size_t	nSize;

		nSize = _aToolbarInfo.GetCount();
		for(i = 0; i < nSize; i++)
		{
			if(_aToolbarInfo[i]._pIDeskBand == NULL)
				continue;

			if(bActivated)
				_aToolbarInfo[i]._pIDeskBand->ShowDW(TRUE);		//IEツールバーを表示
			else
				_aToolbarInfo[i]._pIDeskBand->ShowDW(FALSE);	//IEツールバーを消す
		}

		//GoogleツールバーはShowDWで?UIハンドラーを変更するのでここで上書き。
		//ShowWindowで表示/非表示を切り替えれば解決するのかな?要調査
		if(bActivated)
			ChangeUIHandler();			//UIHandlerを変更する

		return	true;
	}

tabbrowser231.gif さらにビューウインドウのCreate内でのGoogleツールバー生成処理を削除し、外部からIE用ツールバーを作成するための関数を追加する。
	//Create関数のオーバーライド。内部でIEの取得、接続などを行う
	HWND Create(HWND hWndParent, _U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
			DWORD dwStyle = 0, DWORD dwExStyle = 0,
			_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
	{
		HWND	hWnd;

		hWnd = __super::Create(hWndParent,rect,szWindowName,dwStyle,dwExStyle,MenuOrID,lpCreateParam);
		if(hWnd == NULL)
			return	NULL;			//Create失敗

		QueryControl(&_pIWebBrowser2);		//_pIWebBrowser2にこのビューに関連づいているIEをセットする
		if(_pIWebBrowser2 == NULL)
			return	hWnd;			//WebBrowser取得失敗

		Advise(_pIWebBrowser2);		//IEとの接続


		//jacascriptや画像ダウンロードのコントロール設定
		{
			CComPtr<IOleObject>		pIOleObject;
			CComObject<CAmbientControl>*		pCAmbientControl;
			CComPtr<IAxWinAmbientDispatchEx>	pIAxWinAmbientDispatchEx;

			//ダウンロードコントロールの準備
			CComObject<CAmbientControl>::CreateInstance(&pCAmbientControl);
			if(pCAmbientControl)
				pCAmbientControl->QueryInterface(&_pIAmbientControl);

			//IEコントロールへのセット
			_pIWebBrowser2->QueryInterface(&pIOleObject);
			if(pIOleObject && pCAmbientControl)
				pIOleObject->SetClientSite(pCAmbientControl);

			//デフォルトのダウンロードコントロールを設定
			//本来ならゾーン変化をチェックしてゾーンに応じて決定すべき?
			SetAmbientDownloadControl(DLCTL_DLIMAGES | DLCTL_VIDEOS | DLCTL_BGSOUNDS);
		}


		//■以下削除

		return	hWnd;
	}


	//■追加
	bool	AddIEToolbar(HWND hWndIERebar)
	{
		size_t	nIndex;

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

		return	true;
	}

tabbrowser232.gif 最後にCMainFrame側でビューを生成するときの処理を変えれば終わりだ。
	//タブの新規作成
	//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;		//タブへの追加失敗
		}

		pView->AddIEToolbar(_wndDummy);		//■追加 Googleツールバー生成

		return	pView;
	}

tabbrowser233.gif
これで実行したときの見た目は変わらないが、少しずつ対応できてきた。次回も引き続きIE用ツールバーを複数利用するための実装を準備する。

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


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