<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
   <channel>
      <title>UsefullCode.net</title>
      <link>http://www.usefullcode.net/</link>
      <description>Visual Studio 2005/2008での開発者向けに便利なソースコードを提供
This site provide you with useful source codes under &apos;USEFULLCODE license&apos;.</description>
      <language>ja</language>
      <copyright>Copyright 2009</copyright>
      <lastBuildDate>Mon, 20 Apr 2009 09:57:26 +0900</lastBuildDate>
      <generator>http://www.sixapart.com/movabletype/</generator>
      <docs>http://blogs.law.harvard.edu/tech/rss</docs> 

            <item>
         <title>第65回  IE用ツールバーを再びきちんと表示する　（タブブラウザーを作る）</title>
         <description><![CDATA[<a href="http://www.usefullcode.net/2009/04/20/tabbrowser295.gif" rel="lightbox"><img alt="tabbrowser295.gif" src="http://www.usefullcode.net/2009/04/20/tabbrowser295-thumb.gif" width="400" height="390" align="left" /></a>
<a href="http://www.usefullcode.net/2009/04/64_tabbrowser.html" target=_blank>前回</a>の作業で、「タブ」をバックグラウンドを開けるようになった。しかしその副作用で、タブの開き方によって「Googleツールバー」などのIE用ツールバーが表示されなかったり、下端が欠けるなどの不具合が生じた。今回はそれらを修正する。

まずCIEToolbarInfoの中でIEツールバーを生成する処理でbVisibleを利用した条件分岐を入れる。
IDeskBandからのGetBandInfoによる情報はShowDW(TRUE)を実行しないときちんと取得できない。そのためShowDWを実行しないときはGetBandInfoによる情報を利用せずに、既存のリバー情報のみを利用するようにした。
<br clear=left>
<pre class=SourceCode>
	//hWndParentはCDummyWnd（Googleツールバーの親となるウインドウハンドル）
	//clsidIDeskBandはGoogleツールバーのCLSIDを指定する
	bool	CreateIEToolbar(IWebBrowser2* pIWebBrowser2,HWND hWndParent,IDeskBand** ppIDeskBand,const IID&amp; clsidIDeskBand,bool bVisible)
	{
		HRESULT	hr;

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

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

		CComPtr&lt;IObjectWithSite&gt;	pIObjectWithSite;

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

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

			pIIEToolbar = new CComObject&lt;CIEToolbar&gt;;

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

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

		DESKBANDINFO	sDeskBandInfo;

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

		CRect	rect;		//■変更 不要なサイズ指定が残っていたので変更

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

			hWndRebar = ::GetParent(hWndParent);
			nIndex = -1;
			::SendMessage(hWndParent,WM_DNP_GETRBINDEX,(WPARAM)&amp;nIndex,NULL);
			if(nIndex != -1 &amp;&amp; hWndRebar)
			{
				//ShowDW(TRUE)を実行していないとGetBandInfoでサイズが
				//取得できないので、bVisible=falseのときはリバーの大きさを
				//調整しない
				if(bVisible)		//■条件を追加
				{
					REBARBANDINFO	info;

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

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

		return	true;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/20/tabbrowser296.gif" rel="lightbox"><img alt="tabbrowser296.gif" src="http://www.usefullcode.net/2009/04/20/tabbrowser296-thumb.gif" width="400" height="347" align="left" /></a>
また、<a href="http://www.usefullcode.net/2009/04/64_tabbrowser.html" target=_blank>前回</a>の実装でCMainFrame::CreateNewTab内にバグがあったのでそれを修正する。
pView-&gt;AddIEToolbarの呼び出し時に「！」が抜けていた。
<br clear=left>
<pre class=SourceCode>
	//タブの新規作成
	//nPosはタブを追加する場所。nPos&lt;0（もしくはnPos=m_view.GetPageCount()）で一番後ろ、
	//そのほかの数値はCTabView::InsertPageにそのまま渡す
	//
	//戻ったポインタは自動削除されるため、deleteの必要なし
	//
	//bOpenInBackground=trueならバックグラウンドでタブを開く
	//
	CTabBrowser100View*	CreateNewTab(LPCTSTR pszURL,LPCTSTR pszTitle,int nPos=-1,int nImage=-1,bool bOpenInBackground=false)
	{
		bool	ret;
		CTabBrowser100View*	pView;

		//bOpenInBackgroundが指定されていても現在タブが1つもない状態ならbOpenInBackgroundをfalseに強制設定する
		if(bOpenInBackground &amp;&amp; m_view.GetPageCount() == 0)
			bOpenInBackground = false;

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

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

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

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

		//IEツールバーの生成
		{
			size_t	i;
			size_t	nSize;

			nSize = _acAvailableIEToolbar.GetCount();
			for(i = 0; i &lt; nSize; i++)
			{
				if(_acAvailableIEToolbar[i].pwndDummy)
					pView-&gt;AddIEToolbar(*_acAvailableIEToolbar[i].pwndDummy,! bOpenInBackground);		//■変更 IEツールバー生成
			}
		}

		return	pView;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/20/tabbrowser297.gif" rel="lightbox"><img alt="tabbrowser297.gif" src="http://www.usefullcode.net/2009/04/20/tabbrowser297-thumb.gif" width="400" height="351" align="left" /></a>
これでビルド／実行するとIE用ツールバーが再びきちんと表示されるようになった。
<br clear=left>
<br>

これまでの作業で

・「お気に入り」メニューを開いているときにメニューバーの「お気に入り」がハイライトにならない
・「お気に入り」メニューでフォーカスが変わるため、メニューを開きながらメニューバーを順に開けない
・「お気に入り」メニューを開くとステータスバーのデザインが壊れる
・「お気に入り」メニュー内の項目選択でステータスバーへ解説表示ができない
・「お気に入り」メニュー内の項目の有効／無効を切りかえれない
・「編集」メニュー内の「コピー」などの各項目をアドレスバーなどIEコントロール以外で利用できない
・スクリプトエラーダイアログの抑制がNavigate直後に働かない
・Navigate直後のタブ名が「about:blank」になる
・アドレスバーの表示URLが長い場合、先頭から表示されずに後方が表示される
・「戻る」「進む」ボタンにIE履歴を選択するためのドロップメニューがない
・IEツールバーを利用するのに毎回手動で表示する必要がある（終了時の状態を保存していない）
・IEツールバーを新規表示するときに必ずリバーが1行表示される
・リンクの右クリックで「新しいタブで開く」でタブを開き、「新しいウインドウで開く」では新しくウインドウを生成するようにすべき
・ページ読み込み中を示す表示がない
・アドレスバーがオートコンプリートによるURL入力に対応していない
・メニュー項目で利用できないものが多い
・実装上のバグからUNICODEビルドしかできない

などなどざっと挙げただけどもまだ不具合や未実装な必要最低限の機能が多く残っている。

しかしだんだん疲れてきたのでしばらくタブブラウザーからは離れて保留にします。お疲れ様でした。また気が向くか要望があれば再開するかもしれませんが。。。

<a href="http://www.usefullcode.net/2009/04/20/20090420_TabBrowser100_65.zip">プロジェクトファイルをダウンロード</a>
]]></description>
         <link>http://www.usefullcode.net/2009/04/65_tabbrowser.html</link>
         <guid>http://www.usefullcode.net/2009/04/65_tabbrowser.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">タブブラウザーを作る</category>
        
        
         <pubDate>Mon, 20 Apr 2009 09:57:26 +0900</pubDate>
      </item>
            <item>
         <title>第64回  「タブ」をバックグラウンドで開けるようにする　（タブブラウザーを作る）</title>
         <description><![CDATA[<a href="http://www.usefullcode.net/2009/04/19/tabbrowser288.gif" rel="lightbox"><img alt="tabbrowser288.gif" src="http://www.usefullcode.net/2009/04/19/tabbrowser288-thumb.gif" width="400" height="598" align="left" /></a>
今回は新しいページをバックグラウンドのタブで開けるようにする。

現状では「ファイルメニュー」の「新規作成」でも、リンクを右クリックして現れるメニューから「新しいウインドウで開く」を選択したときも、新しく開いたタブにフォーカスがあたり、それまで開いていたタブから新しいタブに切り替わってしまう。

それを
・「ファイルメニュー」の「新規作成」で開いたタブはアクティブで
・リンクを右クリックして現れるメニューから「新しいウインドウで開く」から開いたタブはバックグラウンドで
開くようにする。


「タブ」コントロールはWTLのCTabViewを利用している。このクラスには標準ではタブをバックグラウンドで開くオプションがなく、常にアクティブにしてタブが作られてしまう。
CTabViewに新しいタブをバックグラウンドで開くオプションを追加するために、派生クラスを作り、AddPageとInsertPageを上書きする。
<br clear=left>
<pre class=SourceCode>
//■追加
class	CTabViewEx : public CTabView
{

public:

	//WTLのCTabView::InsertPageからソースをコピー＆改変
	//
	//bOpenInBackground=trueなら新しいタブにフォーカスを与えない（バックグラウンドで開く）
	//
	bool AddPage(HWND hWndView, LPCTSTR lpstrTitle, int nImage = -1, LPVOID pData = NULL,bool bOpenInBackground=false)
	{
		return InsertPage(GetPageCount(), hWndView, lpstrTitle, nImage, pData, bOpenInBackground);
	}

	//WTLのCTabView::InsertPageからソースをコピー＆改変
	//
	//bOpenInBackground=trueなら新しいタブにフォーカスを与えない（バックグラウンドで開く）
	//
	bool InsertPage(int nPage, HWND hWndView, LPCTSTR lpstrTitle, int nImage = -1, LPVOID pData = NULL,bool bOpenInBackground=false)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		ATLASSERT(nPage == GetPageCount() || IsValidPageIndex(nPage));

		CTabViewEx* pT = static_cast&lt;CTabViewEx*&gt;(this);		//■変更 CTabViewExでキャスト

		int cchBuff = lstrlen(lpstrTitle) + 1;
		LPTSTR lpstrBuff = NULL;
		ATLTRY(lpstrBuff = new TCHAR[cchBuff]);
		if(lpstrBuff == NULL)
			return false;

		SecureHelper::strcpy_x(lpstrBuff, cchBuff, lpstrTitle);

		CTempBuffer&lt;TCHAR, _WTL_STACK_ALLOC_THRESHOLD&gt; buff;
		LPTSTR lpstrTabText = buff.Allocate(m_cchTabTextLength + 1);
		if(lpstrTabText == NULL)
			return false;

		pT-&gt;ShortenTitle(lpstrTitle, lpstrTabText, m_cchTabTextLength + 1);

		SetRedraw(FALSE);

		TCITEMEXTRA tcix = { 0 };
		tcix.tciheader.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM;
		tcix.tciheader.pszText = lpstrTabText;
		tcix.tciheader.iImage = nImage;
		tcix.tvpage.hWnd = hWndView;
		tcix.tvpage.lpstrTitle = lpstrBuff;
		tcix.tvpage.pData = pData;
		int nItem = m_tab.InsertItem(nPage, tcix);
		if(nItem == -1)
		{
			delete [] lpstrBuff;
			SetRedraw(TRUE);
			return false;
		}

		if(bOpenInBackground == false || GetPageCount() == 1)		//■条件を追加
		{
			//新しいタブをアクティブにする
			SetActivePage(nItem);
			pT-&gt;OnPageActivated(m_nActivePage);
		}

		if(GetPageCount() == 1)
			pT-&gt;ShowTabControl(true);

		pT-&gt;UpdateLayout();

		SetRedraw(TRUE);
		RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);

		return true;
	}
};
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/20/tabbrowser289.gif" rel="lightbox"><img alt="tabbrowser289.gif" src="http://www.usefullcode.net/2009/04/20/tabbrowser289-thumb.gif" width="400" height="326" align="left" /></a>
そしてCMainFrame::m_viewをCTabViewから新しい派生クラスのCTabViewExに変更する。
<br clear=left>
<pre class=SourceCode>
class CMainFrame : public CFrameWindowImpl&lt;CMainFrame&gt;, public CUpdateUI&lt;CMainFrame&gt;,
		public CMessageFilter, public CIdleHandler
		,protected CIShellMenuPopup					//「お気に入り」メニュー用クラス。publicの必要なし
		,protected CIEToolbarManager				//IEツールバー管理クラス。publicの必要なし
{
	CAddressBarCtrl	_wndAddressBar;			// アドレスバー用コンボボックス

	CTabViewEx			m_view;			//■変更
	CCommandBarCtrl2 m_CmdBar;

public:
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/20/tabbrowser290.gif" rel="lightbox"><img alt="tabbrowser290.gif" src="http://www.usefullcode.net/2009/04/20/tabbrowser290-thumb.gif" width="400" height="553" align="left" /></a>
新しいタブを作るための関数CreateNewTabでも新しいタブをアクティブにするかバックグラウンドにするかの選択ができるようにする。
<br clear=left>
<pre class=SourceCode>
	//■変更(bOpenInBackgroundへの対応)
	//タブの新規作成
	//nPosはタブを追加する場所。nPos&lt;0（もしくはnPos=m_view.GetPageCount()）で一番後ろ、
	//そのほかの数値はCTabView::InsertPageにそのまま渡す
	//
	//戻ったポインタは自動削除されるため、deleteの必要なし
	//
	//bOpenInBackground=trueならバックグラウンドでタブを開く
	//
	CTabBrowser100View*	CreateNewTab(LPCTSTR pszURL,LPCTSTR pszTitle,int nPos=-1,int nImage=-1,bool bOpenInBackground=false)
	{
		bool	ret;
		CTabBrowser100View*	pView;

		//■追加
		//bOpenInBackgroundが指定されていても現在タブが1つもない状態ならbOpenInBackgroundをfalseに強制設定する
		if(bOpenInBackground &amp;&amp; m_view.GetPageCount() == 0)
			bOpenInBackground = false;

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

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

		//タブにビューを割り当てる
		if(nPos &lt; 0)
			nPos = m_view.GetPageCount();
		if(pszTitle)
			ret = m_view.InsertPage(nPos,pView-&gt;m_hWnd,pszTitle,nImage,pView,bOpenInBackground);	//■変更
		else
			ret = m_view.InsertPage(nPos,pView-&gt;m_hWnd,_T(&quot;&quot;),nImage,pView,bOpenInBackground);		//■変更

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

		//IEツールバーの生成
		{
			size_t	i;
			size_t	nSize;

			nSize = _acAvailableIEToolbar.GetCount();
			for(i = 0; i &lt; nSize; i++)
			{
				if(_acAvailableIEToolbar[i].pwndDummy)
					pView-&gt;AddIEToolbar(*_acAvailableIEToolbar[i].pwndDummy,bOpenInBackground);		//IEツールバー生成
			}
		}

		return	pView;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/20/tabbrowser292.gif" rel="lightbox"><img alt="tabbrowser292.gif" src="http://www.usefullcode.net/2009/04/20/tabbrowser292-thumb.gif" width="400" height="347" align="left" /></a>
独自メッセージ用のクラスに新しいタブをどう開くかのオプション用変数を追加する。
<br clear=left>
<pre class=SourceCode>
#pragma	once

class	CTabBrowser100View;

// CMainFrame::nDnpCreateNewTab() 用の情報クラス
class	CDnpCreateNewTabInfo
{
public:
	CAtlString	strURL;
	CAtlString	strTitle;
	int		nImage;
	int		nPos;
	bool	bOpenInBackground;		//■追加

	CTabBrowser100View*	pView;

	CDnpCreateNewTabInfo()
	{
		strURL	= _T(&quot;about:blank&quot;);
		pView	= NULL;
		nImage	= -1;
		nPos	= -1;
		bOpenInBackground = false;	//■追加
	}
};
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/20/tabbrowser291.gif" rel="lightbox"><img alt="tabbrowser291.gif" src="http://www.usefullcode.net/2009/04/20/tabbrowser291-thumb.gif" width="400" height="347" align="left" /></a>
そして独自メッセーによるタブ生成処理時にも指定ができるようにする。
<br clear=left>
<pre class=SourceCode>
	//WM_DNP_CREATENEWTABによりタブの作成
	//WPARAMはCDnpCreateNewTabInfoへのポインタを渡す
	LRESULT OnDnpCreateNewTab(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; bHandled)
	{
		CDnpCreateNewTabInfo*	pInfo = (CDnpCreateNewTabInfo*)wParam;

		if(pInfo == NULL)
			return	0;

		//■変更　pInfo-&gt;bOpenInBackgroundを追加
		pInfo-&gt;pView = CreateNewTab(pInfo-&gt;strURL,pInfo-&gt;strTitle,pInfo-&gt;nPos,pInfo-&gt;nImage,pInfo-&gt;bOpenInBackground);

		return	0;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/20/tabbrowser293.gif" rel="lightbox"><img alt="tabbrowser293.gif" src="http://www.usefullcode.net/2009/04/20/tabbrowser293-thumb.gif" width="400" height="347" align="left" /></a>
最後にリンクを右クリックして「新しいウインドウで開く」を選択したときに、バックグラウンドでタブを開くように指定すれば終わりだ。
<br clear=left>
<pre class=SourceCode>
	//新しいウインドウで開く前に呼ばれる処理
	//新しいタブで開く
	void	__stdcall OnNewWindow2(IDispatch **ppDisp,VARIANT_BOOL *Cancel)
	{
		CDnpCreateNewTabInfo	cInfo;

		cInfo.bOpenInBackground = true;		//■追加 リンクを新しいタブで開くときはバックグラウンドで開く

		//新しいタブを作る
		GetTopLevelWindow().SendMessage(WM_DNP_CREATENEWTAB,(WPARAM)&amp;cInfo);
		if(cInfo.pView == NULL || cInfo.pView-&gt;_pIWebBrowser2 == NULL)
			return;

		//新しいタブで開くようにIEコントロールにポインタを渡す
		cInfo.pView-&gt;_pIWebBrowser2-&gt;put_RegisterAsBrowser(VARIANT_TRUE);	//これしなくても開くようになっているのはなぜ？IE8から？一応実行しておく
		cInfo.pView-&gt;_pIWebBrowser2-&gt;get_Application(ppDisp);
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/20/tabbrowser294.gif" rel="lightbox"><img alt="tabbrowser294.gif" src="http://www.usefullcode.net/2009/04/20/tabbrowser294-thumb.gif" width="400" height="433" align="left" /></a>
これで新しいタブをバックグラウンドで開けるようになった。

しかし今回の修正によりリンクを新しいタブで開いたときに「Googleツールバー」の下端が欠けてしまい、きちんと表示されなくなった。次回はその問題を修正する。
<br clear=left>

<a href="http://www.usefullcode.net/2009/04/20/20090420_TabBrowser100_64.zip">プロジェクトファイルをダウンロード</a>
]]></description>
         <link>http://www.usefullcode.net/2009/04/64_tabbrowser.html</link>
         <guid>http://www.usefullcode.net/2009/04/64_tabbrowser.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">タブブラウザーを作る</category>
        
        
         <pubDate>Mon, 20 Apr 2009 05:21:24 +0900</pubDate>
      </item>
            <item>
         <title>第63回  ソースコードを少し整理する　（タブブラウザーを作る）</title>
         <description><![CDATA[これまでの作業でまたソースコードが煩雑化し、まったく利用されていない部分も多く残っている。今回は機能の追加などはせずに少しソースコードを整理する。

<br>
<br>
<h4>過去の「お気に入り」関連処理を削除</h4>

「お気に入り」メニューはIShellMenuにより表示しているが、IShellMenuによる実装の前にはフォルダからインターネットショートカットを検索して直にメニューを生成／表示していた。それらの処理はもう利用しなくなったので削除する。

まず「FavoritesMenu.h」と「DnpFolderMenu.h」の2つのファイルをプロジェクトから取り除く。プロジェクトからの削除に加えて、ファイル自体も削除してしまってかまわない。

そして「MainFrm.h」の中にある「#include &quot;FavoritesMenu.h&quot;」や「CHAIN_MSG_MAP_MEMBER(_cFovMenu)」、関数「CMainFrame::OnMenuSelect」や「CMainFrame::OnFavorite」を削除する。

<br>
<br>
<h4>現在の「お気に入り」関連処理を整理</h4>

「CShellMenuCallback」を独立したヘッダーファイルに移動する。

そしてCMainFrame::PopupMenuの引数に「HWND hWnd」を追加する。この関数の内部処理では「m_hWnd」を参照する部分を「hWnd」に変えて、ウインドウを引数で渡せるようにする。
<pre class=SourceCode>
	bool	PopupMenu(int nX,int nY,HWND hWnd)
</pre>
<br>

次はこれまでメニューリソースの「お気に入り」メニューの位置をソースコードの中で「４」と固定して指定していた。それを簡単に変更できるようにする。
そのためにまず「MainFrm.h」の先頭に以下の宣言を追加する。
<pre class=SourceCode>
#define FAVORITE_MENU_POSITION	4		//メインウインドウ用リソースでの「お気に入り」メニューの位置
</pre>

そして「CMainFrame::PopupMenu」、「CCommandBarCtrl2::DoPopupMenu」、「CMainFrame::OnMenuSelectForPopup」内の「4」というメニュー位置の指定をすべて「FAVORITE_MENU_POSITION」に置き換える。


最後に「お気に入り」関連処理を「CMainFrame」から離した場所に移動する。
独立したヘッダーファイルにクラス「CIShellMenuPopup」を新しく作り、
「CMainFrame::PopupMenu」、「_pIMenuBand」、
「CMainFrame::TranslatePopupMessage」をそのクラスの中に移動する。そして「CMainFrame」の派生元に「CIShellMenuPopup」を追加する。

<br>
<br>
<h4>IEツールバー関連処理を整理</h4>

「CMainFrame」内に実装しているインストールされているIEツールバーを検索する処理などを離した場所に移動する。

独立したヘッダーファイルにクラス「CIEToolbarManager」を新しく作り、CMainFrame内の以下のメンバ関数、クラス、変数をその中に移動する。
・CDummyWnd
・CAvailableIEToolbar
・_acAvailableIEToolbar、
・CLSIDtoUIString
・RegEnumKeyName
・EnumAvailableIEToolbar、

そして「CMainFrame」の派生元に「CIEToolbarManager」を追加する。

<br>
<br>
<h4>その他</h4>

・CAmbientControl
・CTabBrowser100View::CIEToolbarInfo
を独立したヘッダーファイルへ移動する。


・CTabBrowser100View::GetZone
を「CIEUtility」へ移動する。

「CTabBrowser100View」と「CMainFrame」内のメンバ関数やメンバ変数にprotectedやpublicの指定を追加する。

・「CTabBrowser100View」内の変数の記述位置を前後に移動

・その他、少しだけコメントを追加



<br>
<br>
今回は以上の細かなソースコード整理をした。次回は現在のページを開いたままリンクをバックグラウンドのタブで開けるようにする。

<a href="http://www.usefullcode.net/2009/04/19/20090419_TabBrowser100_63.zip">プロジェクトファイルをダウンロード</a>
]]></description>
         <link>http://www.usefullcode.net/2009/04/63_tabbrowser.html</link>
         <guid>http://www.usefullcode.net/2009/04/63_tabbrowser.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">タブブラウザーを作る</category>
        
        
         <pubDate>Sun, 19 Apr 2009 15:40:58 +0900</pubDate>
      </item>
            <item>
         <title>第62回  IShellMenuによる「お気に入り」にメニュー項目を追加する　（タブブラウザーを作る）</title>
         <description><![CDATA[<a href="http://www.usefullcode.net/2009/04/19/tabbrowser284.gif" rel="lightbox"><img alt="tabbrowser284.gif" src="http://www.usefullcode.net/2009/04/19/tabbrowser284-thumb.gif" width="400" height="376" align="left" /></a>
今回は再び「お気に入り」メニュー関連項目を実装する。

「お気に入り」メニューの表示方法をIShellMenuに変えてから、「お気に入りに追加」などの項目が表示されなくなった。今回はこれらの項目を再び表示、使えるようにする。

IShellMenuへのメニュー追加はIShellMenu::SetMenuで行える。ここにリソースから読みだしたHMENUを渡すだけでいい。内部でDestroyMenuされるため、m_Cmdbar.GetMenu()などの引数は渡せない。
<br clear=left>
<pre class=SourceCode>
	bool	PopupMenu(int nX,int nY)
	{
		LPITEMIDLIST	pidl;

		CComPtr&lt;IShellFolder&gt;		pIShellFolder;

		if(_pIMenuBand)
		{
			//すでにメニューが開いていたら、まずはそのメニューを閉じる

			CComPtr&lt;IOleCommandTarget&gt;	pIOleCommandTarget;

			_pIMenuBand-&gt;QueryInterface(&amp;pIOleCommandTarget);
			if(pIOleCommandTarget)
				pIOleCommandTarget-&gt;Exec(&amp;CLSID_MenuBand,22,0,NULL,NULL);
		}


		//「お気に入り」フォルダのPIDLとIShellFolderを取得
		{
			CComPtr&lt;IShellFolder&gt;	pIShellFolderDesktop;

			::SHGetDesktopFolder(&amp;pIShellFolderDesktop);
			if(pIShellFolderDesktop == NULL)
				return	false;
			::SHGetSpecialFolderLocation(NULL,CSIDL_FAVORITES,&amp;pidl);
			pIShellFolderDesktop-&gt;BindToObject(pidl,NULL,IID_IShellFolder,(void **)&amp;pIShellFolder);
		}



		CComPtr&lt;IDeskBand&gt;	pIDeskBand;

		//PIDLとIShellFolderの示すIShellMenu（IDeskBand）を取得
		{
			HRESULT		hr;
			CRegKey		cRegOrder;
			CComPtr&lt;IShellMenu&gt;	pIShellMenu;
			CComPtr&lt;IDeskBar&gt;	pIDeskBar;
			CComPtr&lt;IMenuPopup&gt;	pIMenuPopup;

			//並び順用レジストリ。必要ならCreateしてもいいが今回は「お気に入り」のみなのでopen
			cRegOrder.Open(HKEY_CURRENT_USER,_T(&quot;Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MenuOrder\\Favorites&quot;));

			::CoCreateInstance(CLSID_MenuBand,NULL,CLSCTX_INPROC_SERVER,IID_IShellMenu,(void**)&amp;pIShellMenu);

			//■追加
			//「お気に入りに追加」などのメニュー項目をメニューリソースから追加
			//IShellMenu::Initializeよりも先にIShellMenu::SetMenuを使わないとだめなことに注意
			if(pIShellMenu)
			{
				HMENU	hMenu;
				HMENU	hSubMenu = NULL;

				hMenu = ::LoadMenu(::_Module.m_hInst,MAKEINTRESOURCE(IDR_MAINFRAME));
				if(hMenu)
					hSubMenu = ::GetSubMenu(hMenu,4);			//■メニュー位置固定

				if(hSubMenu)
					pIShellMenu-&gt;SetMenu(hSubMenu,m_hWnd,SMSET_TOP);
				//if(hMenu)
				//	::DestroyMenu(hMenu);		//不要
			}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/19/tabbrowser285.gif" rel="lightbox"><img alt="tabbrowser285.gif" src="http://www.usefullcode.net/2009/04/19/tabbrowser285-thumb.gif" width="400" height="376" align="left" /></a>
そのままでは追加したメニュー項目にデフォルトのアイコンが表示されてしまう。アイコンが表示されないように、SMC_GETINFOを受けとったときに、SMIM_ICONで-1を指定して、アイコンを消す。
<br clear=left>
<pre class=SourceCode>
	//普通のメニュー項目に関する情報
	HRESULT	OnSMC_GETINFO(LPSMDATA psmd,UINT uMsg,WPARAM wParam,LPARAM lParam)
	{
		SMINFO*		pSmInfo = (SMINFO*)lParam;

		if(pSmInfo-&gt;dwMask &amp; SMIM_FLAGS)
			pSmInfo-&gt;dwFlags |= SMIF_DROPCASCADE | SMIF_TRACKPOPUP;

		//■追加
		if(pSmInfo-&gt;dwMask &amp; SMIM_ICON)
			pSmInfo-&gt;iIcon = -1;			//追加メニューのアイコンを非表示にする。iIcon==0のときのみ-1にすべき？

		return	S_OK;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/19/tabbrowser286.gif" rel="lightbox"><img alt="tabbrowser286.gif" src="http://www.usefullcode.net/2009/04/19/tabbrowser286-thumb.gif" width="400" height="376" align="left" /></a>
またIShellMenuを使う前にお気に入りが開いたことを検出するために「dummy」というメニュー項目を用意していた。それはもう不要なのでリソースから消しておく。
<br clear=left>

<a href="http://www.usefullcode.net/2009/04/19/tabbrowser287.gif" rel="lightbox"><img alt="tabbrowser287.gif" src="http://www.usefullcode.net/2009/04/19/tabbrowser287-thumb.gif" width="400" height="337" align="left" /></a>
これでビルド／実行すると「お気に入りの整理」などのメニュー項目が追加され、利用できるようになった。

だんだんソースコードが荒れてきて利用されていない関数も多くなってきた。そのため次回は再びソースコードの整理をする。
<br clear=left>

<a href="http://www.usefullcode.net/2009/04/19/20090419_TabBrowser100_62.zip">プロジェクトファイルをダウンロード</a>
]]></description>
         <link>http://www.usefullcode.net/2009/04/62_tabbrowser.html</link>
         <guid>http://www.usefullcode.net/2009/04/62_tabbrowser.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">タブブラウザーを作る</category>
        
        
         <pubDate>Sun, 19 Apr 2009 11:12:51 +0900</pubDate>
      </item>
            <item>
         <title>第61回  CAxHostWindowのInvokeを上書きする　（タブブラウザーを作る）</title>
         <description><![CDATA[<a href="http://www.usefullcode.net/2009/04/19/tabbrowser281.gif" rel="lightbox"><img alt="tabbrowser281.gif" src="http://www.usefullcode.net/2009/04/19/tabbrowser281-thumb.gif" width="400" height="376" align="left" /></a>
今回は画像表示やスクリプト実行のON/OFFなどを制御するダウンロードコントロールが正常に働くようにする。

とはいうものの前回の作業でほとんどの部分が実装されているのでInvokeを上書きするだけでいい。
<br clear=left>
<pre class=SourceCode>
	//■追加
	STDMETHOD(Invoke)(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
			VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
	{
		HRESULT	hr = E_FAIL;
		CComPtr&lt;IDispatch&gt;	pIDispatch;

		//ダウンロードコントロール用のInvoke
		if(_pIAmbientControl)
			_pIAmbientControl-&gt;QueryInterface(&amp;pIDispatch);
		if(pIDispatch)
			hr = pIDispatch-&gt;Invoke(dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
		if(SUCCEEDED(hr))
			return	hr;

		//IEコントロールのイベント用のInvoke
		hr = IDispEventImpl&lt;SINKID_EVENTS, CTabBrowser100View, &amp;DIID_DWebBrowserEvents2&gt;::Invoke(dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
		if(SUCCEEDED(hr))
			return	hr;

		//デフォルト（CAxHostWindow）用のInvoke
		return CComObject&lt;CAxHostWindow&gt;::Invoke(dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/19/tabbrowser283.gif" rel="lightbox"><img alt="tabbrowser283.gif" src="http://www.usefullcode.net/2009/04/19/tabbrowser283-thumb.gif" width="400" height="376" align="left" /></a>
これは関係ないが、IEツールバーホスト用のクラスの中のフォーカス変更処理は前回の作業で不要になったので削除する。
<br clear=left>
<pre class=SourceCode>
	//IInputObjectSite
	STDMETHOD(OnFocusChangeIS)(IUnknown *punkObj,BOOL fSetFocus)
	{
		//■内部処理削除
		//HRESULT	hr = E_FAIL;
		//CComPtr&lt;IOleInPlaceObject&gt; pIOleInPlaceObject;

		//if(_pIDispatch)
		//	_pIDispatch-&gt;QueryInterface(&amp;pIOleInPlaceObject);
		//if(pIOleInPlaceObject == NULL)
		//	return	S_OK;

		//if(fSetFocus)
		//{
		//	hr = pIOleInPlaceObject-&gt;UIDeactivate();
		//	pIOleInPlaceObject-&gt;InPlaceDeactivate();
		//}
		//else
		//{
		//	HWND hWnd;
		//	hr = pIOleInPlaceObject-&gt;GetWindow(&amp;hWnd);
		//	if(SUCCEEDED(hr) &amp;&amp; ::IsWindow(hWnd))
		//		::ShowWindow(hWnd,SW_NORMAL);
		//}

		return	S_OK;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/19/tabbrowser282.gif" rel="lightbox"><img alt="tabbrowser282.gif" src="http://www.usefullcode.net/2009/04/19/tabbrowser282-thumb.gif" width="400" height="362" align="left" /></a>
これでビルド／実行すると画像表示のON/OFFなどのダウンロード関連機能が再び使えるようになった。

次回は「お気に入り」メニューに「お気に入りの整理」などのメニュー項目を追加する。
<br clear=left>

<a href="http://www.usefullcode.net/2009/04/19/20090419_TabBrowser100_61.zip">プロジェクトファイルをダウンロード</a>
]]></description>
         <link>http://www.usefullcode.net/2009/04/61_tabbrowser.html</link>
         <guid>http://www.usefullcode.net/2009/04/61_tabbrowser.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">タブブラウザーを作る</category>
        
        
         <pubDate>Sun, 19 Apr 2009 09:41:08 +0900</pubDate>
      </item>
            <item>
         <title>第60回  フォーカス変更を検出して処理する　（タブブラウザーを作る）</title>
         <description><![CDATA[<a href="http://www.usefullcode.net/2009/04/19/tabbrowser274.gif" rel="lightbox"><img alt="tabbrowser274.gif" src="http://www.usefullcode.net/2009/04/19/tabbrowser274-thumb.gif" width="400" height="343" align="left" /></a>
前回はフォーカス関連のバグ修正のためビューウインドウをCAxWindowからCAxHostWindowに移行した。今回はIEコントロールがフォーカスを受け取ったことを検出して、正常に処理されるようにする。

まずはCMainFrameのPreTranslateMessage内で、ビューウインドウのPreTranslateMessageが呼ばれるようにする。ATL/WTLアプリケーションウイザードでは標準で同じ様な処理が実装されているが、ウイザードのバグにより正常にビューウインドウのPreTranslateMessageが呼ばれていない。次のバージョンでは修正してもらいたいものだ。。。
<br clear=left>
<pre class=SourceCode>
	virtual BOOL PreTranslateMessage(MSG* pMsg)
	{
		//■追加
		{
			CTabBrowser100View*	pView;

			pView = GetActivePageView();
			if(pView &amp;&amp; pView-&gt;PreTranslateMessage(pMsg))
				return	TRUE;
		}

		if(TranslatePopupMessage(pMsg-&gt;hwnd,pMsg-&gt;message,pMsg-&gt;wParam,pMsg-&gt;lParam,pMsg))
			return	TRUE;

		if(_wndAddressBar.IsChild(::GetFocus()) == FALSE)		//アドレスバーにフォーカスがあるときはPreTranslateMessageを回さない（アドレスバーでCtrl+Cなどを使えるようにするため）
		{
			if(CFrameWindowImpl&lt;CMainFrame&gt;::PreTranslateMessage(pMsg))
				return TRUE;
		}

		return m_view.PreTranslateMessage(pMsg);
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/19/tabbrowser275.gif" rel="lightbox"><img alt="tabbrowser275.gif" src="http://www.usefullcode.net/2009/04/19/tabbrowser275-thumb.gif" width="400" height="560" align="left" /></a>
そしてビューウインドウ内にPreTranslateMessageを追加する。ビューに対してWM_FORWARDMSGを投げると、CAxHostWindow内で自動的にTranslateAcceleatorが呼び出される。

また、フォーカスの変更を取得するためのウインドウCSubclassIEWndを追加する。今回はWM_SETFOCUSもしくはWM_KILLFOCUSがIEコントロールに届いたらそれをビューウインドウへ送るようにした。
<br clear=left>
<pre class=SourceCode>
	//■追加
	//「Internet Explorer_Server」をサブクラス化
	class	CSubclassIEWnd : public CWindowImpl&lt;CSubclassIEWnd&gt;
	{
		CTabBrowser100View*	_pView;
	public:
		CSubclassIEWnd(CTabBrowser100View* pView)
		{
			_pView = pView;
		}
		BEGIN_MSG_MAP(CSubclassIEWnd)
			if(uMsg == WM_SETFOCUS || uMsg == WM_KILLFOCUS)// || uMsg == WM_MOUSEACTIVATE)
			{
				if(_pView)
					_pView-&gt;SendMessage(uMsg,wParam,lParam);
			}

			if(uMsg == WM_DESTROY)
			{
				UnsubclassWindow();
			}
		END_MSG_MAP()
	};

	//■追加
	CSubclassIEWnd	_wndIEServer;

public:
	DECLARE_WND_SUPERCLASS(NULL, CAxWindow::GetWndClassName())	//CAxHostWindow::ではなくCAxWindow::のままなことに注意


	CTabBrowser100View(CTabView* pTabView)
		: _wndReflect(this)
		,_wndIEServer(this)
	{
		_pTabView = pTabView;
		_bPageError = false;
	}


	//■追加
	BOOL PreTranslateMessage(MSG* pMsg)
	{
		if((pMsg-&gt;message &lt; WM_KEYFIRST || pMsg-&gt;message &gt; WM_KEYLAST) &amp;&amp;
		   (pMsg-&gt;message &lt; WM_MOUSEFIRST || pMsg-&gt;message &gt; WM_MOUSELAST))
		{
			return FALSE;
		}

		BOOL bRet = FALSE;

		//IOleInPlaceActiveObject::TranslateAccelerator(pMsg)の呼び出し
		if(pMsg-&gt;hwnd == m_hWnd || IsChild(pMsg-&gt;hwnd))
			bRet = (BOOL)SendMessage(WM_FORWARDMSG, 0, (LPARAM)pMsg);

		return bRet;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/19/tabbrowser276.gif" rel="lightbox"><img alt="tabbrowser276.gif" src="http://www.usefullcode.net/2009/04/19/tabbrowser276-thumb.gif" width="400" height="366" align="left" /></a>
IEコントロールが持つ「Internet Explorer_Server」ウインドウはドキュメントがそろったときに生成される。そのためOnDocumentComplete内でサブクラス化する。
<br clear=left>
<pre class=SourceCode>
	//HTMLページが読み終わったときに呼ばれる処理
	void	_stdcall OnDocumentComplete(IDispatch* pDisp, VARIANT* vURL)
	{
		if(pDisp != _pIWebBrowser2)
			return;			//フレームなどの読み込み終了は無視

		//■追加
		//IEをサブクラス化
		if(_wndIEServer.IsWindow() == FALSE &amp;&amp; _pIWebBrowser2)
		{
			HWND	hWnd;
			HRESULT	hr = E_FAIL;
			CComPtr&lt;IDispatch&gt;	pIDispatch;
			CComPtr&lt;IOleWindow&gt;	pIOleWindow;

			_pIWebBrowser2-&gt;get_Document(&amp;pIDispatch);
			if(pIDispatch)
				pIDispatch-&gt;QueryInterface(&amp;pIOleWindow);
			if(pIOleWindow)
				hr = pIOleWindow-&gt;GetWindow(&amp;hWnd);
			if(SUCCEEDED(hr))
				_wndIEServer.SubclassWindow(hWnd);
		}

		ChangeUIHandler();			//UIHandlerを変更する

		HICON		hIcon;
		CAtlString	strFile;
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/19/tabbrowser278.gif" rel="lightbox"><img alt="tabbrowser278.gif" src="http://www.usefullcode.net/2009/04/19/tabbrowser278-thumb.gif" width="400" height="376" align="left" /></a>
そしてビューウインドウに届いたWM_SETFOCUSなどをメッセージマップで処理する。
<br clear=left>
<pre class=SourceCode>
	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)
		MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus)	//■追加
		MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)	//■追加
		CHAIN_MSG_MAP(CAxHostWindow)
	END_MSG_MAP()


private:

	//■追加
	LRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; bHandled)
	{
		ATLTRACE(&quot;●OnSetFocus\n&quot;);

		SetFocusChange(true);
		bHandled = FALSE;
		return	0;
	}

	//■追加
	LRESULT OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; bHandled)
	{
		ATLTRACE(&quot;●OnKillFocus\n&quot;);

		SetFocusChange(false);
		bHandled = FALSE;
		return	0;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/19/tabbrowser277.gif" rel="lightbox"><img alt="tabbrowser277.gif" src="http://www.usefullcode.net/2009/04/19/tabbrowser277-thumb.gif" width="400" height="366" align="left" /></a>
これまでアドレスバーの中でフォーカスの検出をしていた。この処理はもう不要なので削除する。クラス自体必要性がなくなってしまうのだが、とりあえずこのまま残しておく。
<br clear=left>
<pre class=SourceCode>
//アドレスバー用クラス
class	CAddressBarCtrl	: public CWindowImpl&lt;CAddressBarCtrl,CComboBoxEx&gt;
{
	//■内部処理削除
	class	CInnerComboBox	: public CWindowImpl&lt;CInnerComboBox&gt;
	{
	public:
		BEGIN_MSG_MAP(CInnerComboBox)
			//MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus)
			//MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate)
		END_MSG_MAP()


		////マウスによるフォーカス取得時の処理
		//LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; bHandled)
		//{
		//	GetTopLevelParent().SendMessage(WM_DNP_CHANGEFOCUS,(WPARAM)TRUE);		//メインウインドウへフォーカスを受け取ったことを通知
		//	bHandled = FALSE;
		//	return	0;
		//}

		//LRESULT OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; bHandled)
		//{
		//	GetTopLevelParent().SendMessage(WM_DNP_CHANGEFOCUS,(WPARAM)FALSE);		//メインウインドウへフォーカスを失ったことを通知
		//	bHandled = FALSE;
		//	return	0;
		//}
	};
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/19/tabbrowser279.gif" rel="lightbox"><img alt="tabbrowser279.gif" src="http://www.usefullcode.net/2009/04/19/tabbrowser279-thumb.gif" width="400" height="376" align="left" /></a>
最後に今回のバグの元凶となっていたSetFocusChange内の処理を変更する。
<br clear=left>
<pre class=SourceCode>
	//■変更
	//IEコントロールがフォーカスを受け取ったときbGetFocus=true、
	//IEコントロールがフォーカスを失ったときbGetFocus=falseとして呼び出す
	bool	SetFocusChange(bool bGetFocus)
	{
		if(_pIWebBrowser2 == NULL)
			return	false;

		if(bGetFocus)
		{
		}
		else
		{
			CComPtr&lt;IOleInPlaceObject&gt; pIOleInPlaceObject;

			if(_pIWebBrowser2)
				_pIWebBrowser2-&gt;QueryInterface(&amp;pIOleInPlaceObject);
			if(pIOleInPlaceObject)
				pIOleInPlaceObject-&gt;UIDeactivate();
		}

		return	true;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/19/tabbrowser280.gif" rel="lightbox"><img alt="tabbrowser280.gif" src="http://www.usefullcode.net/2009/04/19/tabbrowser280-thumb.gif" width="400" height="351" align="left" /></a>
これでとりあえず、フォーカス関連のバグは修正された。しかし今回のバグ修正作業によりスクリプトの実行や画像の表示のON/OFF機能が使えなくなってしまっている。

次回はその部分を修正する。
<br clear=left>

<a href="http://www.usefullcode.net/2009/04/19/20090419_TabBrowser100_60.zip">プロジェクトファイルをダウンロード</a>
]]></description>
         <link>http://www.usefullcode.net/2009/04/60_tabbrowser.html</link>
         <guid>http://www.usefullcode.net/2009/04/60_tabbrowser.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">タブブラウザーを作る</category>
        
        
         <pubDate>Sun, 19 Apr 2009 08:45:12 +0900</pubDate>
      </item>
            <item>
         <title>第59回  派生元をCAxWindowからCAxHostWindowに変える　（タブブラウザーを作る）</title>
         <description><![CDATA[<a href="http://www.usefullcode.net/2009/04/19/tabbrowser269.gif" rel="lightbox"><img alt="tabbrowser269.gif" src="http://www.usefullcode.net/2009/04/19/tabbrowser269-thumb.gif" width="400" height="332" align="left" /></a>
今回から数回に分けてフォーカス関連のバグ修正をする。現状ではドロップダウンリストが正常に選択できなくなったり、アドレスバーにフォーカスを置いたままだとIEコントロールの描画が更新されないなどなどの不具合が多い。これらをなんとか治す。

これまで、ビューウインドウはATL/WTLアプリケーションウイザードの生成したCAxWindow派生のものを利用していた。このままだと修正が大変なので、派生元をCAxHostWindowに変更する。

CAxWindowはIEコントロールなどのActiveXコントロールをホストするための簡単な仕組みが備わっているのみだが、CAxHostWindowはかなり多くの実装がされていて便利なためだ。
<br clear=left>
<pre class=SourceCode>
class CTabBrowser100View : public CComObject&lt;CAxHostWindow&gt;	//■変更
	,public IDispEventImpl&lt;SINKID_EVENTS, CTabBrowser100View, &amp;DIID_DWebBrowserEvents2&gt;
	,public CIEUtility
{
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/19/tabbrowser270.gif" rel="lightbox"><img alt="tabbrowser270.gif" src="http://www.usefullcode.net/2009/04/19/tabbrowser270-thumb.gif" width="400" height="581" align="left" /></a>
CAxHostWindowはCWindowImpl派生になっているため、このままではビューウインドウ内でメッセージマップが利用できない。そのためメッセージをCAxHostWindowよりも先に取得してビューウインドウに流仕込むためのウインドウCReflectWndを作成する。
<br clear=left>
<pre class=SourceCode>
	//■追加
	//CAxHostWindowの場合、メッセージハンドラが使えなくなるので
	//このウインドウをサブクラス化してメッセージハンドラが使えるようにする
	class	CReflectWnd : public CWindowImpl&lt;CReflectWnd&gt;
	{
		CTabBrowser100View*	_pView;
	public:
		CReflectWnd(CTabBrowser100View* pView)
		{
			_pView = pView;
		}
		BEGIN_MSG_MAP(CReflectWnd)
			CHAIN_MSG_MAP_MEMBER((*_pView))
		END_MSG_MAP()
	};

	CReflectWnd	_wndReflect;		//■追加

public:
	DECLARE_WND_SUPERCLASS(NULL, CAxWindow::GetWndClassName())	//CAxHostWindow::ではなくCAxWindow::のままなことに注意


	CTabBrowser100View(CTabView* pTabView)
		: _wndReflect(this)						//■追加
	{
		_pTabView = pTabView;
		_bPageError = false;
	}


	BEGIN_SINK_MAP(CTabBrowser100View)
		SINK_ENTRY_EX(SINKID_EVENTS, DIID_DWebBrowserEvents2, DISPID_NEWWINDOW2, OnNewWindow2)
		SINK_ENTRY_EX(SINKID_EVENTS, DIID_DWebBrowserEvents2, DISPID_DOCUMENTCOMPLETE, OnDocumentComplete)
		SINK_ENTRY_EX(SINKID_EVENTS, DIID_DWebBrowserEvents2, DISPID_STATUSTEXTCHANGE, OnStatusTextChange)
		SINK_ENTRY_EX(SINKID_EVENTS, DIID_DWebBrowserEvents2, DISPID_DOWNLOADCOMPLETE, OnDownloadComplete)
		SINK_ENTRY_EX(SINKID_EVENTS, DIID_DWebBrowserEvents2, DISPID_COMMANDSTATECHANGE, OnCommandStateChange)
		SINK_ENTRY_EX(SINKID_EVENTS, DIID_DWebBrowserEvents2, DISPID_DOWNLOADBEGIN, OnDownloadBegin)
		SINK_ENTRY_EX(SINKID_EVENTS, DIID_DWebBrowserEvents2, DISPID_PROGRESSCHANGE, OnProgressChange)
		SINK_ENTRY_EX(SINKID_EVENTS, DIID_DWebBrowserEvents2, DISPID_PROPERTYCHANGE, OnPropertyChange)
		SINK_ENTRY_EX(SINKID_EVENTS, DIID_DWebBrowserEvents2, DISPID_TITLECHANGE, OnTitleChange)
		SINK_ENTRY_EX(SINKID_EVENTS, DIID_DWebBrowserEvents2, DISPID_NAVIGATECOMPLETE2, OnNavigateComplete2)
		SINK_ENTRY_EX(SINKID_EVENTS, DIID_DWebBrowserEvents2, DISPID_NAVIGATEERROR, OnNavigateError)
		SINK_ENTRY_EX(SINKID_EVENTS, DIID_DWebBrowserEvents2, DISPID_PRIVACYIMPACTEDSTATECHANGE, OnPrivacyImpactedStateChange)
		SINK_ENTRY_EX(SINKID_EVENTS, DIID_DWebBrowserEvents2, DISPID_NEWWINDOW3, OnNewWindow3)
		SINK_ENTRY_EX(SINKID_EVENTS, DIID_DWebBrowserEvents2, DISPID_SETSECURELOCKICON, OnSetSecureLockIcon)
	END_SINK_MAP()

	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)
		CHAIN_MSG_MAP(CAxHostWindow)		//■追加
	END_MSG_MAP()
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/19/tabbrowser271.gif" rel="lightbox"><img alt="tabbrowser271.gif" src="http://www.usefullcode.net/2009/04/19/tabbrowser271-thumb.gif" width="400" height="581" align="left" /></a>
そしてCreate()の処理を変更する。CAxHostWindow::Create()は使わずに、CWindow::Createを、CAxWindow（CAxHostWindowではない）のクラス名を使って呼び出してウインドウ生成をする。

このままだとCAxHostWindowにIEコントロールが入らないので、AttachControlとSetSiteで作成したIEコントロールをCAxHostWindowに割り当てる。
<br clear=left>
<pre class=SourceCode>
	//■変更
	//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;

		//__super::ではなく、CWindow::のCreateをCAxWindow::GetWndClassName()指定で利用
		hWnd = CWindow::Create(CAxWindow::GetWndClassName(), hWndParent, rect, szWindowName, dwStyle, dwExStyle, MenuOrID, lpCreateParam);
		if(hWnd == NULL)
			return	NULL;			//Create失敗

		_wndReflect.SubclassWindow(m_hWnd);		//メッセージマップが使えるようにこのウインドウをサブクラス化

		//CWindow::Createで作れたコントロールをこのウインドウにアタッチ
		{
			CComPtr&lt;IUnknown&gt;	pIUnknown;

			AtlAxGetControl(m_hWnd,&amp;pIUnknown);
			if(pIUnknown)
				AttachControl(pIUnknown,m_hWnd);

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

			//サイトも設定
			pIUnknown = NULL;
			QueryHost(&amp;pIUnknown);
			SetSite(pIUnknown);
		}

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


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

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

//■削除CAxHostWindowを使うのでセットしない
//			//IEコントロールへのセット
//			_pIWebBrowser2-&gt;QueryInterface(&amp;pIOleObject);
//			if(pIOleObject &amp;&amp; pCAmbientControl)
//				pIOleObject-&gt;SetClientSite(pCAmbientControl);

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

		return	hWnd;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/19/tabbrowser272.gif" rel="lightbox"><img alt="tabbrowser272.gif" src="http://www.usefullcode.net/2009/04/19/tabbrowser272-thumb.gif" width="400" height="388" align="left" /></a>
CAxHostWidnowにはQueryHostが実装されておらず、ちょっとだけ不便なのでCAxWindowからコピーして実装しておく。
<br clear=left>
<pre class=SourceCode>
	//■追加
	//CAxWindowのソースからコピー。ホスト取得用関数
	template &lt;class Q&gt;
	HRESULT QueryHost(Q** ppUnk)
	{
		return QueryHost(__uuidof(Q), (void**)ppUnk);
	}
	HRESULT QueryHost(REFIID iid, void** ppUnk)
	{
		ATLASSERT(ppUnk != NULL);
		if (ppUnk == NULL)
			return E_POINTER;
		HRESULT hr;
		*ppUnk = NULL;
		CComPtr&lt;IUnknown&gt; spUnk;
		hr = AtlAxGetHost(m_hWnd, &amp;spUnk);
		if (SUCCEEDED(hr))
			hr = spUnk-&gt;QueryInterface(iid, ppUnk);
		return hr;
	}
</pre>

<a href="http://www.usefullcode.net/2009/04/19/tabbrowser273.gif" rel="lightbox"><img alt="tabbrowser273.gif" src="http://www.usefullcode.net/2009/04/19/tabbrowser273-thumb.gif" width="400" height="351" align="left" /></a>
これでとりあえず今回は終了だ。まだCAxWindowからCAxHostWindowに切り替えただけでバグは修正されていない。

次回はバグ修正のためにフォーカスがIEコントロールにあるのか、それともそれ以外にあるのかを検出する処理を実装する。
<br clear=left>

<a href="http://www.usefullcode.net/2009/04/19/20090419_TabBrowser100_59.zip">プロジェクトファイルをダウンロード</a>
]]></description>
         <link>http://www.usefullcode.net/2009/04/59_tabbrowser.html</link>
         <guid>http://www.usefullcode.net/2009/04/59_tabbrowser.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">タブブラウザーを作る</category>
        
        
         <pubDate>Sun, 19 Apr 2009 07:34:03 +0900</pubDate>
      </item>
            <item>
         <title>第58回  IShellMenuCallbackにより「お気に入り」をビューで開く　（タブブラウザーを作る）</title>
         <description><![CDATA[<a href="http://www.usefullcode.net/2009/04/17/tabbrowser264.gif" rel="lightbox"><img alt="tabbrowser264.gif" src="http://www.usefullcode.net/2009/04/17/tabbrowser264-thumb.gif" width="400" height="425" align="left" /></a>
<a href="http://www.usefullcode.net/2009/04/57_tabbrowser.html" target=_blank>前回</a>は「お気に入り」メニューをIShellMenuベースに置き換えた。今回はIShellMenu用のコールバックインターフェースを用意して、選択した「お気に入り」がビューで開くようにする。

IShellMenuCallbackがコールバック用インターフェースで、各種イベント時にIShellMenuCallback::CallbackSMが呼ばれる。ここでは「お気に入り」が選択されたときにそのフルパスを独自メッセージでメインウインドウへ返すようにする。
<br clear=left>
<pre class=SourceCode>
//■追加
//IEツールバーをホストするためのインターフェース
MIDL_INTERFACE(&quot;50AFAFED-815E-4ec4-9A78-231C95958716&quot;)
IShellMenuHost : public IUnknown
{
public:
	STDMETHOD (put_IShellFolder)(IShellFolder* pIShellFolder) = 0;
	STDMETHOD (put_NotifyWindow)(HWND hWnd,UINT nMessageID) = 0;
};


//■追加
class	CShellMenuCallback : 
	public CComObjectRootEx&lt;CComSingleThreadModel&gt;
	,public IShellMenuHost
	,public IShellMenuCallback
{
	UINT	_nNotifyMessage;
	HWND	_hWndNotify;

	CComPtr&lt;IShellFolder&gt;	_pIShellFolder;

public:
	BEGIN_COM_MAP(CShellMenuCallback)
		COM_INTERFACE_ENTRY(IShellMenuHost)
		COM_INTERFACE_ENTRY(IShellMenuCallback)
	END_COM_MAP()

	DECLARE_PROTECT_FINAL_CONSTRUCT()

	CShellMenuCallback()
	{
		_nNotifyMessage = 0;
		_hWndNotify = NULL;
	}

	//
	STDMETHOD (put_IShellFolder)(IShellFolder* pIShellFolder)
	{
		_pIShellFolder = NULL;
		if(pIShellFolder == NULL)
			return	E_POINTER;

		return	pIShellFolder-&gt;QueryInterface(IID_IShellFolder,(void**)&amp;_pIShellFolder);
	}

	STDMETHOD (put_NotifyWindow)(HWND hWnd,UINT nMessageID)
	{
		if(hWnd == NULL || ::IsWindow(hWnd) == FALSE || nMessageID == 0)
			return	E_FAIL;

		_hWndNotify = hWnd;
		_nNotifyMessage = nMessageID;

		return	S_OK;
	}




	HRESULT	OnSMC_INITMENU(LPSMDATA psmd,UINT uMsg,WPARAM wParam,LPARAM lParam)
	{
		return	S_FALSE;
	}

	//メニューが作られた
	//処理は不要
	HRESULT	OnSMC_CREATE(LPSMDATA psmd,UINT uMsg,WPARAM wParam,LPARAM lParam)
	{
		return	S_FALSE;
	}

	HRESULT	OnSMC_EXITMENU(LPSMDATA psmd,UINT uMsg,WPARAM wParam,LPARAM lParam)
	{
		return	S_OK;
	}


	//普通のメニュー項目に関する情報
	HRESULT	OnSMC_GETINFO(LPSMDATA psmd,UINT uMsg,WPARAM wParam,LPARAM lParam)
	{
		SMINFO*		pSmInfo = (SMINFO*)lParam;

		if(pSmInfo-&gt;dwMask &amp; SMIM_FLAGS)
			pSmInfo-&gt;dwFlags |= SMIF_DROPCASCADE | SMIF_TRACKPOPUP;

		return	S_OK;
	}

	//IShellFolder項目に関する情報
	//処理必要なし
	HRESULT	OnSMC_GETSFINFO(LPSMDATA psmd,UINT uMsg,WPARAM wParam,LPARAM lParam)
	{
		return	S_OK;
	}

	HRESULT	OnSMC_GETOBJECT(LPSMDATA psmd,UINT uMsg,WPARAM wParam,LPARAM lParam)
	{
		REFIID	iid = (REFIID)wParam;
		void**	ppv = (void**)lParam;

		//処理していない
		return	S_FALSE;
	}

	HRESULT	OnSMC_GETSFOBJECT(LPSMDATA psmd,UINT uMsg,WPARAM wParam,LPARAM lParam)
	{
		REFIID	iid = (REFIID)wParam;
		void**	ppv = (void**)lParam;

		//処理していない
		return	S_FALSE;
	}

	//選択された項目を開く
	HRESULT	OnSMC_SFEXEC(LPSMDATA psmd,UINT uMsg,WPARAM wParam,LPARAM lParam)
	{
		TCHAR	pszFile[MAX_PATH];
		TCHAR	pszPath[MAX_PATH];
		int		nFind;
		CAtlString	strName;

		*pszPath = NULL;
		::SHGetPathFromIDList(psmd-&gt;pidlItem,pszFile);
		::SHGetPathFromIDList(psmd-&gt;pidlFolder,pszPath);

		strName = pszFile;
		nFind = strName.ReverseFind(_T('\\'));
		if(nFind &gt;= 0)
			strName = strName.Right(strName.GetLength() - nFind);
		strName = pszPath + strName;

		//ウインドウへメッセージを送る
		if(*pszPath &amp;&amp; _hWndNotify &amp;&amp; ::IsWindow(_hWndNotify) &amp;&amp; _nNotifyMessage)
			::SendMessage(_hWndNotify,_nNotifyMessage,(WPARAM)(LPCTSTR)strName,NULL);

		return	S_OK;
	}

	HRESULT	OnSMC_SFSELECTITEM(LPSMDATA psmd,UINT uMsg,WPARAM wParam,LPARAM lParam)
	{
		return	S_OK;
	}

	HRESULT	OnSMC_REFRESH(LPSMDATA psmd,UINT uMsg,WPARAM wParam,LPARAM lParam)
	{
		return	S_OK;
	}

	HRESULT	OnSMC_DEMOTE(LPSMDATA psmd,UINT uMsg,WPARAM wParam,LPARAM lParam)
	{
		return	S_OK;
	}

	HRESULT	OnSMC_PROMOTE(LPSMDATA psmd,UINT uMsg,WPARAM wParam,LPARAM lParam)
	{
		return	S_OK;
	}

	HRESULT	OnSMC_DEFAULTICON(LPSMDATA psmd,UINT uMsg,WPARAM wParam,LPARAM lParam)
	{
		return	S_OK;
	}

	HRESULT	OnSMC_NEWITEM(LPSMDATA psmd,UINT uMsg,WPARAM wParam,LPARAM lParam)
	{
		return	S_OK;
	}

	HRESULT	OnSMC_CHEVRONEXPAND(LPSMDATA psmd,UINT uMsg,WPARAM wParam,LPARAM lParam)
	{
		return	S_OK;
	}

	HRESULT	OnSMC_DISPLAYCHEVRONTIP(LPSMDATA psmd,UINT uMsg,WPARAM wParam,LPARAM lParam)
	{
		return	S_OK;
	}

	HRESULT	OnSMC_SETSFOBJECT(LPSMDATA psmd,UINT uMsg,WPARAM wParam,LPARAM lParam)
	{
		return	S_OK;
	}

	HRESULT	OnSMC_SHCHANGENOTIFY(LPSMDATA psmd,UINT uMsg,WPARAM wParam,LPARAM lParam)
	{
		return	S_OK;
	}

	HRESULT	OnSMC_CHEVRONGETTIP(LPSMDATA psmd,UINT uMsg,WPARAM wParam,LPARAM lParam)
	{
		return	S_OK;
	}

	HRESULT	On(LPSMDATA psmd,UINT uMsg,WPARAM wParam,LPARAM lParam)
	{
		return	S_OK;
	}

	HRESULT	OnSMC_SFDDRESTRICTED(LPSMDATA psmd,UINT uMsg,WPARAM wParam,LPARAM lParam)
	{
		return	S_OK;
	}




	STDMETHOD(CallbackSM)(LPSMDATA psmd,UINT uMsg,WPARAM wParam,LPARAM lParam)
	{
		switch(uMsg)
		{
		// The callback is called to init a menuband
		case	SMC_INITMENU:
			return	OnSMC_INITMENU(psmd,uMsg,wParam,lParam);

		case	SMC_CREATE:
			return	OnSMC_CREATE(psmd,uMsg,wParam,lParam);

		// The callback is called when menu is collapsing
		case	SMC_EXITMENU:
			return	OnSMC_EXITMENU(psmd,uMsg,wParam,lParam);

		// The callback is called to return DWORD values
		case	SMC_GETINFO:
			return	OnSMC_GETINFO(psmd,uMsg,wParam,lParam);

		// The callback is called to return DWORD values
		case	SMC_GETSFINFO:
			return	OnSMC_GETSFINFO(psmd,uMsg,wParam,lParam);

		// The callback is called to get some object
		case	SMC_GETOBJECT:
			return	OnSMC_GETOBJECT(psmd,uMsg,wParam,lParam);

		// The callback is called to get some object
		case	SMC_GETSFOBJECT:
			return	OnSMC_GETSFOBJECT(psmd,uMsg,wParam,lParam);

		// The callback is called to execute an shell folder item
		case	SMC_SFEXEC:
			return	OnSMC_SFEXEC(psmd,uMsg,wParam,lParam);

		// The callback is called when an item is selected
		case	SMC_SFSELECTITEM:
			return	OnSMC_SFSELECTITEM(psmd,uMsg,wParam,lParam);

		// Menus have completely refreshed. Reset your state.
		case	SMC_REFRESH:
			return	OnSMC_REFRESH(psmd,uMsg,wParam,lParam);

		// Demote an item
		case	SMC_DEMOTE:
			return	OnSMC_DEMOTE(psmd,uMsg,wParam,lParam);

		// Promote an item, wParam = SMINV_* flag
		case	SMC_PROMOTE:
			return	OnSMC_PROMOTE(psmd,uMsg,wParam,lParam);

		// Returns Default icon location in wParam, index in lParam
		case	SMC_DEFAULTICON:
			return	OnSMC_DEFAULTICON(psmd,uMsg,wParam,lParam);

		// Notifies item is not in the order stream.
		case	SMC_NEWITEM:
			return	OnSMC_NEWITEM(psmd,uMsg,wParam,lParam);

		// Notifies of a expansion via the chevron
		case	SMC_CHEVRONEXPAND:
			return	OnSMC_CHEVRONEXPAND(psmd,uMsg,wParam,lParam);

		// S_OK display, S_FALSE not.
		case	SMC_DISPLAYCHEVRONTIP:
			return	OnSMC_DISPLAYCHEVRONTIP(psmd,uMsg,wParam,lParam);

		// Called to save the passed object
		case	SMC_SETSFOBJECT:
			return	OnSMC_SETSFOBJECT(psmd,uMsg,wParam,lParam);

		// Called when a Change notify is received. lParam points to SMCSHCHANGENOTIFYSTRUCT
		case	SMC_SHCHANGENOTIFY:
			return	OnSMC_SHCHANGENOTIFY(psmd,uMsg,wParam,lParam);

		// Called to get the chevron tip text. wParam = Tip title, Lparam = TipText Both MAX_PATH
		case	SMC_CHEVRONGETTIP:
			OnSMC_CHEVRONGETTIP(psmd,uMsg,wParam,lParam);
			break;

		// Called requesting if it's ok to drop. wParam = IDropTarget.
		case	SMC_SFDDRESTRICTED:
			OnSMC_SFDDRESTRICTED(psmd,uMsg,wParam,lParam);
			break;

		default:
			break;
		}

		return	S_FALSE;
	}
};
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/17/tabbrowser265.gif" rel="lightbox"><img alt="tabbrowser265.gif" src="http://www.usefullcode.net/2009/04/17/tabbrowser265-thumb.gif" width="400" height="456" align="left" /></a>
そしてメインウインドウで独自メッセージが届いたときにビューでURLが開くようにする。
<br clear=left>
<pre class=SourceCode>
		NOTIFY_CODE_HANDLER(TBVN_PAGEACTIVATED, OnTabPageActivated)
		MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelectForPopup)
//		MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)
		MESSAGE_HANDLER(WM_DNP_NAVIGATEFAVORITE, OnDnpNavigateFavorite)	//■追加
		MESSAGE_HANDLER(WM_PARENTNOTIFY, OnParentNotify)
//		COMMAND_RANGE_HANDLER(ID_FAVORITE_FIRST,ID_FAVORITE_LAST,OnFavorite)	//■削除
		CHAIN_MSG_MAP_MEMBER(_cFovMenu)
		CHAIN_MSG_MAP(CUpdateUI&lt;CMainFrame&gt;)
		CHAIN_MSG_MAP(CFrameWindowImpl&lt;CMainFrame&gt;)
	END_MSG_MAP()


	//■追加
	LRESULT OnDnpNavigateFavorite(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; bHandled)
	{
		bool		ret;
		CAtlString	strURL;
		LPCTSTR	pszFile = (LPCTSTR)wParam;

		if(pszFile == NULL || *pszFile == NULL)
			return	0;

		ret = GetInternetShortcut(pszFile,strURL);
		if(ret == false)
			return	0;

		//タブとしてURLを開く
		{
			CTabBrowser100View* pView;

			pView = GetActivePageView();
			if(pView == NULL)
			{
				//新しいタブを作成
				pView = CreateNewTab(_T(&quot;about:blank&quot;),NULL);
			}

			//URLを開く
			if(pView)
				pView-&gt;Navigate(strURL);
		}

		return	0;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/17/tabbrowser266.gif" rel="lightbox"><img alt="tabbrowser266.gif" src="http://www.usefullcode.net/2009/04/17/tabbrowser266-thumb.gif" width="400" height="456" align="left" /></a>
IShellMenu::Initializeで先ほど作成したコールバック用インターフェースを渡す。
<br clear=left>
<pre class=SourceCode>
	bool	PopupMenu(int nX,int nY)
	{
		LPITEMIDLIST	pidl;

		CComPtr&lt;IShellFolder&gt;		pIShellFolder;

		if(_pIMenuBand)
		{
			//すでにメニューが開いていたら、まずはそのメニューを閉じる

			CComPtr&lt;IOleCommandTarget&gt;	pIOleCommandTarget;

			_pIMenuBand-&gt;QueryInterface(&amp;pIOleCommandTarget);
			if(pIOleCommandTarget)
				pIOleCommandTarget-&gt;Exec(&amp;CLSID_MenuBand,22,0,NULL,NULL);
		}


		//「お気に入り」フォルダのPIDLとIShellFolderを取得
		{
			CComPtr&lt;IShellFolder&gt;	pIShellFolderDesktop;

			::SHGetDesktopFolder(&amp;pIShellFolderDesktop);
			if(pIShellFolderDesktop == NULL)
				return	false;
			::SHGetSpecialFolderLocation(NULL,CSIDL_FAVORITES,&amp;pidl);
			pIShellFolderDesktop-&gt;BindToObject(pidl,NULL,IID_IShellFolder,(void **)&amp;pIShellFolder);
		}



		CComPtr&lt;IDeskBand&gt;	pIDeskBand;

		//PIDLとIShellFolderの示すIShellMenu（IDeskBand）を取得
		{
			HRESULT		hr;
			CRegKey		cRegOrder;
			CComPtr&lt;IShellMenu&gt;	pIShellMenu;
			CComPtr&lt;IDeskBar&gt;	pIDeskBar;
			CComPtr&lt;IMenuPopup&gt;	pIMenuPopup;

			//並び順用レジストリ。必要ならCreateしてもいいが今回は「お気に入り」のみなのでopen
			cRegOrder.Open(HKEY_CURRENT_USER,_T(&quot;Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MenuOrder\\Favorites&quot;));

			::CoCreateInstance(CLSID_MenuBand,NULL,CLSCTX_INPROC_SERVER,IID_IShellMenu,(void**)&amp;pIShellMenu);

			//■処理変更
			if(pIShellMenu)
			{
				CComPtr&lt;IShellMenuHost&gt;			pIShellMenuHost;
				CComPtr&lt;IShellMenuCallback&gt;		pIShellMenuCallback;

				//コールバック生成
				pIShellMenuCallback = new CComObject&lt;CShellMenuCallback&gt;;
				if(pIShellMenuCallback)
					pIShellMenuCallback-&gt;QueryInterface(&amp;pIShellMenuHost);
				if(pIShellMenuHost)
				{
					pIShellMenuHost-&gt;put_IShellFolder(pIShellFolder);
					pIShellMenuHost-&gt;put_NotifyWindow(m_hWnd,WM_DNP_NAVIGATEFAVORITE);
				}

				//IShellMenuの初期化
				pIShellMenu-&gt;Initialize(pIShellMenuCallback,-1,ANCESTORDEFAULT,SMINIT_TOPLEVEL | SMINIT_VERTICAL);

				#ifndef	SMSET_USEBKICONEXTRACTION
					#define SMSET_USEBKICONEXTRACTION	0x00000008
				#endif

				//メニューへのフォルダ割り当て
				hr = pIShellMenu-&gt;SetShellFolder(pIShellFolder,pidl,cRegOrder.m_hKey,SMSET_BOTTOM | SMSET_USEBKICONEXTRACTION);	//以下も指定したいが値が不明 | SMSET_HASEXPANDABLEFOLDERS)

				if(SUCCEEDED(hr))
					cRegOrder.Detach();	//レジストリのCloseはIShellMenuに任せる
				ILFree(pidl);
				pidl = NULL;
			}

			if(pIShellMenu)
				pIShellMenu-&gt;QueryInterface(&amp;pIMenuPopup);
			if(pIMenuPopup)
				pIMenuPopup-&gt;QueryInterface(&amp;pIDeskBar);
			if(pIDeskBar)
				pIDeskBar-&gt;QueryInterface(&amp;pIDeskBand);
			if(pIDeskBand == NULL)
				return	false;
		}


		//IShellMenu（IDeskBand）をポップアップメニューで表示
		{
			POINTL	ptl;
			GUID	rclsid;
			CComPtr&lt;IUnknown&gt;			pIUnknown;
			CComPtr&lt;IBandSite&gt;			pIBandSite;
			CComPtr&lt;IMenuPopup&gt;			pIMenuPopup;

			//メニュー用のDeskBar「Menu Desk Bar」
			::CLSIDFromString(L&quot;{ECD4FC4F-521C-11D0-B792-00A0C90312E1}&quot;,&amp;rclsid);
			::CoCreateInstance(rclsid,NULL,CLSCTX_INPROC_SERVER,IID_IUnknown,(void**)&amp;pIUnknown);

			//メニュー用のBandSite
			::CoCreateInstance(CLSID_MenuBandSite,NULL,CLSCTX_INPROC_SERVER,IID_IBandSite,(void**)&amp;pIBandSite);

			if(pIUnknown)
				pIUnknown-&gt;QueryInterface(&amp;pIMenuPopup);	//メニュー用DeskBarだからIMenuPopupを持っている
			if(pIMenuPopup)
				pIMenuPopup-&gt;SetClient(pIBandSite);			//DeskBarにIBandSiteを割り当て
			if(pIBandSite)
				pIBandSite-&gt;AddBand(pIDeskBand);			//IBandSiteに表示したいIShellMenuを割り当てる

			//位置を指定してメニュー表示
			ptl.x = nX;
			ptl.y = nY;
			if(pIMenuPopup)
				pIMenuPopup-&gt;Popup(&amp;ptl,NULL,MPPF_POS_MASK | MPPF_FORCEZORDER | MPPF_RIGHT | MPPF_BOTTOM);
		}


		//メニューの_pIMenuBandを保存
		{
			_pIMenuBand = NULL;
			pIDeskBand-&gt;QueryInterface(&amp;_pIMenuBand);
			if(_pIMenuBand == NULL)
				return	false;
		}

		return	true;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/17/tabbrowser267.gif" rel="lightbox"><img alt="tabbrowser267.gif" src="http://www.usefullcode.net/2009/04/17/tabbrowser267-thumb.gif" width="400" height="456" align="left" /></a>
最後に「stdafx.h」内に独自メッセージを定義しておく。
<br clear=left>
<pre class=SourceCode>
#define	WM_DNP_NAVIGATEFAVORITE		(WM_APP + 13)	//■追加
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/17/tabbrowser268.gif" rel="lightbox"><img alt="tabbrowser268.gif" src="http://www.usefullcode.net/2009/04/17/tabbrowser268-thumb.gif" width="400" height="328" align="left" /></a>
これで「お気に入り」を選択したときにそのURLがビューで開くようになった。また「お気に入り」の表示順序をドラッグアンドドロップにより変更できるようになった。

次回は少しフォーカス関連のバグ修正をする。
<br clear=left>

<a href="http://www.usefullcode.net/2009/04/17/20090417_TabBrowser100_58.zip">プロジェクトファイルをダウンロード</a>
]]></description>
         <link>http://www.usefullcode.net/2009/04/58_tabbrowser.html</link>
         <guid>http://www.usefullcode.net/2009/04/58_tabbrowser.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">タブブラウザーを作る</category>
        
        
         <pubDate>Fri, 17 Apr 2009 10:54:10 +0900</pubDate>
      </item>
            <item>
         <title>第57回  IShellMenuにより「お気に入り」を表示する　（タブブラウザーを作る）</title>
         <description><![CDATA[<a href="http://www.usefullcode.net/2009/04/17/tabbrowser258.gif" rel="lightbox"><img alt="tabbrowser258.gif" src="http://www.usefullcode.net/2009/04/17/tabbrowser258.gif" width="400" height="608" align="left" /></a>
今回は「お気に入り」の表示方法を一新する。

これまでは「お気に入り」フォルダから保存されているインターネットショートカットを列挙して独自にメニューを生成／表示していた。これをInternet Explorerの「お気に入り」や「スタート」メニューと同じようにシェルメニュー（IShellMenu）ベースのものに変える。

Windows Vista以降であればITrackShellMenuを利用することで非常に簡単にIShellMenuをメニューとして表示できる。しかし2009年4月現在Windows Vistaはまだまだ普及率が悪い。そのためITrackShellMenuは使わずに力技でIShellMenuを表示することにした。

CMainFrameにIShellMenuを利用した「お気に入り」表示関数を追加する。
<br clear=left>
<pre class=SourceCode>

	CComPtr&lt;IMenuBand&gt;	_pIMenuBand;


	bool	PopupMenu(int nX,int nY)
	{
		LPITEMIDLIST	pidl;

		CComPtr&lt;IShellFolder&gt;		pIShellFolder;

		if(_pIMenuBand)
		{
			//すでにメニューが開いていたら、まずはそのメニューを閉じる

			CComPtr&lt;IOleCommandTarget&gt;	pIOleCommandTarget;

			_pIMenuBand-&gt;QueryInterface(&amp;pIOleCommandTarget);
			if(pIOleCommandTarget)
				pIOleCommandTarget-&gt;Exec(&amp;CLSID_MenuBand,22,0,NULL,NULL);
		}


		//「お気に入り」フォルダのPIDLとIShellFolderを取得
		{
			CComPtr&lt;IShellFolder&gt;	pIShellFolderDesktop;

			::SHGetDesktopFolder(&amp;pIShellFolderDesktop);
			if(pIShellFolderDesktop == NULL)
				return	false;
			::SHGetSpecialFolderLocation(NULL,CSIDL_FAVORITES,&amp;pidl);
			pIShellFolderDesktop-&gt;BindToObject(pidl,NULL,IID_IShellFolder,(void **)&amp;pIShellFolder);
		}



		CComPtr&lt;IDeskBand&gt;	pIDeskBand;

		//PIDLとIShellFolderの示すIShellMenu（IDeskBand）を取得
		{
			HRESULT		hr;
			CRegKey		cRegOrder;
			CComPtr&lt;IShellMenu&gt;	pIShellMenu;
			CComPtr&lt;IDeskBar&gt;	pIDeskBar;
			CComPtr&lt;IMenuPopup&gt;	pIMenuPopup;

			//並び順用レジストリ。必要ならCreateしてもいいが今回は「お気に入り」のみなのでopen
			cRegOrder.Open(HKEY_CURRENT_USER,_T(&quot;Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MenuOrder\\Favorites&quot;));

			::CoCreateInstance(CLSID_MenuBand,NULL,CLSCTX_INPROC_SERVER,IID_IShellMenu,(void**)&amp;pIShellMenu);

			if(pIShellMenu)
			{
				//とりあえずCallback指定していない
				pIShellMenu-&gt;Initialize(NULL,-1,ANCESTORDEFAULT,SMINIT_TOPLEVEL | SMINIT_VERTICAL);

				#ifndef	SMSET_USEBKICONEXTRACTION
					#define SMSET_USEBKICONEXTRACTION	0x00000008
				#endif

				//メニューへのフォルダ割り当て
				hr = pIShellMenu-&gt;SetShellFolder(pIShellFolder,pidl,cRegOrder.m_hKey,SMSET_BOTTOM | SMSET_USEBKICONEXTRACTION);	//以下も指定したいが値が不明 | SMSET_HASEXPANDABLEFOLDERS)

				if(SUCCEEDED(hr))
					cRegOrder.Detach();	//レジストリのCloseはIShellMenuに任せる
				ILFree(pidl);
				pidl = NULL;
			}

			if(pIShellMenu)
				pIShellMenu-&gt;QueryInterface(&amp;pIMenuPopup);
			if(pIMenuPopup)
				pIMenuPopup-&gt;QueryInterface(&amp;pIDeskBar);
			if(pIDeskBar)
				pIDeskBar-&gt;QueryInterface(&amp;pIDeskBand);
			if(pIDeskBand == NULL)
				return	false;
		}


		//IShellMenu（IDeskBand）をポップアップメニューで表示
		{
			POINTL	ptl;
			GUID	rclsid;
			CComPtr&lt;IUnknown&gt;			pIUnknown;
			CComPtr&lt;IBandSite&gt;			pIBandSite;
			CComPtr&lt;IMenuPopup&gt;			pIMenuPopup;

			//メニュー用のDeskBar「Menu Desk Bar」
			::CLSIDFromString(L&quot;{ECD4FC4F-521C-11D0-B792-00A0C90312E1}&quot;,&amp;rclsid);
			::CoCreateInstance(rclsid,NULL,CLSCTX_INPROC_SERVER,IID_IUnknown,(void**)&amp;pIUnknown);

			//メニュー用のBandSite
			::CoCreateInstance(CLSID_MenuBandSite,NULL,CLSCTX_INPROC_SERVER,IID_IBandSite,(void**)&amp;pIBandSite);

			if(pIUnknown)
				pIUnknown-&gt;QueryInterface(&amp;pIMenuPopup);	//メニュー用DeskBarだからIMenuPopupを持っている
			if(pIMenuPopup)
				pIMenuPopup-&gt;SetClient(pIBandSite);			//DeskBarにIBandSiteを割り当て
			if(pIBandSite)
				pIBandSite-&gt;AddBand(pIDeskBand);			//IBandSiteに表示したいIShellMenuを割り当てる

			//位置を指定してメニュー表示
			ptl.x = nX;
			ptl.y = nY;
			if(pIMenuPopup)
				pIMenuPopup-&gt;Popup(&amp;ptl,NULL,MPPF_POS_MASK | MPPF_FORCEZORDER | MPPF_RIGHT | MPPF_BOTTOM);
		}


		//メニューの_pIMenuBandを保存
		{
			_pIMenuBand = NULL;
			pIDeskBand-&gt;QueryInterface(&amp;_pIMenuBand);
			if(_pIMenuBand == NULL)
				return	false;
		}

		return	true;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/17/tabbrowser259.gif" rel="lightbox"><img alt="tabbrowser259.gif" src="http://www.usefullcode.net/2009/04/17/tabbrowser259-thumb.gif" width="400" height="425" align="left" /></a>
そしてメッセージハンドラに「お気に入り」メニューを表示するための処理を入れる。今回はWM_MENUSELECTが届いたときに表示することにした。
<br clear=left>
<pre class=SourceCode>
		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, OnMenuSelectForPopup)		//■追加
//		MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)		//■削除
		MESSAGE_HANDLER(WM_PARENTNOTIFY, OnParentNotify)
		COMMAND_RANGE_HANDLER(ID_FAVORITE_FIRST,ID_FAVORITE_LAST,OnFavorite)
		CHAIN_MSG_MAP_MEMBER(_cFovMenu)
		CHAIN_MSG_MAP(CUpdateUI&lt;CMainFrame&gt;)
		CHAIN_MSG_MAP(CFrameWindowImpl&lt;CMainFrame&gt;)
	END_MSG_MAP()


	//■追加
	LRESULT OnMenuSelectForPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; bHandled)
	{
		bHandled = FALSE;

		UINT	nMenuItem = LOWORD(wParam);
		HMENU	hMenu = (HMENU)lParam;

		if(HIWORD(wParam) &amp; MF_POPUP)
			return	0;
		if(nMenuItem != 4)							//メニュー位置
			return	0;

		RECT	rect;

		m_CmdBar.GetItemRect(nMenuItem,&amp;rect);
		m_CmdBar.MapWindowPoints(NULL,&amp;rect);

		PopupMenu(rect.left,rect.bottom);

		return	0;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/17/tabbrowser262.gif" rel="lightbox"><img alt="tabbrowser262.gif" src="http://www.usefullcode.net/2009/04/17/tabbrowser262-thumb.gif" width="400" height="532" align="left" /></a>
もともとメニューリソースに用意されているメニューが表示されてしまわないように、CCommandBarCtrlのメニュー表示部分を上書きする。
<br clear=left>
<pre class=SourceCode>
//■追加
class	CCommandBarCtrl2	: public CCommandBarCtrlImpl&lt;CCommandBarCtrl2&gt;
{
public:
	BEGIN_MSG_MAP(CCommandBarCtrl2)
			CHAIN_MSG_MAP(__super)
		ALT_MSG_MAP(1)   // Parent window messages
			CHAIN_MSG_MAP_ALT(__super,1)
		ALT_MSG_MAP(2)   // MDI client window messages
			CHAIN_MSG_MAP_ALT(__super,2)
		ALT_MSG_MAP(3)   // Message hook messages
			CHAIN_MSG_MAP_ALT(__super,3)
	END_MSG_MAP()


	void DoPopupMenu(int nIndex, bool bAnimate)
	{
		if(nIndex == 4)		//メニュー位置固定
		{
			HWND	hWnd = ::GetAncestor(m_hWnd,GA_ROOT);
			::SendMessage(hWnd,WM_MENUSELECT,MAKEWPARAM(nIndex,MF_HILITE),(LPARAM)GetMenu().m_hMenu);
			return;
		}

		__super::DoPopupMenu(nIndex,bAnimate);
	}
};


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


public:
	DECLARE_FRAME_WND_CLASS(NULL, IDR_MAINFRAME)

	CTabView m_view;
	CCommandBarCtrl2 m_CmdBar;
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/17/tabbrowser260.gif" rel="lightbox"><img alt="tabbrowser260.gif" src="http://www.usefullcode.net/2009/04/17/tabbrowser260-thumb.gif" width="400" height="460" align="left" /></a>
さらにIShellMenuがきちんとメッセージを処理できるようにIMenuBand::TranslateMenuMessageを呼び出す処理を追加する。
<br clear=left>
<pre class=SourceCode>
	virtual BOOL PreTranslateMessage(MSG* pMsg)
	{
		//■追加
		if(TranslatePopupMessage(pMsg-&gt;hwnd,pMsg-&gt;message,pMsg-&gt;wParam,pMsg-&gt;lParam,pMsg))
			return	TRUE;

		if(_wndAddressBar.IsChild(::GetFocus()) == FALSE)		//アドレスバーにフォーカスがあるときはPreTranslateMessageを回さない（アドレスバーでCtrl+Cなどを使えるようにするため）
		{
			if(CFrameWindowImpl&lt;CMainFrame&gt;::PreTranslateMessage(pMsg))
				return TRUE;
		}

		return m_view.PreTranslateMessage(pMsg);
	}



	//■追加
	//
	//ポップアップメニューのメッセージ処理
	//
	//pMsg == NULLのときは開いているメニューを閉じるべきかどうかのチェックも併せておこなう
	//（PreTranslateMessageではpMsgも指定する）
	//
	bool	TranslatePopupMessage(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam,MSG* pMsg=NULL)
	{
		if(_pIMenuBand == NULL)
			return	false;

		HRESULT	hr;
		LRESULT	ret = 0;
		MSG		msg;

		if(pMsg == NULL)
		{
			::ZeroMemory(&amp;msg,sizeof(MSG));
			msg.hwnd = hWnd;
			msg.message = uMsg;
			msg.wParam = wParam;
			msg.lParam = lParam;
		}
		else
		{
			msg = *pMsg;
		}

		hr = _pIMenuBand-&gt;IsMenuMessage(&amp;msg);
		if(hr == S_OK)
			hr = _pIMenuBand-&gt;TranslateMenuMessage(&amp;msg,&amp;ret);
		if(hr == S_OK)
			return	true;

		//メニューを閉じるべきかどうかのチェック
		//もう少しチェック項目を増やした方がいい。。。
		if(pMsg == NULL
			&amp;&amp; (hr == E_FAIL
			|| (uMsg &gt;= WM_MOUSEFIRST &amp;&amp; uMsg &lt;= WM_MOUSELAST)
			|| uMsg == WM_INITMENUPOPUP
			|| uMsg == WM_SIZE
			|| uMsg == WM_MOVE
			|| uMsg == WM_MOVING
			|| uMsg == WM_INITMENU
			|| 0))
		{
			//メニューを閉じる

			CComPtr&lt;IOleCommandTarget&gt;	pIOleCommandTarget;

			_pIMenuBand-&gt;QueryInterface(&amp;pIOleCommandTarget);
			if(pIOleCommandTarget)
				pIOleCommandTarget-&gt;Exec(&amp;CLSID_MenuBand,22,0,NULL,NULL);
		}

		return	false;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/17/tabbrowser261.gif" rel="lightbox"><img alt="tabbrowser261.gif" src="http://www.usefullcode.net/2009/04/17/tabbrowser261-thumb.gif" width="400" height="351" align="left" /></a>
ちょっと汚い実装方法だが、メッセージマップの中からもIMenuBandへメッセージが渡るようにする。
<br clear=left>
<pre class=SourceCode>
	BEGIN_MSG_MAP(CMainFrame)
		//■追加
		{
			//「お気に入り」メニュー用TranslateMessage
			if(TranslatePopupMessage(hWnd,uMsg,wParam,lParam))
				return	TRUE;
		}
		MESSAGE_HANDLER(WM_DNP_CREATENEWTAB, OnDnpCreateNewTab)
		MESSAGE_HANDLER(WM_DNP_CHANGEFOCUS, OnDnpChangeFocus)
		MESSAGE_HANDLER(WM_DNP_CHANGEADDRESS, OnDnpChangeAddress)
		NOTIFY_CODE_HANDLER(CBEN_ENDEDIT, OnAddressbarEnter)
		MESSAGE_HANDLER(WM_CREATE, OnCreate)
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/17/tabbrowser263.gif" rel="lightbox"><img alt="tabbrowser263.gif" src="http://www.usefullcode.net/2009/04/17/tabbrowser263-thumb.gif" width="400" height="328" align="left" /></a>
これでビルド／実行するとIShellMenuにより「お気に入り」が表示されるようになった。

まだ実装が不十分なため「お気に入り」メニューが開いているのにコマンドバーの「お気に入り」がハイライト状態になっていない、ドラッグアンドドロップによる「お気に入り」の移動ができない、メニュー表示がクラシックスタイルなどなど機能が足りない。

しかし「お気に入り」の並び順がInternet Explorerでの表示と同じだったり、アイコンの読み込みがバックグラウンドで行われる、TIPSが表示されるなど「お気に入り」メニューとしてそこそこ使える状態になっている。

次回は選択した「お気に入り」のURLをタブとして開くようにする。
<br clear=left>

<a href="http://www.usefullcode.net/2009/04/17/20090417_TabBrowser100_57.zip">プロジェクトファイルをダウンロード</a>
]]></description>
         <link>http://www.usefullcode.net/2009/04/57_tabbrowser.html</link>
         <guid>http://www.usefullcode.net/2009/04/57_tabbrowser.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">タブブラウザーを作る</category>
        
        
         <pubDate>Fri, 17 Apr 2009 07:54:19 +0900</pubDate>
      </item>
            <item>
         <title>第56回  右クリックメニューでIEツールバーを選択する　（タブブラウザーを作る）</title>
         <description><![CDATA[<a href="http://www.usefullcode.net/2009/04/16/tabbrowser250.gif" rel="lightbox"><img alt="tabbrowser250.gif" src="http://www.usefullcode.net/2009/04/16/tabbrowser250.gif" width="400" height="360" align="left" /></a>
<a href="http://www.usefullcode.net/2009/04/55_tabbrowser.html" target=_blank>前回</a>はインストールされて利用可能なInternet Explorer用ツールバーがすべて表示されるようにした。
今回は右クリックメニューから選んで表示／非表示できるようにする。

ツールバーなどのエリアでの右クリック処理はWM_PARENTNOTIFYとして届く。これを受け取ったらRB_HITTESTを利用して右クリックされた場所がツールバーならIEツールバー選択用のメニューを表示する。
そして選択されたIEツールバーの表示／非表示を切り替える。
<br clear=left>
<pre class=SourceCode>
		NOTIFY_CODE_HANDLER(TBVN_CONTEXTMENU, OnTabContextMenu)
		NOTIFY_CODE_HANDLER(TBVN_PAGEACTIVATED, OnTabPageActivated)
		MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)
		MESSAGE_HANDLER(WM_PARENTNOTIFY, OnParentNotify)			//■追加
		COMMAND_RANGE_HANDLER(ID_FAVORITE_FIRST,ID_FAVORITE_LAST,OnFavorite)
		CHAIN_MSG_MAP_MEMBER(_cFovMenu)
		CHAIN_MSG_MAP(CUpdateUI&lt;CMainFrame&gt;)
		CHAIN_MSG_MAP(CFrameWindowImpl&lt;CMainFrame&gt;)
	END_MSG_MAP()


	//■追加
	LRESULT OnParentNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; bHandled)
	{
		if(wParam != WM_RBUTTONDOWN)
			return	0;

		size_t	nIndex;
		POINT	pt;

		::GetCursorPos(&amp;pt);

		{
			RBHITTESTINFO	info;

			::ZeroMemory(&amp;info,sizeof(RBHITTESTINFO));
			info.pt = pt;
			ScreenToClient(&amp;info.pt);
			if(::SendMessage(m_hWndToolBar,RB_HITTEST,NULL,(LPARAM)&amp;info) &lt; 0)
				return	0;
		}

		//メニュー表示
		{
			HMENU	hMenu;
			size_t	i;
			size_t	nSize;

			nSize = _acAvailableIEToolbar.GetCount();
			if(nSize == 0)			//利用可能なIEツールバーがない
				return	0;

			hMenu = ::CreatePopupMenu();

			for(i = 0; i &lt; nSize; i++)
			{
				::InsertMenu(hMenu,i,MF_BYPOSITION | MF_STRING,i + 1,_acAvailableIEToolbar[i].strName);

				if(_acAvailableIEToolbar[i].IsVisible())
					::CheckMenuItem(hMenu,i + 1,MF_CHECKED | MF_BYCOMMAND);
			}

			nIndex = (size_t)::TrackPopupMenu(hMenu,TPM_LEFTALIGN | TPM_RETURNCMD,pt.x,pt.y,NULL,m_hWnd,NULL);
			::DestroyMenu(hMenu);

			if(nIndex == 0)
				return	0;			//選択されなかった
			nIndex--;
		}


		if(_acAvailableIEToolbar[nIndex].IsVisible() == false)
		{
			//ツールバーの表示
			AddIEToolbar(nIndex);
		}
		else
		{
			//ツールバーの消去
			int		i;
			int		nSize;
			CTabBrowser100View*	pView;

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

				pView-&gt;RemoveIEToolbar(_acAvailableIEToolbar[nIndex].pwndDummy-&gt;m_hWnd);
			}

			::SendMessage(m_hWndToolBar,RB_DELETEBAND,(WPARAM)_acAvailableIEToolbar[nIndex].pwndDummy-&gt;GetRebarIndex(),NULL);

			_acAvailableIEToolbar[nIndex].pwndDummy-&gt;DestroyWindow();
			delete	_acAvailableIEToolbar[nIndex].pwndDummy;
			_acAvailableIEToolbar[nIndex].pwndDummy = NULL;
		}


		bHandled = FALSE;
		return	0;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/16/tabbrowser253.gif" rel="lightbox"><img alt="tabbrowser253.gif" src="http://www.usefullcode.net/2009/04/16/tabbrowser253.gif" width="400" height="360" align="left" /></a>
今までツールバーの管理をCAtlArray&lt;CDummyWnd*&gt;にしていたが、このままだと表示／非表示の切り替えがややこしいのでacAvailableIEToolbarに移動する。

また、AddIEToolbarの引数もクラスIDから_acAvailableIEToolbarへのインデックスに変更しておく。
<br clear=left>
<pre class=SourceCode>
//	CAtlArray&lt;CDummyWnd*&gt;	_apwndDummy;	//■削除_acAvailableIEToolbarの中へ

	//■変更。引数からCLSIDから_acAvailableIEToolbarへのインデックスに変更。
	bool	AddIEToolbar(size_t nIndex)
	{
		IID			clsidIDeskBand;
		CDummyWnd*	pwndDummy;

		if(nIndex &gt;= _acAvailableIEToolbar.GetCount())
			return	false;			//不正なインデックス
		if(_acAvailableIEToolbar[nIndex].IsVisible())
			return	false;			//すでに表示されている

		clsidIDeskBand = _acAvailableIEToolbar[nIndex].clsidToolbar;

		pwndDummy = new CDummyWnd(clsidIDeskBand);

		//ダミーウインドウを生成し、リバーに割り当てる。これはIEツールバーに利用
		pwndDummy-&gt;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-&gt;_nBandID = nCount + ATL_IDW_BAND_FIRST - 1;

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

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

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

		_acAvailableIEToolbar[nIndex].pwndDummy = pwndDummy;

		return	true;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/16/tabbrowser254.gif" rel="lightbox"><img alt="tabbrowser254.gif" src="http://www.usefullcode.net/2009/04/16/tabbrowser254.gif" width="400" height="360" align="left" /></a>
IDeskBandの親ウインドウとして利用するpwndDummyとIsVisibleを用意した。ただしIsVisibleは実際にIDeskBandが表示状態かどうかまではチェックしていない。
<br clear=left>
<pre class=SourceCode>
	//■変更 pwndDummyを追加
	class	CAvailableIEToolbar
	{
	public:
		CAtlString	strName;
		IID			clsidToolbar;
		CDummyWnd*	pwndDummy;

		CAvailableIEToolbar()
		{
			pwndDummy = NULL;
			clsidToolbar = GUID_NULL;
		}

		CAvailableIEToolbar(const IID&amp; clsid,LPCTSTR pszName)
		{
			pwndDummy = NULL;
			clsidToolbar = clsid;
			strName = pszName;
		}

		bool	IsVisible(void)
		{
			if(pwndDummy == NULL || pwndDummy-&gt;IsWindow() == FALSE)
				return	false;
			return	true;
		}
	};
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/16/tabbrowser249.gif" rel="lightbox"><img alt="tabbrowser249.gif" src="http://www.usefullcode.net/2009/04/16/tabbrowser249.gif" width="400" height="360" align="left" /></a>
デストラクタ内のCDummyWndのdelete処理も_acAvailableIEToolbarに変更する。
<br clear=left>
<pre class=SourceCode>
	//■変更
	~CMainFrame()
	{
		size_t	i;
		size_t	nSize;

		nSize = _acAvailableIEToolbar.GetCount();
		for(i = 0; i &lt; nSize; i++)
		{
			if(_acAvailableIEToolbar[i].pwndDummy == NULL)
				continue;
			delete	_acAvailableIEToolbar[i].pwndDummy;
			_acAvailableIEToolbar[i].pwndDummy = NULL;
		}
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/16/tabbrowser251.gif" rel="lightbox"><img alt="tabbrowser251.gif" src="http://www.usefullcode.net/2009/04/16/tabbrowser251.gif" width="400" height="360" align="left" /></a>
_acAvailableIEToolbarのCDummyWndを取得するように変更する。
<br clear=left>
<pre class=SourceCode>
	//■変更
	//タブが選択されたときの処理
	LRESULT OnTabPageActivated(int idCtrl, LPNMHDR pnmh, BOOL&amp; bHandled)
	{
		if(pnmh == NULL)
			return	0;

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

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

				if(pnmh-&gt;idFrom == i)
					pView-&gt;OnTabPageChange(true);
				else
				{
					pView-&gt;OnTabPageChange(false);
					pView-&gt;SetStatusBar(m_hWndStatusBar,false);	//ステータスバー解放
				}
			}

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


		bool		ret;
		CTabBrowser100View*	pView;
		size_t		i;
		size_t		nSize;
		bool		bVisible;
		nSize = _acAvailableIEToolbar.GetCount();

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

		for(i = 0; i &lt; nSize; i++)
		{
			if(_acAvailableIEToolbar[i].pwndDummy)
				_acAvailableIEToolbar[i].pwndDummy-&gt;ShowRebar(bVisible);				//リバー表示
		}

		if(pView == NULL)
			return	0;

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

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

		return	0;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/16/tabbrowser252.gif" rel="lightbox"><img alt="tabbrowser252.gif" src="http://www.usefullcode.net/2009/04/16/tabbrowser252.gif" width="400" height="360" align="left" /></a>
_acAvailableIEToolbarのCDummyWndを取得するように変更する。
<br clear=left>
<pre class=SourceCode>
	//■変更
	//タブの新規作成
	//nPosはタブを追加する場所。nPos&lt;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(&amp;m_view);	//タブビューのポインタを渡す
		if(pView == NULL)
			return	NULL;

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

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

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

		//IEツールバーの生成
		{
			size_t	i;
			size_t	nSize;

			nSize = _acAvailableIEToolbar.GetCount();
			for(i = 0; i &lt; nSize; i++)
			{
				if(_acAvailableIEToolbar[i].pwndDummy)
					pView-&gt;AddIEToolbar(*_acAvailableIEToolbar[i].pwndDummy,true);		//IEツールバー生成
			}
		}

		return	pView;
	}
</pre>
<br>


<a href="http://www.usefullcode.net/2009/04/16/tabbrowser255.gif" rel="lightbox"><img alt="tabbrowser255.gif" src="http://www.usefullcode.net/2009/04/16/tabbrowser255.gif" width="400" height="360" align="left" /></a>
これまでOnCreateでは見つかったすべてのIEツールバーを表示していた。これをIEツールバーを探すにとどめる。
<br clear=left>
<pre class=SourceCode>
	LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL&amp; /*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列で表示


		//■削除
		//{
		//	size_t	i;
		//	size_t	nSize;

		//	EnumAvailableIEToolbar();

		//	nSize = _acAvailableIEToolbar.GetCount();
		//	for(i = 0; i &lt; nSize; i++)
		//	{
		//		AddIEToolbar(_acAvailableIEToolbar[i].clsidToolbar);
		//	}
		//}

		//■追加
		EnumAvailableIEToolbar();			//IEツールバーの列挙

		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-&gt;AddMessageFilter(this);
		pLoop-&gt;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;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/16/tabbrowser256.gif" rel="lightbox"><img alt="tabbrowser256.gif" src="http://www.usefullcode.net/2009/04/16/tabbrowser256.gif" width="400" height="360" align="left" /></a>
最後にビューウインドウ側でIEツールバーを非表示にする処理を追加する。
今回は表示／非表示は生成／破棄により実現している。そのためタブが多い場合はかなり負荷がかかってしまう。
<br clear=left>
<pre class=SourceCode>
	//■追加
	bool	RemoveIEToolbar(HWND hWndIERebar)
	{
		size_t	i;
		size_t	nSize;

		nSize = _aToolbarInfo.GetCount();
		for(i = 0; i &lt; nSize; i++)
		{
			if(_aToolbarInfo[i]._hWndRebarIE != hWndIERebar)
				continue;

			_aToolbarInfo[i]._hWndRebarIE = NULL;

			if(_aToolbarInfo[i]._pIDeskBand == NULL)
				return	true;

			_aToolbarInfo[i]._pIDeskBand-&gt;ShowDW(FALSE);
			_aToolbarInfo[i]._pIDeskBand-&gt;CloseDW(0);
			_aToolbarInfo[i]._pIDeskBand = NULL;

			return	true;
		}

		return	false;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/16/tabbrowser257.gif" rel="lightbox"><img alt="tabbrowser257.gif" src="http://www.usefullcode.net/2009/04/16/tabbrowser257-thumb.gif" width="400" height="333" align="left" /></a>
これでビルド／実行すると、ツールバー部分の右クリックメニューによりInternet Explorer用ツールバーを選んで表示／非表示できるようになった。

次回はお気に入りメニューをきちんとしたものに作り直す準備をする。
<br clear=left>

<a href="http://www.usefullcode.net/2009/04/16/20090416_TabBrowser100_56.zip">ファイルをダウンロード</a>
]]></description>
         <link>http://www.usefullcode.net/2009/04/56_tabbrowser.html</link>
         <guid>http://www.usefullcode.net/2009/04/56_tabbrowser.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">タブブラウザーを作る</category>
        
        
         <pubDate>Thu, 16 Apr 2009 16:41:57 +0900</pubDate>
      </item>
            <item>
         <title>第55回  インストールされているすべてのIEツールバーを表示する　（タブブラウザーを作る）</title>
         <description><![CDATA[<a href="http://www.usefullcode.net/2009/04/12/tabbrowser245.gif" rel="lightbox"><img alt="tabbrowser245.gif" src="http://www.usefullcode.net/2009/04/12/tabbrowser245-thumb.gif" width="400" height="433" align="left" /></a>
<a href="http://www.usefullcode.net/2009/04/54_tabbrowser.html" target=_blank>前回</a>までの作業で「Googleツールバー」を複数表示できるようになった。今回は「Googleツールバー」だけでなく、ほかのInternet Explorer用ツールバーも表示できるようにする。

まず、現在Internet Explorer用として登録されている利用可能なツールバー情報を保存しておくためのクラスを用意する。
<br clear=left>
<pre class=SourceCode>
	//■追加
	class	CAvailableIEToolbar
	{
	public:
		CAtlString	strName;
		IID			clsidToolbar;

		CAvailableIEToolbar()
		{
			clsidToolbar = GUID_NULL;
		}

		CAvailableIEToolbar(const IID&amp; clsid,LPCTSTR pszName)
		{
			clsidToolbar = clsid;
			strName = pszName;
		}
	};

	CAtlArray&lt;CAvailableIEToolbar&gt;	_acAvailableIEToolbar;	//■追加



	//■追加
	//指定したHKEY内のレジストリキー名を列挙
	bool	RegEnumKeyName(HKEY hKey,CAtlArray&lt;CAtlString&gt;&amp; astrClsid)
	{
		int		i;
		LONG	nRet;

		i = 0;
		while(1)
		{
			TCHAR	pszName[2048];
			DWORD	dwLen;
			DWORD	dwType;

			//レジストリ内を列挙
			dwLen = 2048;
			*pszName = NULL;
			nRet = ::RegEnumValue(hKey,i++,pszName,&amp;dwLen,NULL,&amp;dwType,NULL,NULL);
			if(nRet != ERROR_SUCCESS)
				break;
			if(pszName == NULL || *pszName == NULL)
				continue;

			astrClsid.Add(pszName);
		}

		return	true;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/12/tabbrowser246.gif" rel="lightbox"><img alt="tabbrowser246.gif" src="http://www.usefullcode.net/2009/04/12/tabbrowser246-thumb.gif" width="400" height="433" align="left" /></a>
レジストリから利用可能なIE用ツールバーのCLSIDを取得する。HKEY_CURRENT_USERとHKEY_LOCAL_MACHINEの2箇所に保存されているため、それら両方を読み込み重複チェックをしてから保存しておく。
<br clear=left>
<pre class=SourceCode>
	//■追加
	//レジストリに登録されているIEツールバーを見つけ
	//_acAvailableIEToolbarに格納する
	bool	EnumAvailableIEToolbar(void)
	{
		LONG		nRet;
		CRegKey		cRegistry;
		CAtlArray&lt;CAtlString&gt;	astrClsid;

		_acAvailableIEToolbar.RemoveAll();

		//最初にレジストリからIEツールバーかもしれないレジストリキーをすべて列挙して
		//astrClsidへ格納

		//ユーザー専用のIEツールバーかもしれないレジストリキーを列挙
		nRet = cRegistry.Open(HKEY_CURRENT_USER,_T(&quot;Software\\Microsoft\\Internet Explorer\\Toolbar\\WebBrowser&quot;));
		if(nRet == ERROR_SUCCESS)
		{
			RegEnumKeyName(cRegistry.m_hKey,astrClsid);
			cRegistry.Close();
		}

		//ユーザー共通のIEツールバーかもしれないレジストリキーを列挙
		nRet = cRegistry.Open(HKEY_LOCAL_MACHINE,_T(&quot;Software\\Microsoft\\Internet Explorer\\Toolbar&quot;));
		if(nRet == ERROR_SUCCESS)
		{
			bool	bFind;
			size_t	i;
			size_t	j;
			size_t	nSize;
			CAtlArray&lt;CAtlString&gt;	astrClsid2;

			RegEnumKeyName(cRegistry.m_hKey,astrClsid2);
			cRegistry.Close();

			//重複チェックして重複していないものだけastrClsid2からastrClsidへコピー
			nSize = astrClsid.GetCount();
			for(i = 0; i &lt; astrClsid2.GetCount(); i++)
			{
				bFind = false;
				for(j = 0; j &lt; nSize; j++)
				{
					if(astrClsid[j].CompareNoCase(astrClsid2[i]))
						continue;

					bFind = true;		//重複が見つかった
					break;
				}

				if(bFind)
					continue;

				//重複はなかった
				astrClsid.Add(astrClsid2[i]);
			}
		}


		//astrClsidに格納されているIEツールバーかもしれないレジストリキーが
		//IEツールバーかどうかをチェックして_acAvailableIEToolbarへ追加

		size_t	i;
		size_t	nSize;

		nSize = astrClsid.GetCount();
		for(i = 0; i &lt; nSize; i++)
		{
			HRESULT	hr;
			GUID	rclsid;
			CAtlStringW	ustrName;
			CAtlString	strName;

			CComPtr&lt;IDeskBand&gt;	pIDeskBand;

			//文字列からIIDへ変換
			ustrName = astrClsid[i];
			hr = ::CLSIDFromString(ustrName.GetBuffer(0),&amp;rclsid);
			if(FAILED(hr))
				continue;

			//ためしにCoCreateしてIDeskBandかをチェック
			hr = ::CoCreateInstance(rclsid,NULL,CLSCTX_INPROC_SERVER,IID_IDeskBand,(void**)&amp;pIDeskBand);
			if(pIDeskBand == NULL)
				continue;
			pIDeskBand = NULL;

			/////////////////////////
			//IEツールバーが見つかった

			CLSIDtoUIString(rclsid,strName);
			_acAvailableIEToolbar.Add(CAvailableIEToolbar(rclsid,strName));
		}

		return	true;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/12/tabbrowser244.gif" rel="lightbox"><img alt="tabbrowser244.gif" src="http://www.usefullcode.net/2009/04/12/tabbrowser244-thumb.gif" width="400" height="433" align="left" /></a>
GUIDなCLSIDだけでは不便なので、CLSIDから「Google Toolbar」や「MSN Toolbar」というような表示用文字列を取得する。今回はレジストリを参照し、CLSIDとPROGIDの2つのみをチェックするようにした。
<br clear=left>
<pre class=SourceCode>
	//■追加
	//CLSIDをUI用の文字列に変換する
	bool	CLSIDtoUIString(const IID&amp; rclsid,CAtlString&amp; strText)
	{
		HRESULT		hr;
		LONG		nRet;
		ULONG		nChars;
		TCHAR		pszName[2048];
		WCHAR*		pwszString;
		CRegKey		cReg2;
		CAtlString	strKey;

		strText = _T(&quot;&quot;);

		/////////////////////////////////////
		// HKEY_CLASSES_ROOT\\CLSID\\{xxxxxxxx}
		//からUI名の取得を試みる
		//

		pwszString = NULL;
		hr = ::StringFromCLSID(rclsid,&amp;pwszString);
		if(FAILED(hr))
			return	false;

		strKey = _T(&quot;CLSID\\&quot;) + (CAtlString)pwszString;
		::CoTaskMemFree(pwszString);

		nRet = cReg2.Open(HKEY_CLASSES_ROOT,strKey);
		if(nRet == ERROR_SUCCESS)
		{
			nChars = 2048;
			nRet = cReg2.QueryStringValue(NULL,pszName,&amp;nChars);
			cReg2.Close();
			if(nRet == ERROR_SUCCESS)
			{
				strText = pszName;
				if(strText != _T(&quot;&quot;))
					return	true;
			}
		}


		/////////////////////////////////////
		// HKEY_CLASSES_ROOT\\xxxx.xxxx.xxxx
		//（プログラムID）からUI名の取得を試みる
		//

		pwszString = NULL;
		hr = ::ProgIDFromCLSID(rclsid,&amp;pwszString);
		strKey = pwszString;
		::CoTaskMemFree(pwszString);

		nRet = cReg2.Open(HKEY_CLASSES_ROOT,strKey);
		if(nRet == ERROR_SUCCESS)
		{
			nChars = 2048;
			nRet = cReg2.QueryStringValue(NULL,pszName,&amp;nChars);
			cReg2.Close();
			if(nRet == ERROR_SUCCESS)
			{
				strText = pszName;
				if(strText != _T(&quot;&quot;))
					return	true;
			}
		}

		strText = strKey;

		return	false;
	}
</pre>
<br>


<a href="http://www.usefullcode.net/2009/04/12/tabbrowser247.gif" rel="lightbox"><img alt="tabbrowser247.gif" src="http://www.usefullcode.net/2009/04/12/tabbrowser247-thumb.gif" width="400" height="433" align="left" /></a>
最後にOnCreate内で利用可能なIE用ツールバーを探しだして、そのすべてを表示するようにした。
<br clear=left>
<pre class=SourceCode>
	LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL&amp; /*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列で表示

		//■変更
		{
			size_t	i;
			size_t	nSize;

			EnumAvailableIEToolbar();

			nSize = _acAvailableIEToolbar.GetCount();
			for(i = 0; i &lt; nSize; i++)
			{
				AddIEToolbar(_acAvailableIEToolbar[i].clsidToolbar);
			}
		}


		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-&gt;AddMessageFilter(this);
		pLoop-&gt;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;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/12/tabbrowser248.gif" rel="lightbox"><img alt="tabbrowser248.gif" src="http://www.usefullcode.net/2009/04/12/tabbrowser248-thumb.gif" width="400" height="333" align="left" /></a>
これで実行すると、インストールされているIE用ツールバーの分だけリバーが作られ、複数のIE用ツールバーが表示されるようになった。

一番上の「DinopSearchBar」は内部処理がIEに直接アクセスする形で実装されているためきちんと表示されず、2つ目の「Adobe PDF」はリバーサイズがきちんと設定されず、4番目の「Gooスティック」はウインドウサイズ変更時の再描画処理がきちんとされていないなど、まだきちんと動かない部分も多いが、とりあえずはいろいろなIE用のツールバーが利用可能になった。

次回はメニューからIE用ツールバーを選択して表示できるようにする。
<br clear=left>

<a href="http://www.usefullcode.net/2009/04/12/20090412_TabBrowser100_55.zip">プロジェクトファイルをダウンロード</a>
]]></description>
         <link>http://www.usefullcode.net/2009/04/55_tabbrowser.html</link>
         <guid>http://www.usefullcode.net/2009/04/55_tabbrowser.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">タブブラウザーを作る</category>
        
        
         <pubDate>Sun, 12 Apr 2009 17:25:12 +0900</pubDate>
      </item>
            <item>
         <title>第54回  「Googleツールバー」を2つ表示する　（タブブラウザーを作る）</title>
         <description><![CDATA[<a href="http://www.usefullcode.net/2009/04/12/tabbrowser237.gif" rel="lightbox"><img alt="tabbrowser237.gif" src="http://www.usefullcode.net/2009/04/12/tabbrowser237-thumb.gif" width="400" height="561" align="left" /></a>
<a href="http://www.usefullcode.net/2009/04/53_tabbrowser.html" target=_blank>前回</a>はビューウインドウを中心にIEツールバーを複数利用する準備をした。今回はCMainFrame側を中心に修正を行う。

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

またこれまでリバーのインデックス渡しにバグがあったので、きちんとIDからインデックスを取得して渡すように修正した。
<br clear=left>
<pre class=SourceCode>
	//■処理内容変更
	class	CDummyWnd	: public CWindowImpl&lt;CDummyWnd&gt;
	{
		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&amp; bHandled)
		{
			UINT*	pnIndex = (UINT*)wParam;

			if(pnIndex)
				*pnIndex = GetRebarIndex();

			return	0;
		}

		LRESULT OnDnpGetClsid(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; 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&amp; 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;
		}
	};
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/12/tabbrowser238.gif" rel="lightbox"><img alt="tabbrowser238.gif" src="http://www.usefullcode.net/2009/04/12/tabbrowser238-thumb.gif" width="400" height="612" align="left" /></a>
そしてCDummyWndをCAtlArrayにより配列化、簡単にCDummyWndを作れるようにAddIEToolbar関数を用意した。
<br clear=left>
<pre class=SourceCode>
	CAtlArray&lt;CDummyWnd*&gt;	_apwndDummy;		//■変更


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

		pwndDummy = new CDummyWnd(clsidIDeskBand);

		//ダミーウインドウを生成し、リバーに割り当てる。これはIEツールバーに利用
		pwndDummy-&gt;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-&gt;_nBandID = nCount + ATL_IDW_BAND_FIRST - 1;

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

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

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

		_apwndDummy.Add(pwndDummy);

		return	true;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/12/tabbrowser234.gif" rel="lightbox"><img alt="tabbrowser234.gif" src="http://www.usefullcode.net/2009/04/12/tabbrowser234-thumb.gif" width="400" height="386" align="left" /></a>
CDummyWndの配列はnewによる確保にしたので、デストラクタでdeleteしておく。
<br clear=left>
<pre class=SourceCode>
	//■追加
	~CMainFrame()
	{
		size_t	i;
		size_t	nSize;

		nSize = _apwndDummy.GetCount();
		for(i = 0; i &lt; nSize; i++)
		{
			if(_apwndDummy[i] == NULL)
				continue;
			delete	_apwndDummy[i];
			_apwndDummy[i] = NULL;
		}
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/12/tabbrowser235.gif" rel="lightbox"><img alt="tabbrowser235.gif" src="http://www.usefullcode.net/2009/04/12/tabbrowser235-thumb.gif" width="400" height="386" align="left" /></a>
後はこれまで_wndDummyにアクセスしていた部分を配列に沿ったものに修正する。
まずはリバーの表示／非表示を切り替える処理だ。
<br clear=left>
<pre class=SourceCode>
	//タブが選択されたときの処理
	LRESULT OnTabPageActivated(int idCtrl, LPNMHDR pnmh, BOOL&amp; bHandled)
	{
		if(pnmh == NULL)
			return	0;

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

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

				if(pnmh-&gt;idFrom == i)
					pView-&gt;OnTabPageChange(true);
				else
				{
					pView-&gt;OnTabPageChange(false);
					pView-&gt;SetStatusBar(m_hWndStatusBar,false);	//ステータスバー解放
				}
			}

			pView = GetActivePageView();
			if(pView)
				pView-&gt;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 &lt; nSize; i++)
		{
			if(_apwndDummy[i])
				_apwndDummy[i]-&gt;ShowRebar(bVisible);				//リバー表示
		}

		if(pView == NULL)
			return	0;

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

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

		return	0;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/12/tabbrowser236.gif" rel="lightbox"><img alt="tabbrowser236.gif" src="http://www.usefullcode.net/2009/04/12/tabbrowser236-thumb.gif" width="400" height="386" align="left" /></a>
タブの新規作成処理。今のところ新しいタブは必ずアクティブに開くので、生成時はAddIEToolbarにtrueを渡している。
<br clear=left>
<pre class=SourceCode>
	//タブの新規作成
	//nPosはタブを追加する場所。nPos&lt;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(&amp;m_view);	//タブビューのポインタを渡す
		if(pView == NULL)
			return	NULL;

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

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

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

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

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

		return	pView;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/12/tabbrowser239.gif" rel="lightbox"><img alt="tabbrowser239.gif" src="http://www.usefullcode.net/2009/04/12/tabbrowser239-thumb.gif" width="400" height="401" align="left" /></a>
OnCreateで「Googleツールバー」のGUIDを利用してリバーを作る。今回はAddIEToolbarを2度呼ぶことで2つの「Googleツールバー」を表示することにした。
<br clear=left>
<pre class=SourceCode>
	LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL&amp; /*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&quot;{2318C2B1-4965-11d4-9B18-009027A5CD4F}&quot;};		//GoogleツールバーのGUID

			::CLSIDFromString(pszGUID,&amp;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-&gt;AddMessageFilter(this);
		pLoop-&gt;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;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/12/tabbrowser240.gif" rel="lightbox"><img alt="tabbrowser240.gif" src="http://www.usefullcode.net/2009/04/12/tabbrowser240-thumb.gif" width="400" height="390" align="left" /></a>
実際のIEツールバー生成処理を担っているビューウインドウ側のCIEToolbarInfoの中で、新しい独自メッセージによりGUIDを取得して利用するようにする。
<br clear=left>
<pre class=SourceCode>
		//■変更
		//IEツールバーを生成する
		bool	Create(IWebBrowser2* pIWebBrowser2,bool bVisible)
		{
			IID		rclsid = GUID_NULL;

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

			return	CreateIEToolbar(pIWebBrowser2,_hWndRebarIE,&amp;_pIDeskBand,rclsid,bVisible);
		}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/12/tabbrowser241.gif" rel="lightbox"><img alt="tabbrowser241.gif" src="http://www.usefullcode.net/2009/04/12/tabbrowser241-thumb.gif" width="400" height="390" align="left" /></a>
ビューウインドウ側のAddIEToolbarで引数にbVisibleを用意した。
<br clear=left>
<pre class=SourceCode>
	//■変更
	bool	AddIEToolbar(HWND hWndIERebar,bool bVisible)
	{
		size_t	nIndex;

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

		return	true;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/12/tabbrowser242.gif" rel="lightbox"><img alt="tabbrowser242.gif" src="http://www.usefullcode.net/2009/04/12/tabbrowser242-thumb.gif" width="400" height="390" align="left" /></a>
最後に「stdafx.h」内に独自メッセージの定義を追加する。
<br clear=left>
<pre class=SourceCode>
#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)		//■追加
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/12/tabbrowser243.gif" rel="lightbox"><img alt="tabbrowser243.gif" src="http://www.usefullcode.net/2009/04/12/tabbrowser243-thumb.gif" width="400" height="369" align="left" /></a>
これでビルド／実行すると「Googleツールバー」が2つ表示されるようになった。

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

<a href="http://www.usefullcode.net/2009/04/12/20090412_TabBrowser100_54.zip">プロジェクトファイルをダウンロード</a>
]]></description>
         <link>http://www.usefullcode.net/2009/04/54_tabbrowser.html</link>
         <guid>http://www.usefullcode.net/2009/04/54_tabbrowser.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">タブブラウザーを作る</category>
        
        
         <pubDate>Sun, 12 Apr 2009 13:17:21 +0900</pubDate>
      </item>
            <item>
         <title>第53回  IE用ツールバーを複数利用するための準備をする　（タブブラウザーを作る）</title>
         <description><![CDATA[<a href="http://www.usefullcode.net/2009/04/12/tabbrowser228.gif" rel="lightbox"><img alt="tabbrowser228.gif" src="http://www.usefullcode.net/2009/04/12/tabbrowser228-thumb.gif" width="400" height="574" align="left" /></a>
これまでInternet Explorer用のツールバーとして「Googleツールバー」のみを固定表示していた。これをこれから数回のステップでInternet Explorerのようにインストールされているツールバーを自由に選択／利用できるできるようにする。

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

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


	CAtlString	_strLastStatusText;					//最後に送られてきたステータステキストを保管
	CComPtr&lt;IDocHostUIHandler&gt;	_pHideScriptError;
	CIELikeStatusbar			_wndStatusbar;		//ステータスバー
//	CComPtr&lt;IDeskBand&gt;			_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&quot;{2318C2B1-4965-11d4-9B18-009027A5CD4F}&quot;};		//GoogleツールバーのGUID

			::CLSIDFromString(pszGUID,&amp;rclsid);

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

	protected:

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

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

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

			CComPtr&lt;IObjectWithSite&gt;	pIObjectWithSite;

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

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

				pIIEToolbar = new CComObject&lt;CIEToolbar&gt;;

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

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

			DESKBANDINFO	sDeskBandInfo;

			//別に必要ないが情報をたくさん取得
			::ZeroMemory(&amp;sDeskBandInfo,sizeof(DESKBANDINFO));
			sDeskBandInfo.dwMask = DBIM_MINSIZE | DBIM_MAXSIZE | DBIM_INTEGRAL | DBIM_ACTUAL | DBIM_TITLE | DBIM_MODEFLAGS | DBIM_BKCOLOR;
			hr = (*ppIDeskBand)-&gt;GetBandInfo(0,DBIF_VIEWMODE_NORMAL,&amp;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)&amp;nIndex,NULL);
				if(nIndex != -1 &amp;&amp; hWndRebar)
				{
					REBARBANDINFO	info;

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

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

			return	true;
		}
	};
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/12/tabbrowser229.gif" rel="lightbox"><img alt="tabbrowser229.gif" src="http://www.usefullcode.net/2009/04/12/tabbrowser229-thumb.gif" width="400" height="345" align="left" /></a>
今回はツールバー情報をCAtlArrayとして実装することにした。
<br clear=left>
<pre class=SourceCode>
	CAtlArray&lt;CIEToolbarInfo&gt;	_aToolbarInfo;		//■追加


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


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

<a href="http://www.usefullcode.net/2009/04/12/tabbrowser230.gif" rel="lightbox"><img alt="tabbrowser230.gif" src="http://www.usefullcode.net/2009/04/12/tabbrowser230-thumb.gif" width="400" height="574" align="left" /></a>
CAtlArrayにより単純にCIEToolbarInfoを配列化しているのでCIEToolbarInfoではCComPtrを使わずにIDeskBand*を利用した。そのためビューウインドウが破棄されるときにReleaseしておく。

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

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

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

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

				_aToolbarInfo[i]._pIDeskBand-&gt;ShowDW(FALSE);	//非表示
				_aToolbarInfo[i]._pIDeskBand-&gt;CloseDW(0);		//終了
				_aToolbarInfo[i]._pIDeskBand-&gt;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 &lt; nSize; i++)
		{
			if(_aToolbarInfo[i]._pIDeskBand == NULL)
				continue;

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

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

		return	true;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/12/tabbrowser231.gif" rel="lightbox"><img alt="tabbrowser231.gif" src="http://www.usefullcode.net/2009/04/12/tabbrowser231-thumb.gif" width="400" height="353" align="left" /></a>
さらにビューウインドウのCreate内でのGoogleツールバー生成処理を削除し、外部からIE用ツールバーを作成するための関数を追加する。
<br clear=left>
<pre class=SourceCode>
	//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(&amp;_pIWebBrowser2);		//_pIWebBrowser2にこのビューに関連づいているIEをセットする
		if(_pIWebBrowser2 == NULL)
			return	hWnd;			//WebBrowser取得失敗

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


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

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

			//IEコントロールへのセット
			_pIWebBrowser2-&gt;QueryInterface(&amp;pIOleObject);
			if(pIOleObject &amp;&amp; pCAmbientControl)
				pIOleObject-&gt;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;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/12/tabbrowser232.gif" rel="lightbox"><img alt="tabbrowser232.gif" src="http://www.usefullcode.net/2009/04/12/tabbrowser232-thumb.gif" width="400" height="420" align="left" /></a>
最後にCMainFrame側でビューを生成するときの処理を変えれば終わりだ。
<br clear=left>
<pre class=SourceCode>
	//タブの新規作成
	//nPosはタブを追加する場所。nPos&lt;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(&amp;m_view);	//■変更 タブビューのポインタを渡す
		if(pView == NULL)
			return	NULL;

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

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

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

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

		return	pView;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/12/tabbrowser233.gif" rel="lightbox"><img alt="tabbrowser233.gif" src="http://www.usefullcode.net/2009/04/12/tabbrowser233-thumb.gif" width="400" height="369" align="left" /></a>
これで実行したときの見た目は変わらないが、少しずつ対応できてきた。次回も引き続きIE用ツールバーを複数利用するための実装を準備する。
<br clear=left>

<a href="http://www.usefullcode.net/2009/04/12/20090412_TabBrowser100_53.zip">プロジェクトファイルをダウンロード</a>
]]></description>
         <link>http://www.usefullcode.net/2009/04/53_tabbrowser.html</link>
         <guid>http://www.usefullcode.net/2009/04/53_tabbrowser.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">タブブラウザーを作る</category>
        
        
         <pubDate>Sun, 12 Apr 2009 10:03:55 +0900</pubDate>
      </item>
            <item>
         <title>第52回  Googleツールバーの表示サイズを自動調整する　（タブブラウザーを作る）</title>
         <description><![CDATA[<a href="http://www.usefullcode.net/2009/04/11/tabbrowser224.gif" rel="lightbox"><img alt="tabbrowser224.gif" src="http://www.usefullcode.net/2009/04/11/tabbrowser224-thumb.gif" width="400" height="571" align="left" /></a>
<a href="http://www.usefullcode.net/2009/04/51_tabbrowser.html" target=_blank>前回</a>はタブがあるときだけ「Googleツールバー」用のリバーが表示されるようにした。今回はリバーの大きさが「Googleツールバー」に合わせて変わるようにする。


「Googleツールバー」の生成はCMainFrame::OnCreate内で行っていた。それを関数に切り出して呼び出すようにした。生成処理内では<a href="http://www.usefullcode.net/2009/04/51_tabbrowser.html" target=_blank>前回</a>実装したリバーのIDを取得する処理を使ってDESKBANDINFOの情報をリバーにセットする。
<br clear=left>
<pre class=SourceCode>
	//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(&amp;_pIWebBrowser2);		//_pIWebBrowser2にこのビューに関連づいているIEをセットする
		if(_pIWebBrowser2 == NULL)
			return	hWnd;			//WebBrowser取得失敗

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


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

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

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

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

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

			::CLSIDFromString(pszGUID,&amp;rclsid);

			CreateIEToolbar(_hWndRebarIE,&amp;_pIDeskBand,rclsid);
		}

		return	hWnd;
	}




	//■追加
	//hWndParentはCDummyWnd（Googleツールバーの親となるウインドウハンドル）
	//clsidIDeskBandはGoogleツールバーのCLSIDを指定する
	bool	CreateIEToolbar(HWND hWndParent,IDeskBand** ppIDeskBand,const IID&amp; clsidIDeskBand)
	{
		HRESULT	hr;

		if(ppIDeskBand == NULL)
			return	false;
		if(*ppIDeskBand)
		{
			ATLASSERT(0);
			(*ppIDeskBand)-&gt;Release();
			*ppIDeskBand = NULL;
		}

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

		CComPtr&lt;IObjectWithSite&gt;	pIObjectWithSite;

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

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

			pIIEToolbar = new CComObject&lt;CIEToolbar&gt;;

			pIIEToolbar-&gt;put_hwnd(hWndParent);
			if(_pIWebBrowser2)
				pIIEToolbar-&gt;put_IWebBrowser2(_pIWebBrowser2);
			if(pIObjectWithSite)
				hr = pIObjectWithSite-&gt;SetSite(pIIEToolbar);

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

		DESKBANDINFO	sDeskBandInfo;

		//別に必要ないが情報をたくさん取得
		::ZeroMemory(&amp;sDeskBandInfo,sizeof(DESKBANDINFO));
		sDeskBandInfo.dwMask = DBIM_MINSIZE | DBIM_MAXSIZE | DBIM_INTEGRAL | DBIM_ACTUAL | DBIM_TITLE | DBIM_MODEFLAGS | DBIM_BKCOLOR;
		hr = (*ppIDeskBand)-&gt;GetBandInfo(0,DBIF_VIEWMODE_NORMAL,&amp;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)&amp;nIndex,NULL);
			if(nIndex != -1 &amp;&amp; hWndRebar)
			{
				REBARBANDINFO	info;

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

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

		return	true;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/11/tabbrowser225.gif" rel="lightbox"><img alt="tabbrowser225.gif" src="http://www.usefullcode.net/2009/04/11/tabbrowser225-thumb.gif" width="400" height="338" align="left" /></a>
次に「Googleツールバー」で（トップレベルHTMLとして作られている？）ドロップダウンメニューを開くとビューウインドウにきちんとフォーカスが当たらない問題を修正する。CIEUtilityのSetFocusChange内を変更する。今まではUIDeactivateを呼ぶのみだったが、InPlaceDeactivateも呼ぶようにした。
<br clear=left>
<pre class=SourceCode>
	//■処理内容追加
	//IEコントロールがフォーカスを受け取ったときbGetFocus=true、
	//IEコントロールがフォーカスを失ったときbGetFocus=falseとして呼び出す
	bool	SetFocusChange(bool bGetFocus)
	{
		if(_pIWebBrowser2 == NULL)
			return	false;

		HRESULT	hr = E_FAIL;
		CComPtr&lt;IOleInPlaceObject&gt; pIOleInPlaceObject;

		if(_pIWebBrowser2)
			_pIWebBrowser2-&gt;QueryInterface(&amp;pIOleInPlaceObject);
		if(pIOleInPlaceObject == NULL)
			return	S_OK;

		if(bGetFocus)
		{
			hr = pIOleInPlaceObject-&gt;UIDeactivate();
			pIOleInPlaceObject-&gt;InPlaceDeactivate();
		}
		else
		{
			HWND hWnd;

			hr = pIOleInPlaceObject-&gt;GetWindow(&amp;hWnd);
			if(SUCCEEDED(hr) &amp;&amp; ::IsWindow(hWnd))
				::ShowWindow(hWnd,SW_NORMAL);
		}

		return	true;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/11/tabbrowser226.gif" rel="lightbox"><img alt="tabbrowser226.gif" src="http://www.usefullcode.net/2009/04/11/tabbrowser226-thumb.gif" width="400" height="338" align="left" /></a>
同様にCIEToolbar内も変更しておく。
<br clear=left>
<pre class=SourceCode>
	//■処理内容追加
	//IInputObjectSite
	STDMETHOD(OnFocusChangeIS)(IUnknown *punkObj,BOOL fSetFocus)
	{
		HRESULT	hr = E_FAIL;
		CComPtr&lt;IOleInPlaceObject&gt; pIOleInPlaceObject;

		if(_pIDispatch)
			_pIDispatch-&gt;QueryInterface(&amp;pIOleInPlaceObject);
		if(pIOleInPlaceObject == NULL)
			return	S_OK;

		if(fSetFocus)
		{
			hr = pIOleInPlaceObject-&gt;UIDeactivate();
			pIOleInPlaceObject-&gt;InPlaceDeactivate();
		}
		else
		{
			HWND hWnd;
			hr = pIOleInPlaceObject-&gt;GetWindow(&amp;hWnd);
			if(SUCCEEDED(hr) &amp;&amp; ::IsWindow(hWnd))
				::ShowWindow(hWnd,SW_NORMAL);
		}

		return	S_OK;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/11/tabbrowser227.gif" rel="lightbox"><img alt="tabbrowser227.gif" src="http://www.usefullcode.net/2009/04/11/tabbrowser227-thumb.gif" width="400" height="369" align="left" /></a>
これでビルド／実行すると、これまで下端が切れて表示されていた「Googleツールバー」がきちんと表示されるようになった。

次回複数のInternet Explorer用ツールバーが表示できるようにするための準備をする。
<br clear=left>

<a href="http://www.usefullcode.net/2009/04/11/20090411_TabBrowser100_52.zip">プロジェクトファイルをダウンロード</a>
]]></description>
         <link>http://www.usefullcode.net/2009/04/52_tabbrowser.html</link>
         <guid>http://www.usefullcode.net/2009/04/52_tabbrowser.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">タブブラウザーを作る</category>
        
        
         <pubDate>Sat, 11 Apr 2009 18:11:57 +0900</pubDate>
      </item>
            <item>
         <title>第51回  タブがないときにGoogleツールバーが表示されないようにする　（タブブラウザーを作る）</title>
         <description><![CDATA[<a href="http://www.usefullcode.net/2009/04/11/tabbrowser219.gif" rel="lightbox"><img alt="tabbrowser219.gif" src="http://www.usefullcode.net/2009/04/11/tabbrowser219-thumb.gif" width="400" height="571" align="left" /></a>
これまで起動直後などタブが1つもないときには「Googleツールバー」を表示するための領域（リバー）が空白のまま表示されていた。今回はタブがない場合にはリバーが表示されないようにする。

まずGoogleツールバーの親ウインドウとして利用しているCDummyWndの処理内容を追加する。リバーの表示／非表示を切り替える関数やリバーサイズが変わったときにGoogleツールバーのウインドウサイズを変更する処理を追加した。
<br clear=left>
<pre class=SourceCode>
	//■処理内容実装
	class	CDummyWnd	: public CWindowImpl&lt;CDummyWnd&gt;
	{
	public:
		UINT	_nBandIndex;		//rebar上のインデックス

		CDummyWnd()
		{
			_nBandIndex = -1;
		}

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

		LRESULT OnDnpRbIndex(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; bHandled)
		{
			UINT*	pnIndex = (UINT*)wParam;

			if(pnIndex)
				*pnIndex = _nBandIndex;

			return	0;
		}


		LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; bHandled)
		{
			bHandled = FALSE;
			if(_nBandIndex == -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(_nBandIndex == -1 || IsWindow() == FALSE)
				return	false;

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

			return	true;
		}
	};
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/11/tabbrowser220.gif" rel="lightbox"><img alt="tabbrowser220.gif" src="http://www.usefullcode.net/2009/04/11/tabbrowser220-thumb.gif" width="400" height="462" align="left" /></a>
そしてOnCreate内でGoogleツールバー用のリバー生成後、そのIDをCDummyWndに渡しておく。
<br clear=left>
<pre class=SourceCode>
	LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL&amp; /*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列で表示

		//ダミーウインドウを生成し、リバーに割り当てる。これはIEツールバーに利用
		//ここで生成してしまうと何もないリバーができてしまうが気にしない
		_wndDummy.Create(m_hWnd,CRect(0,0,500,24),0,WS_CHILD);
		AddSimpleReBarBand(_wndDummy,0,TRUE);						//1行表示

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

			nCount = (UINT)::SendMessage(m_hWndToolBar,RB_GETBANDCOUNT,NULL,NULL);
			_wndDummy._nBandIndex = nCount - 1;
			_wndDummy.ShowRebar(false);			//非表示にする
		}


		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-&gt;AddMessageFilter(this);
		pLoop-&gt;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;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/11/tabbrowser221.gif" rel="lightbox"><img alt="tabbrowser221.gif" src="http://www.usefullcode.net/2009/04/11/tabbrowser221-thumb.gif" width="400" height="462" align="left" /></a>
OnTabPageActivatedの部分でツールバーの表示／非表示が切り替わるようにする。
<br clear=left>
<pre class=SourceCode>
	//タブが選択されたときの処理
	LRESULT OnTabPageActivated(int idCtrl, LPNMHDR pnmh, BOOL&amp; bHandled)
	{
		if(pnmh == NULL)
			return	0;

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

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

				if(pnmh-&gt;idFrom == i)
					pView-&gt;OnTabPageChange(true);
				else
				{
					pView-&gt;OnTabPageChange(false);
					pView-&gt;SetStatusBar(m_hWndStatusBar,false);	//ステータスバー解放
				}
			}

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


		bool		ret;
		CTabBrowser100View*	pView;

		pView = GetActivePageView();		//アクティブビュー取得
		if(pView == NULL)
		{
			_wndDummy.ShowRebar(false);			//■追加 リバー消去
			return	0;
		}

		_wndDummy.ShowRebar(true);			//■追加 リバー表示

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

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

		return	0;
	}
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/11/tabbrowser222.gif" rel="lightbox"><img alt="tabbrowser222.gif" src="http://www.usefullcode.net/2009/04/11/tabbrowser222-thumb.gif" width="400" height="363" align="left" /></a>
今回はCDummyWndに独自メッセージを送ることでリバーのIDが取得できるようにした。そのためのメッセージを「stdafx.h」に定義しておく。
<br clear=left>
<pre class=SourceCode>
#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)		//■追加
</pre>
<br>

<a href="http://www.usefullcode.net/2009/04/11/tabbrowser223.gif" rel="lightbox"><img alt="tabbrowser223.gif" src="http://www.usefullcode.net/2009/04/11/tabbrowser223-thumb.gif" width="400" height="340" align="left" /></a>
これでタブがないときには「Googleツールバー」用のリバーが表示されなくなった。

次回はGoogleツールバーの下端が切れる問題とページ上でキー入力ができなくなるバグを修正する。
<br clear=left>

<a href="http://www.usefullcode.net/2009/04/11/20090411_TabBrowser100_51.zip">プロジェクトファイルをダウンロード</a>
]]></description>
         <link>http://www.usefullcode.net/2009/04/51_tabbrowser.html</link>
         <guid>http://www.usefullcode.net/2009/04/51_tabbrowser.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">タブブラウザーを作る</category>
        
        
         <pubDate>Sat, 11 Apr 2009 10:37:18 +0900</pubDate>
      </item>
      
   </channel>
</rss>
