前の10件 5  6  7  8  9  10  11  12  13  14  15

記事一覧

第26回 「編集」メニューから「コピー」などできるようにする (タブブラウザーを作る)

tabbrowser103.gif
前回は「印刷」「印刷プレビュー」などの機能が使えるようにした。

今回は前回とまったく同じ方法で「コピー」や「切り取り」などのクリップボード関連操作をメニューからできるようにする。

CIEUtilityにCopy()などを実装する。今回は利用しないがSelectAll()も用意した。
	//■追加
	bool	Copy(void)
	{
		if(_pIWebBrowser2 == NULL)
			return	false;
		return	SUCCEEDED(_pIWebBrowser2->ExecWB(OLECMDID_COPY,OLECMDEXECOPT_PROMPTUSER,NULL,NULL)) ? true : false;
	}

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

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

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

tabbrowser104.gif そして「MainFrm.h」の中でメニューが選択されたときに上で作成した関数が呼ばれるようにする。
	BEGIN_MSG_MAP(CMainFrame)
		MESSAGE_HANDLER(WM_DNP_CREATENEWTAB, OnDnpCreateNewTab)
		MESSAGE_HANDLER(WM_DNP_CHANGEFOCUS, OnDnpChangeFocus)
		MESSAGE_HANDLER(WM_DNP_CHANGEADDRESS, OnDnpChangeAddress)
		MESSAGE_HANDLER(WM_DNP_CHANGESTATUSTEXT, OnDnpChangeStatusText)
		MESSAGE_HANDLER(WM_DNP_CHANGEPROGRESS, OnDnpChangeProgress)
		NOTIFY_CODE_HANDLER(CBEN_ENDEDIT, OnAddressbarEnter)
		MESSAGE_HANDLER(WM_CREATE, OnCreate)
		MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
		COMMAND_ID_HANDLER(ID_APP_EXIT, OnFileExit)
		COMMAND_ID_HANDLER(ID_FILE_NEW, OnFileNew)
		COMMAND_ID_HANDLER(ID_VIEW_TOOLBAR, OnViewToolBar)
		COMMAND_ID_HANDLER(ID_VIEW_STATUS_BAR, OnViewStatusBar)
		COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)
		COMMAND_ID_HANDLER(ID_WINDOW_CLOSE, OnWindowClose)
		COMMAND_ID_HANDLER(ID_WINDOW_CLOSE_ALL, OnWindowCloseAll)
		COMMAND_ID_HANDLER(ID_FILE_PRINT, OnFileCommand)
		COMMAND_ID_HANDLER(ID_FILE_PRINT_PREVIEW, OnFileCommand)
		COMMAND_ID_HANDLER(ID_FILE_PRINT_SETUP, OnFileCommand)
		COMMAND_ID_HANDLER(ID_EDIT_COPY, OnFileCommand)				//■追加
		COMMAND_ID_HANDLER(ID_EDIT_CUT, OnFileCommand)				//■追加
		COMMAND_ID_HANDLER(ID_EDIT_PASTE, OnFileCommand)			//■追加
		COMMAND_ID_HANDLER(ID_EDIT_SELECT_ALL, OnFileCommand)		//■追加
		COMMAND_RANGE_HANDLER(ID_WINDOW_TABFIRST, ID_WINDOW_TABLAST, OnWindowActivate)
		COMMAND_ID_HANDLER(ID_IE_BACK, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_NEXT, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_STOP, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_REFRESH, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_ADDFAVORITE, OnIEAddFavorite)
		COMMAND_ID_HANDLER(ID_IE_ORGANIZE_FAVORITE, OnIEOrganizeFavorite)
		NOTIFY_CODE_HANDLER(TBVN_CONTEXTMENU, OnTabContextMenu)
		NOTIFY_CODE_HANDLER(TBVN_PAGEACTIVATED, OnTabPageActivated)
		MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)
		MESSAGE_HANDLER(WM_SIZE, OnSize)
		COMMAND_RANGE_HANDLER(ID_FAVORITE_FIRST,ID_FAVORITE_LAST,OnFavorite)
		CHAIN_MSG_MAP_MEMBER(_cFovMenu)
		CHAIN_MSG_MAP(CUpdateUI<CMainFrame>)
		CHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>)
	END_MSG_MAP()

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

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

		bHandled = TRUE;
		switch(wID)
		{
		case	ID_EDIT_COPY:				//■追加 コピー
			pView->Copy();
			break;

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

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

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

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

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

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

		default:
			bHandled = FALSE;
			break;
		}

		return	0;
	}

tabbrowser105.gif
これでビルド/実行すると「編集」メニューから「コピー」などの操作ができるようになった。

本来であればIEコントロール上で選択されている部分がないばあいは「コピー」メニューを無効にするべきだ。しかし今回の実装では常にメニューが有効になっている。

次回はIEコントロールの状態に合わせてメニューの有効/無効が自動で変わるようにする。

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

第25回 印刷関連機能が使えるようにする (タブブラウザーを作る)

tabbrowser100.gif
前回はツールバーとして「Googleツールバー」を利用するというかなりヘビーな実装をした。今回は軽く印刷関連機能の実装を行う。

IEコントロールはIWebBrowser2::ExecWB (IOleCommandTarget::Exec)により各種操作ができるように作られている。ここにOLECMDID_PRINTなどを与えることで印刷機能を利用する。

実際にIWebBrowser2を操作する処理をCIEUtilityに追加する。

ちなみに私はIOleCommandTarget関連は後から機能を拡張できる利点がある反面、外側から何が実装されているのかが分かりにくくCOMインターフェースの嫌な部分だと思う。なんとかならないのかな。。。
	//■追加
	//bPrintOrPreview=trueなら印刷、falseなら印刷プレビュー
	bool	PrintOrPreview(bool bPrintOrPreview)
	{
		HRESULT	hr;

		if(_pIWebBrowser2 == NULL)
			return	false;

		if(bPrintOrPreview)
			hr = _pIWebBrowser2->ExecWB(OLECMDID_PRINT,OLECMDEXECOPT_PROMPTUSER,NULL,NULL);
		else
			hr = _pIWebBrowser2->ExecWB(OLECMDID_PRINTPREVIEW,OLECMDEXECOPT_PROMPTUSER,NULL,NULL);

		return	SUCCEEDED(hr) ? true : false;
	}

	//■追加
	bool	PrintSetup(void)
	{
		HRESULT	hr = E_FAIL;

		if(_pIWebBrowser2)
			hr = _pIWebBrowser2->ExecWB(OLECMDID_PAGESETUP,OLECMDEXECOPT_PROMPTUSER,NULL,NULL);

		return	SUCCEEDED(hr) ? true : false;
	}

tabbrowser101.gif そして「MainFrm.h」側でメニュー操作により飛んで来た印刷関連メッセージを処理するメッセージハンドラを追加する。
	BEGIN_MSG_MAP(CMainFrame)
		MESSAGE_HANDLER(WM_DNP_CREATENEWTAB, OnDnpCreateNewTab)
		MESSAGE_HANDLER(WM_DNP_CHANGEFOCUS, OnDnpChangeFocus)
		MESSAGE_HANDLER(WM_DNP_CHANGEADDRESS, OnDnpChangeAddress)
		MESSAGE_HANDLER(WM_DNP_CHANGESTATUSTEXT, OnDnpChangeStatusText)
		MESSAGE_HANDLER(WM_DNP_CHANGEPROGRESS, OnDnpChangeProgress)
		NOTIFY_CODE_HANDLER(CBEN_ENDEDIT, OnAddressbarEnter)
		MESSAGE_HANDLER(WM_CREATE, OnCreate)
		MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
		COMMAND_ID_HANDLER(ID_APP_EXIT, OnFileExit)
		COMMAND_ID_HANDLER(ID_FILE_NEW, OnFileNew)
		COMMAND_ID_HANDLER(ID_VIEW_TOOLBAR, OnViewToolBar)
		COMMAND_ID_HANDLER(ID_VIEW_STATUS_BAR, OnViewStatusBar)
		COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)
		COMMAND_ID_HANDLER(ID_WINDOW_CLOSE, OnWindowClose)
		COMMAND_ID_HANDLER(ID_WINDOW_CLOSE_ALL, OnWindowCloseAll)
		COMMAND_ID_HANDLER(ID_FILE_PRINT, OnFileCommand)					//■追加
		COMMAND_ID_HANDLER(ID_FILE_PRINT_PREVIEW, OnFileCommand)			//■追加
		COMMAND_ID_HANDLER(ID_FILE_PRINT_SETUP, OnFileCommand)				//■追加
		COMMAND_RANGE_HANDLER(ID_WINDOW_TABFIRST, ID_WINDOW_TABLAST, OnWindowActivate)
		COMMAND_ID_HANDLER(ID_IE_BACK, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_NEXT, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_STOP, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_REFRESH, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_ADDFAVORITE, OnIEAddFavorite)
		COMMAND_ID_HANDLER(ID_IE_ORGANIZE_FAVORITE, OnIEOrganizeFavorite)
		NOTIFY_CODE_HANDLER(TBVN_CONTEXTMENU, OnTabContextMenu)
		NOTIFY_CODE_HANDLER(TBVN_PAGEACTIVATED, OnTabPageActivated)
		MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)
		MESSAGE_HANDLER(WM_SIZE, OnSize)
		COMMAND_RANGE_HANDLER(ID_FAVORITE_FIRST,ID_FAVORITE_LAST,OnFavorite)
		CHAIN_MSG_MAP_MEMBER(_cFovMenu)
		CHAIN_MSG_MAP(CUpdateUI<CMainFrame>)
		CHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>)
	END_MSG_MAP()

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

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

		bHandled = TRUE;
		switch(wID)
		{
		case	ID_FILE_PRINT:				//印刷
			pView->PrintOrPreview(true);
			break;

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

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

		default:
			bHandled = FALSE;
			break;
		}

		return	0;
	}

tabbrowser102.gif
これで「印刷」「印刷プレビュー」「プリンタの設定」の各項目が利用できるようになった。

次回は「切り取り」「コピー」「貼り付け」というクリップボード関連機能を実装する。

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

第24回 「Googleツールバー」をホストし検索バーとして利用する (タブブラウザーを作る)

tabbrowser92.gif
これまでの作業でタブブラウザーとしてまだ「お気に入り」機能を中心に致命的な機能不足があるものの、普段使いにも耐えれるレベルになってきた。しかし最近のブラウザーに必ず付いている検索バーがないため、検索しづらいという使いにくさもあった。

ゼロから検索バーを実装するのが正攻法だが、せっかくなので今回は「Googleツールバー」を利用できるようにする。当然のことながらパソコンに「Googleツールバー」がインストールされている必要がある。

まず下準備としてすべてのビューに対してタブの切り替えが通知されるようにする。「MainFrm.hのOntTabPageActivatedに処理を追加する。
	//タブが選択されたときの処理
	LRESULT OnTabPageActivated(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
	{
		if(pnmh == NULL)
			return	0;

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

			int kk=m_view.GetActivePage();

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

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

		bool		ret;
		CTabBrowser100View*	pView;

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

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

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

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

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

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

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

		return	0;
	}

tabbrowser93.gif 次に「Googleツールバー」を表示用の位置を確保するためにツールバー領域にリバーを作る。ここではCDummyWndというダミーウインドウを用意してそれにたいしてリバーを作成した。
	//■追加
	class	CDummyWnd	: public CWindowImpl<CDummyWnd>
	{
	public:
		BEGIN_MSG_MAP(CDummyWnd)
		END_MSG_MAP()
	};

	CDummyWnd			_wndDummy;		//■追加


	LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
	{
		// コマンドバー ウィンドウの作成
		HWND hWndCmdBar = m_CmdBar.Create(m_hWnd, rcDefault, NULL, ATL_SIMPLE_CMDBAR_PANE_STYLE);
		// メニューのアタッチ
		m_CmdBar.AttachMenu(GetMenu());
		// コマンドバー画像の読み込み
		m_CmdBar.LoadImages(IDR_MAINFRAME);
		// 以前のメニューの削除
		SetMenu(NULL);

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

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

		_wndAddressBar.Create(m_hWnd,CRect(0,0,200,200),0,WS_CHILD | WS_VISIBLE | CBS_DROPDOWN);
		AddSimpleReBarBand(_wndAddressBar);

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

		CreateSimpleStatusBar();

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

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

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

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

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

		return 0;
	}


tabbrowser94.gif
そしてタブが作成されるときに、「Googleツールバー」を配置するためのダミーウインドウがビューに渡すようにする。

本来であればこんな実装はするべきではないのだが、、、ソースコードが汚くなるが今回は(も)気にせずにどんどん変更していく。
	//タブの新規作成
	//nPosはタブを追加する場所。nPos<0(もしくはnPos=m_view.GetPageCount())で一番後ろ、
	//そのほかの数値はCTabView::InsertPageにそのまま渡す
	//
	//戻ったポインタは自動削除されるため、deleteの必要なし
	//
	CTabBrowser100View*	CreateNewTab(LPCTSTR pszURL,LPCTSTR pszTitle,int nPos=-1,int nImage=-1)
	{
		bool	ret;
		CTabBrowser100View*	pView;

		pView = new CTabBrowser100View(&m_view,_wndDummy);	//■変更 タブビューのポインタとIEツールバー用のダミーウインドウを渡しておく
		if(pView == NULL)
			return	NULL;

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

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

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

		return	pView;
	}

tabbrowser95.gif 「Googleツールバー」のようなInternet Explorer用ツールバーはIDeskBandとして実装されている。その内部では親ウインドウを取得するためにIOleWindow、IWebBrowser2を取得するためにIServiceProvider、フォーカス変更を知らせるためにIInputObjectSiteなどが利用されている。 それらを用意してIDeskBandをホストするためのインターフェースを作成する。
//■追加
//IEツールバーをホストするためのインターフェース
MIDL_INTERFACE("28997A04-86A4-436d-BF58-133F7BD82E8A")
IIEToolbar : public IUnknown
{
public:
	STDMETHOD (put_hwnd)(HWND hWnd) = 0;
	STDMETHOD (put_IWebBrowser2)(IDispatch* pIDispatch) = 0;
};



//■追加
//IEツールバーをホストするためのクラス
class ATL_NO_VTABLE CIEToolbar : 
	public CComObjectRootEx<CComSingleThreadModel>,
	public IOleCommandTarget,
	public IOleWindow,
	public IServiceProvider,
	public IInputObjectSite,
	public IIEToolbar
{
public:
	CIEToolbar()
	{
	}

	BEGIN_COM_MAP(CIEToolbar)
		COM_INTERFACE_ENTRY(IIEToolbar)
		COM_INTERFACE_ENTRY(IOleCommandTarget)
		COM_INTERFACE_ENTRY(IOleWindow)
		COM_INTERFACE_ENTRY(IServiceProvider)
		COM_INTERFACE_ENTRY(IInputObjectSite)
	END_COM_MAP()

	DECLARE_PROTECT_FINAL_CONSTRUCT()


	HWND	m_hWnd;			//ツールバーの親となるウインドウハンドルを保持 IOleWindow::GetWindow() でツールバーに渡す

	CComPtr<IDispatch>		_pIDispatch;		//ツールバーに渡すIWebBrowser2のIDispatch


	//IIEToolbar
	STDMETHOD (put_hwnd)(HWND hWnd)
	{
		m_hWnd = hWnd;
		return	S_OK;
	}
	STDMETHOD (put_IWebBrowser2)(IDispatch* pIDispatch)
	{
		_pIDispatch = NULL;

		if(pIDispatch == NULL)
			return	E_POINTER;

		return	pIDispatch->QueryInterface(IID_IDispatch,(void**)&_pIDispatch);
	}



	//IOleCommandTarget
	STDMETHOD(Exec)(const GUID *pguidCmdGroup,DWORD nCmdID,DWORD nCmdExecOpt,VARIANTARG *pvaIn,VARIANTARG *pvaOut)
	{
		return	S_OK;
	}
	STDMETHOD(QueryStatus)(const GUID *pguidCmdGroup,ULONG cCmds,OLECMD *prgCmds,OLECMDTEXT *pCmdText)
	{
		return	S_OK;
	}


	//IOleWindow
	STDMETHOD(ContextSensitiveHelp)(BOOL fEnterMode)
	{
		return	E_NOTIMPL;
	}
	STDMETHOD(GetWindow)(HWND* phwnd)
	{
		if(phwnd == NULL)
			return	E_FAIL;

		*phwnd = m_hWnd;
		return	S_OK;
	}


	//IServiceProvider
	STDMETHOD(QueryService)(REFGUID guidService,REFIID riid,void **ppv)
	{
		if(_pIDispatch)
		{
			*ppv = _pIDispatch;
			return	S_OK;
		}

		{
			//IEを起動して渡す

			HRESULT	hr;
			CComPtr<IWebBrowserApp>	pIWebBrowserApp;

			pIWebBrowserApp = NULL;
			hr = ::CoCreateInstance(CLSID_InternetExplorer,NULL,CLSCTX_SERVER,IID_IWebBrowserApp,(void**)&pIWebBrowserApp);
			if(pIWebBrowserApp)
				pIWebBrowserApp->put_Visible(VARIANT_TRUE);
			if(pIWebBrowserApp)
				pIWebBrowserApp->Navigate(L"about:blank",NULL,NULL,NULL,NULL);
			::Sleep(1000);		//■■1秒固定で待つ
			if(pIWebBrowserApp)
			{
				IWebBrowser2*	pIWebBrowser2;

				hr = pIWebBrowserApp->QueryInterface(IID_IWebBrowser2,(void**)&pIWebBrowser2);

				*ppv = pIWebBrowser2;
				return	S_OK;
			}
		}

		return	E_FAIL;
	}

	//IInputObjectSite
	STDMETHOD(OnFocusChangeIS)(IUnknown *punkObj,BOOL fSetFocus)
	{
		if(fSetFocus)
		{
			HRESULT	hr = E_FAIL;
			CComPtr<IOleInPlaceObject> pIOleInPlaceObject;

			if(_pIDispatch)
				_pIDispatch->QueryInterface(&pIOleInPlaceObject);
			if(pIOleInPlaceObject)
				hr = pIOleInPlaceObject->UIDeactivate();		//IEのUIを無効化
		}

		return	S_OK;
	}
};

tabbrowser96.gif ビュークラス内のコンストラクタ周りでリバー用のHWNDを保存するように修正する。
class CTabBrowser100View : public CWindowImpl<CTabBrowser100View, CAxWindow>
	,public IDispEventImpl<SINKID_EVENTS, CTabBrowser100View, &DIID_DWebBrowserEvents2>
	,public CIEUtility
{
	CTabView*	_pTabView;		//タブビューを保持
	HWND		_hWndRebarIE;	//■追加 IEツールバー用のリバー
public:
	DECLARE_WND_SUPERCLASS(NULL, CAxWindow::GetWndClassName())


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

tabbrowser97.gif
タブが切り替えられたときにIDeskBandの表示/非表示を切り替える動作を実装する。

ShowWindowで表示/非表示した方が効率がいいのだが、ここではIDeskBand::ShowDWを利用した。


Internet Explorer用のツールバーは1つのツールバーに対して1つのIEコントロールを割り当てる仕組みで作られている。これはIDeskBandがタブブラウザが一般的でなかった頃に設計されたインターフェースであり、当時は1つのInternet Explorerの中で複数のページを切り替えて表示することが想定されていなかったためだ。

スタンドアロン型のIE6からタブブラウザ型のIE7にバージョンアップするときに、このIDeskBandも併せてタブブラウザーに即した形に大きく変わるのではないか?と期待半分、大きく変わったらまたIEツールバーを作りなおさなければいけないという悪寒半分で昔はIE7の登場を待っていた。

しかし蓋を開けてみればIE6からIE7でIDeskBandはまったく同じままに残った。最初は不思議だったのだが、SPY++でのぞいてみるとすぐにその理由がわかった。Internet Explorer 7は1つのタブに対して1つのIEツールバーを生成する。。。そしてタブを切り替えたときにそれらを表示/非表示して切り換えていた。平たく言えば、IE7は内部でタブの数だけIE6を開くような造りになっていた。

今回実装しているタブブラウザー内「Googleツールバー」の表示でも同じ方法を使っている。ビュークラス内でIDeskBandを生成し、タブが切り替わったときにアクティブになったタブのIDeskBandを表示、それ以外を非表示にしている。
	CComPtr<IDeskBand>	_pIDeskBand;	//■追加


	//■追加
	//タブの選択変更があったときメインウインドウから呼ばれる
	bool	OnTabPageChange(bool bActivated)
	{
		if(_pIDeskBand == NULL)
			return	false;

		if(bActivated)
			_pIDeskBand->ShowDW(TRUE);		//IEツールバーを表示
		else
			_pIDeskBand->ShowDW(FALSE);		//IEツールバーを消す

		return	true;
	}

tabbrowser98.gif
最後にCreate()の中で「Googleツールバー」のIDeskBandを生成する。

「Googleツールバー」のGUIDは数年前にメモしていたものを流用したが、2009年4月4日現在の最新版のものでも同じGUIDが使われているようだ。 このGUIDを使ってCOMインターフェースをCoCreateInstanceし、ホストするためのIIEToolbarインターフェースに割り当てている。
		//■追加
		//Googleツールバーを生成する
		{
			HRESULT	hr;
			GUID	rclsid;
			WCHAR	pszGUID[] = {L"{2318C2B1-4965-11d4-9B18-009027A5CD4F}"};		//GoogleツールバーのGUID

			::CLSIDFromString(pszGUID,&rclsid);

			_pIDeskBand = NULL;
			hr = ::CoCreateInstance(rclsid,NULL,CLSCTX_INPROC_SERVER,IID_IDeskBand,(void**)&_pIDeskBand);
			if(_pIDeskBand)
			{
				CComPtr<IObjectWithSite>	pIObjectWithSite;

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

				DESKBANDINFO	sDeskBandInfo;

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

				//■■本当はきちんと調整しないとだめ!!
				CRect	rect(0,0,2000,sDeskBandInfo.ptMinSize.y);		//横サイズは十分大きいサイズを確保(//■■2000px固定)

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

					pIIEToolbar = new CComObject<CIEToolbar>;

					pIIEToolbar->put_hwnd(_hWndRebarIE);
					if(_pIWebBrowser2)
						pIIEToolbar->put_IWebBrowser2(_pIWebBrowser2);
					if(pIObjectWithSite)
						hr = pIObjectWithSite->SetSite(pIIEToolbar);

					if(SUCCEEDED(hr))
						hr = _pIDeskBand->ShowDW(TRUE);
				}

				//位置調整
				{
					HWND	hWnd;

					_pIDeskBand->GetWindow(&hWnd);
					if(::IsWindow(hWnd))
						::MoveWindow(hWnd,0,0,rect.Width(),rect.Height(),TRUE);
				}
			}
		}

		return	hWnd;
	}

tabbrowser99.gif
これでビルド/実行してタブを開くと「Googleツールバー」が表示され、検索などができるようになった。もちろんページランクの表示機能なども動作した。

しかしホスト方法、特に親ウインドウを共通にしているなどだいぶ実装を省略しているため、「Googleツールバー」ではドロップダウンリストからアクセスできる検索履歴を利用するときにうまく動かないことがあるようだ。

次回は「印刷」機能を実装する。

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

第23回 プログレスバーでページの読み込み状況を表示する (タブブラウザーを作る)

tabbrowser86.gif
前回はステータスバーにプログレスコントロールを配置した。今回はプログレスコントロールにIEコントロールから受けとった進行状況を表示する。

基本的な流れはステータスバーにIEコントロールからのメッセージを表示したときと同じだ。

「stdafx.h」にIEコントロールからの進行状況を知らせる独自メッセージを定義する。
#define	WM_DNP_CHANGEPROGRESS	(WM_APP + 5)		//■追加

tabbrowser88.gif 次にビュークラスでIEコントロールからのDISPID_PROGRESSCHANGEイベントを受信してメインウインドウへ通知する処理を実装する。
	//■2つ変数を追加
	long	_nLastProgress;			//最後に受け取ったプログレス情報
	long	_nLastProgressMax;		//最後に受け取ったプログレス最大値

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

		//状態を保存しておく
		_nLastProgress		= lProgress;
		_nLastProgressMax	= lProgressMax;

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

		//メインウインドウに変更を通知する
		GetTopLevelWindow().SendMessage(WM_DNP_CHANGEPROGRESS,(WPARAM)_nLastProgress,(LPARAM)_nLastProgressMax);
	}

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

tabbrowser87.gif long型のメンバー変数_nLastProgressと_nLastProgressMaxをコンストラクタで初期化する処理を忘れずに追加しておく。
	CTabBrowser100View(CTabView* pTabView)
	{
		_pTabView = pTabView;
		_nLastProgress		= 0;		//■追加
		_nLastProgressMax	= -1;		//■追加
	}

tabbrowser89.gif
そして「MainFrm.h」側で独自メッセージを受信したときにそれをプログレスバーに表示する処理を追加する。

また、OnSize内でタブブラウザー起動時にプログレスバーが表示されないようにIsWindow()でチェックする処理を入れた。
	BEGIN_MSG_MAP(CMainFrame)
		MESSAGE_HANDLER(WM_DNP_CREATENEWTAB, OnDnpCreateNewTab)
		MESSAGE_HANDLER(WM_DNP_CHANGEFOCUS, OnDnpChangeFocus)
		MESSAGE_HANDLER(WM_DNP_CHANGEADDRESS, OnDnpChangeAddress)
		MESSAGE_HANDLER(WM_DNP_CHANGESTATUSTEXT, OnDnpChangeStatusText)
		MESSAGE_HANDLER(WM_DNP_CHANGEPROGRESS, OnDnpChangeProgress)		//■追加
		NOTIFY_CODE_HANDLER(CBEN_ENDEDIT, OnAddressbarEnter)
		MESSAGE_HANDLER(WM_CREATE, OnCreate)
		MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
		COMMAND_ID_HANDLER(ID_APP_EXIT, OnFileExit)
		COMMAND_ID_HANDLER(ID_FILE_NEW, OnFileNew)
		COMMAND_ID_HANDLER(ID_VIEW_TOOLBAR, OnViewToolBar)
		COMMAND_ID_HANDLER(ID_VIEW_STATUS_BAR, OnViewStatusBar)
		COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)
		COMMAND_ID_HANDLER(ID_WINDOW_CLOSE, OnWindowClose)
		COMMAND_ID_HANDLER(ID_WINDOW_CLOSE_ALL, OnWindowCloseAll)
		COMMAND_RANGE_HANDLER(ID_WINDOW_TABFIRST, ID_WINDOW_TABLAST, OnWindowActivate)
		COMMAND_ID_HANDLER(ID_IE_BACK, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_NEXT, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_STOP, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_REFRESH, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_ADDFAVORITE, OnIEAddFavorite)
		COMMAND_ID_HANDLER(ID_IE_ORGANIZE_FAVORITE, OnIEOrganizeFavorite)
		NOTIFY_CODE_HANDLER(TBVN_CONTEXTMENU, OnTabContextMenu)
		NOTIFY_CODE_HANDLER(TBVN_PAGEACTIVATED, OnTabPageActivated)
		MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)
		MESSAGE_HANDLER(WM_SIZE, OnSize)
		COMMAND_RANGE_HANDLER(ID_FAVORITE_FIRST,ID_FAVORITE_LAST,OnFavorite)
		CHAIN_MSG_MAP_MEMBER(_cFovMenu)
		CHAIN_MSG_MAP(CUpdateUI<CMainFrame>)
		CHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>)
	END_MSG_MAP()

	//■追加
	LRESULT OnDnpChangeProgress(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		RefreshProgressBar((long)wParam,(long)lParam);
		return	0;
	}


	LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		bHandled = FALSE;

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

		return	0;
	}

tabbrowser90.gif 最後に、タブが切り替わったときに、新しいタブでの進行状況が表示されるように、OnTabPageActivated()の中にプログレスバーの更新処理を入れておく。
	//タブが選択されたときの処理
	LRESULT OnTabPageActivated(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
	{
		if(pnmh == NULL)
			return	0;

		bool		ret;
		CTabBrowser100View*	pView;

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

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

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

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

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

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

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

		return	0;
	}

tabbrowser91.gif
これでビルド/実行するとステータスバーにあるプログレスバーコントロールにページの読み込み状況が表示されるようになった。

次回はちょっと趣向を変えて「Googleツールバー」を利用する。実現方法がまだわからないので挫折したらほかの話題に変わるかもしれません。

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

第22回 ステータスバーにプログレスコントロールを配置する (タブブラウザーを作る)

tabbrowser84.gif
Internet Explorerはステータスバーにプログレスバーが表示され、ページの読み込み状態がひと目でわかるようになっている。

今回はInternet Explorerのように進行状況を表示するためステータスバーにプログレスバーコントロールを配置する。

CStatusBarCtrl::SetParts() を利用してペインを1つ作り、そのうちの1つにプログレスバーコントロールが重なるように配置した。表示するタイミングはWM_SIZEを利用し、ステータスバーががメインウインドウのサイズ変更されたときもきちんと更新されるようにした。 また、今回はプログレスバーを表示するにとどめ、進行状況の表示はしていない。
	BEGIN_MSG_MAP(CMainFrame)
		MESSAGE_HANDLER(WM_DNP_CREATENEWTAB, OnDnpCreateNewTab)
		MESSAGE_HANDLER(WM_DNP_CHANGEFOCUS, OnDnpChangeFocus)
		MESSAGE_HANDLER(WM_DNP_CHANGEADDRESS, OnDnpChangeAddress)
		MESSAGE_HANDLER(WM_DNP_CHANGESTATUSTEXT, OnDnpChangeStatusText)
		NOTIFY_CODE_HANDLER(CBEN_ENDEDIT, OnAddressbarEnter)
		MESSAGE_HANDLER(WM_CREATE, OnCreate)
		MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
		COMMAND_ID_HANDLER(ID_APP_EXIT, OnFileExit)
		COMMAND_ID_HANDLER(ID_FILE_NEW, OnFileNew)
		COMMAND_ID_HANDLER(ID_VIEW_TOOLBAR, OnViewToolBar)
		COMMAND_ID_HANDLER(ID_VIEW_STATUS_BAR, OnViewStatusBar)
		COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)
		COMMAND_ID_HANDLER(ID_WINDOW_CLOSE, OnWindowClose)
		COMMAND_ID_HANDLER(ID_WINDOW_CLOSE_ALL, OnWindowCloseAll)
		COMMAND_RANGE_HANDLER(ID_WINDOW_TABFIRST, ID_WINDOW_TABLAST, OnWindowActivate)
		COMMAND_ID_HANDLER(ID_IE_BACK, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_NEXT, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_STOP, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_REFRESH, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_ADDFAVORITE, OnIEAddFavorite)
		COMMAND_ID_HANDLER(ID_IE_ORGANIZE_FAVORITE, OnIEOrganizeFavorite)
		NOTIFY_CODE_HANDLER(TBVN_CONTEXTMENU, OnTabContextMenu)
		NOTIFY_CODE_HANDLER(TBVN_PAGEACTIVATED, OnTabPageActivated)
		MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)
		MESSAGE_HANDLER(WM_SIZE, OnSize)				//■追加
		COMMAND_RANGE_HANDLER(ID_FAVORITE_FIRST,ID_FAVORITE_LAST,OnFavorite)
		CHAIN_MSG_MAP_MEMBER(_cFovMenu)
		CHAIN_MSG_MAP(CUpdateUI<CMainFrame>)
		CHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>)
	END_MSG_MAP()


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

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

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

		if(nProgressMax < nProgress)
			bVisible = false;

		if(bVisible == false)
			nProgressWidth = 0;

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

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

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


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

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

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

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

		return	true;
	}


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

		RefreshProgressBar(50,100);		//プログレスバーを50%で表示

		return	0;
	}


tabbrowser85.gif
これでビルド/実行するとステータスバーにプログレスバーコントロールが表示された。

次回はこのプログレスバーコントロールにIEコントロールから受け取った進行状況を表示する。

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

第21回 IEコントロールからのメッセージをステータスバーに表示する (タブブラウザーを作る)

tabbrowser80.gif
Internet Explorerではステータスバーに「ページが表示されました」などのメッセージが表示される。この文字列はIEコントロールのイベントDISPID_STATUSTEXTCHANGEで受信できる。今回はこれを利用してステータスバーにメッセージを表示する。

ステータスバーメッセージ表示機能の実装はアドレスバーに開かれているページのURLを表示したのと基本的に同じ流れだ。

まず「stdafx.h」にメインウインドウへメッセージが変更されたことを知らせる独自メッセージを定義する。
#define	WM_DNP_CHANGESTATUSTEXT	(WM_APP + 4)			//■追加

tabbrowser81.gif 次にビュークラスの中にIEコントロールからのイベントを受信したときにメインウインドウへ通知する処理を実装する。またユーザーによって「タブ」が切りかえられたときに、そのページ用のステータスバーメッセージがきちんと表示されるように取得用の関数GetLastStatusText()も実装しておく。
	CAtlString	_strLastStatusText;		//■追加 最後に送られてきたステータステキストを保管

	void __stdcall OnStatusTextChange(BSTR bstrText)
	{
		//■処理を実装

		_strLastStatusText = bstrText;		//いつでも参照できるようにクラスのメンバーに保存しておく

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

		//メインウインドウに変更を通知する
		GetTopLevelWindow().SendMessage(WM_DNP_CHANGESTATUSTEXT,(WPARAM)(LPCTSTR)_strLastStatusText);
	}

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

tabbrowser82.gif そして「MainFrm.h」内に独自メッセージWM_DNP_CHANGESTATUSTEXTを受け取ったときや、タブが切り替わったときにステータスバーの表示を更新する処理を追加する。
	BEGIN_MSG_MAP(CMainFrame)
		MESSAGE_HANDLER(WM_DNP_CREATENEWTAB, OnDnpCreateNewTab)
		MESSAGE_HANDLER(WM_DNP_CHANGEFOCUS, OnDnpChangeFocus)
		MESSAGE_HANDLER(WM_DNP_CHANGEADDRESS, OnDnpChangeAddress)
		MESSAGE_HANDLER(WM_DNP_CHANGESTATUSTEXT, OnDnpChangeStatusText)	//■追加
		NOTIFY_CODE_HANDLER(CBEN_ENDEDIT, OnAddressbarEnter)
		MESSAGE_HANDLER(WM_CREATE, OnCreate)
		MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
		COMMAND_ID_HANDLER(ID_APP_EXIT, OnFileExit)
		COMMAND_ID_HANDLER(ID_FILE_NEW, OnFileNew)
		COMMAND_ID_HANDLER(ID_VIEW_TOOLBAR, OnViewToolBar)
		COMMAND_ID_HANDLER(ID_VIEW_STATUS_BAR, OnViewStatusBar)
		COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)
		COMMAND_ID_HANDLER(ID_WINDOW_CLOSE, OnWindowClose)
		COMMAND_ID_HANDLER(ID_WINDOW_CLOSE_ALL, OnWindowCloseAll)
		COMMAND_RANGE_HANDLER(ID_WINDOW_TABFIRST, ID_WINDOW_TABLAST, OnWindowActivate)
		COMMAND_ID_HANDLER(ID_IE_BACK, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_NEXT, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_STOP, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_REFRESH, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_ADDFAVORITE, OnIEAddFavorite)
		COMMAND_ID_HANDLER(ID_IE_ORGANIZE_FAVORITE, OnIEOrganizeFavorite)
		NOTIFY_CODE_HANDLER(TBVN_CONTEXTMENU, OnTabContextMenu)
		NOTIFY_CODE_HANDLER(TBVN_PAGEACTIVATED, OnTabPageActivated)
		MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)
		COMMAND_RANGE_HANDLER(ID_FAVORITE_FIRST,ID_FAVORITE_LAST,OnFavorite)
		CHAIN_MSG_MAP_MEMBER(_cFovMenu)
		CHAIN_MSG_MAP(CUpdateUI<CMainFrame>)
		CHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>)
	END_MSG_MAP()

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

		if(pszText == NULL)
			return	0;

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

		return	0;
	}


	//■処理を変更/追加
	//タブが選択されたときの処理
	LRESULT OnTabPageActivated(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
	{
		if(pnmh == NULL)
			return	0;

		bool		ret;
		CTabBrowser100View*	pView;

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

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

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

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

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

		return	0;
	}

tabbrowser83.gif
これでビルド/実行するとステータスバーにIEコントロールからのメッセージが表示されるようになった。

次回はダウンロード状況などがわかるようにステータスバーにプログレスバーを配置する。

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

第20回 ウインドウの位置やサイズを保存/復元する (タブブラウザーを作る)

tabbrowser73.gif
今回は終了時にウインドウの位置やサイズを保存し、起動時にその位置やサイズをみ込むことで前回閉じた位置に前回のままの大きさで開く処理を実装する。情報の保存はレジストリに行う。

ウインドウの位置やサイズの取得/復元は以前に「ウインドウの位置情報を保存/復元するクラス」で作成したCDnpWindowPlacementクラスを利用する。

まずこのクラスを利用するために「DnpWindowPlacement.h」ファイルをプロジェクトに追加する。Visual Studio 2008で「プロジェクト」メニューから「既存の項目を追加」を選択する。このメニュー項目がない場合はソリューションウインドウを開いてからもういちどメニューを選択する。

tabbrowser74.gif
そして現われたウインドウで「DnpWindowPlacement.h」を追加する。

※このファイルは今回のサンプルプロジェクトもしくは「ウインドウの位置情報を保存/復元するクラス」からダウンロードしてください

tabbrowser75.gif 次に情報を保存するためのレジストリ位置を簡単に変えれるように「stdafx.h」にレジストリ位置用の定義を追加する。
#define	DNP_REGKEY		_T("software\\dinop\\tabbrowser")	//■追加

tabbrowser76.gif そして「TabBrowser100.cpp」のメインウインドウ生成後にレジストリから位置情報を読み込み、復元する処理を追加する。
int Run(LPTSTR /*lpstrCmdLine*/ = NULL, int nCmdShow = SW_SHOWDEFAULT)
{
	CMessageLoop theLoop;
	_Module.AddMessageLoop(&theLoop);

	CMainFrame wndMain;

	if(wndMain.CreateEx() == NULL)
	{
		ATLTRACE(_T("メイン ウィンドウの作成に失敗しました!\n"));
		return 0;
	}

	//wndMain.ShowWindow(nCmdShow);		//■削除

	//■追加
	//ウインドウサイズ/位置をレジストリから復元
	{
		bool	ret;
		CDnpWindowPlacement	cPlacement;

		ret = cPlacement.LoadFromReg(HKEY_CURRENT_USER,DNP_REGKEY,_T("WindowPlacement"));
		if(ret)
			ret = cPlacement.Restore(wndMain);
		if(ret == false)
			wndMain.ShowWindow(nCmdShow);
	}

	int nRet = theLoop.Run();

	_Module.RemoveMessageLoop();
	return nRet;
}

tabbrowser77.gif さらに「MainFrm.h」内にCDnpWindowPlacementを利用するためのincludeを追加する。
#include "DnpWindowPlacement.h"		//■追加

tabbrowser78.gif そして、OnDestroy()が呼ばれたときにレジストリへウインドウの位置/サイズを保存するようにする。
	LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
	{
		//■追加
		//現在のウインドウサイズ/位置をレジストリに保存
		{
			CDnpWindowPlacement	cPlacement;

			cPlacement.GetCurrentPos(m_hWnd);
			cPlacement.SaveToReg(HKEY_CURRENT_USER,DNP_REGKEY,_T("WindowPlacement"));
		}

		_cTabImageList.Destroy();

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

		bHandled = FALSE;
		return 1;
	}

tabbrowser79.gif
これでビルド/実行すると前回の位置に同じ大きさでタブブラウザが開くようになった。

次回はステータスバーにIEコントロールからのメッセージを表示する機能を追加する。

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

第19回 タブを切り替えたときにアドレスバーのURL表示を更新する (タブブラウザーを作る)

tabbrowser70.gif
前回はアドレスバーにアクティブなタブで読み込まれたホームページのURLが自動で表示されるようにした。しかしタブを切り替えたときにアドレスバーのURL表示が変わらないという問題があった。今回はその点を修正する。

WTLのCTabViewではタブが切り替わったとき、親ウインドウにTBVN_PAGEACTIVATEDという通知が届く。これを処理してアドエスバーを更新する。MainFrm.h内にTBVN_PAGEACTIVATEDのハンドラと処理を実装する。
	BEGIN_MSG_MAP(CMainFrame)
		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)
		MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
		COMMAND_ID_HANDLER(ID_APP_EXIT, OnFileExit)
		COMMAND_ID_HANDLER(ID_FILE_NEW, OnFileNew)
		COMMAND_ID_HANDLER(ID_VIEW_TOOLBAR, OnViewToolBar)
		COMMAND_ID_HANDLER(ID_VIEW_STATUS_BAR, OnViewStatusBar)
		COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)
		COMMAND_ID_HANDLER(ID_WINDOW_CLOSE, OnWindowClose)
		COMMAND_ID_HANDLER(ID_WINDOW_CLOSE_ALL, OnWindowCloseAll)
		COMMAND_RANGE_HANDLER(ID_WINDOW_TABFIRST, ID_WINDOW_TABLAST, OnWindowActivate)
		COMMAND_ID_HANDLER(ID_IE_BACK, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_NEXT, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_STOP, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_REFRESH, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_ADDFAVORITE, OnIEAddFavorite)
		COMMAND_ID_HANDLER(ID_IE_ORGANIZE_FAVORITE, OnIEOrganizeFavorite)
		NOTIFY_CODE_HANDLER(TBVN_CONTEXTMENU, OnTabContextMenu)
		NOTIFY_CODE_HANDLER(TBVN_PAGEACTIVATED, OnTabPageActivated)		//■追加
		MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)
		COMMAND_RANGE_HANDLER(ID_FAVORITE_FIRST,ID_FAVORITE_LAST,OnFavorite)
		CHAIN_MSG_MAP_MEMBER(_cFovMenu)
		CHAIN_MSG_MAP(CUpdateUI<CMainFrame>)
		CHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>)
	END_MSG_MAP()



	//■追加
	//タブが選択されたときの処理
	LRESULT OnTabPageActivated(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
	{
		if(pnmh == NULL)
			return	0;

		bool		ret;
		CAtlString	strURL;
		CTabBrowser100View*	pView;

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

		ret = pView->GetURL(strURL);		//URL取得
		if(ret == false)
			return	0;

		//アドレスバーのURL変更
		_wndAddressBar.SetWindowText(strURL);

		return	0;
	}

tabbrowser71.gif 次にIEUtility.hに現在のURLを取得するための関数を追加する。
	//■追加
	bool	GetURL(CAtlString& strURL)
	{
		HRESULT		hr;
		CComBSTR	bstr;

		strURL = _T("");
		if(_pIWebBrowser2 == NULL)
			return	false;

		hr = _pIWebBrowser2->get_LocationURL(&bstr);
		if(FAILED(hr))
			return	false;

		strURL = bstr;

		return	true;
	}

tabbrowser72.gif
これでビルド/実行するとタブを切り替えたときにもきちんとアドレスバーにそのタブで開いているページのURLが表示されるようになった。

まだまだアドレスバーで修正しなければいけない点が残っているがとりあえず保留して、次回はタブブラウザーが起動するときに前回閉じた位置で開くように設定する。

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

2009年04月03日

第18回 アドレスバーに自動で現在のURLを表示する (タブブラウザーを作る)

tabbrowser66.gif
今までアドレスバーはURLを入力して開くというアドレスバー→タブ方向の一方的な機能しか実装されていなかった。Internet Explorerなどのアドレスバーではリンクのクリックなどにより読み込まれたホームページのURLが自動でアドレスバーに表示され、アドレスバーとタブが双方向にアクセスし合っている。

今回はタブ内で読み込まれたURLをアドレスバーに表示する機能を実装する。まずはURL変更をメインウインドウに知らせるための独自メッセージをstdafx.h内に定義する。
#define	WM_DNP_CHANGEADDRESS	(WM_APP + 3)		//■追加

tabbrowser67.gif そして定義した独自メッセージハンドラをMainFrm.h内に書く。ここでは(あまりやりたくはないのだが)直接アドレスバーへSetWindowTextでURLを書き込むことにした。
	BEGIN_MSG_MAP(CMainFrame)
		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)
		MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
		COMMAND_ID_HANDLER(ID_APP_EXIT, OnFileExit)
		COMMAND_ID_HANDLER(ID_FILE_NEW, OnFileNew)
		COMMAND_ID_HANDLER(ID_VIEW_TOOLBAR, OnViewToolBar)
		COMMAND_ID_HANDLER(ID_VIEW_STATUS_BAR, OnViewStatusBar)
		COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)
		COMMAND_ID_HANDLER(ID_WINDOW_CLOSE, OnWindowClose)
		COMMAND_ID_HANDLER(ID_WINDOW_CLOSE_ALL, OnWindowCloseAll)
		COMMAND_RANGE_HANDLER(ID_WINDOW_TABFIRST, ID_WINDOW_TABLAST, OnWindowActivate)
		COMMAND_ID_HANDLER(ID_IE_BACK, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_NEXT, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_STOP, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_REFRESH, OnIECommand)
		COMMAND_ID_HANDLER(ID_IE_ADDFAVORITE, OnIEAddFavorite)
		COMMAND_ID_HANDLER(ID_IE_ORGANIZE_FAVORITE, OnIEOrganizeFavorite)
		NOTIFY_CODE_HANDLER(TBVN_CONTEXTMENU, OnTabContextMenu)
		MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)
		COMMAND_RANGE_HANDLER(ID_FAVORITE_FIRST,ID_FAVORITE_LAST,OnFavorite)
		CHAIN_MSG_MAP_MEMBER(_cFovMenu)
		CHAIN_MSG_MAP(CUpdateUI<CMainFrame>)
		CHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>)
	END_MSG_MAP()


	//■追加
	//アドレスバー表示用URLの変更処理
	//アクティブなタブのIEでURL変更があったときにメッセージが届く
	LRESULT OnDnpChangeAddress(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		LPCTSTR		pszURL = (LPCTSTR)wParam;

		if(pszURL == NULL)
			return	0;

		_wndAddressBar.SetWindowText(pszURL);

		return	0;
	}

tabbrowser68.gif
さらにビュークラスにIEコントロールからのイベントを受信して、URL変更をメインウインドウへ知らせる処理を追加する。

URLはIEコントロールからのOnNavigateComplete2イベントを受信したときにアドレスバーへ表示することにした。
	//■追加
	//メインウインドウへアドレス変更を通知する
	bool	NotifyChangeURL(LPCTSTR pszURL)
	{
		if(_pTabView == NULL)
			return	false;
		if(_pTabView->GetActivePage() != _pTabView->PageIndexFromHwnd(m_hWnd))
			return	false;			//このビューがアクティブでなければ処理しない

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

		return	true;
	}

	void __stdcall OnNavigateComplete2(IDispatch *pDisp,VARIANT *pvURL)
	{
		//■処理内容実装
		if(pDisp != _pIWebBrowser2)
			return;			//フレームなどのイベントは無視

		NotifyChangeURL((CAtlString)pvURL->bstrVal);
	}

tabbrowser69.gif
これでビルド/実行するとアクティブタブでのページ切り替えを検出してアドレスバーのURLが自動的に変わるようになった。

まだこの状態だと、タブを切り替えたときにきちんとアドレスバーのURL表示が更新されない、次回はその点を修正する。


ちなみにInternet Exploreのアドレスバーではユーザーがアドレスを入力中(もしくは入力した形跡がある)ならアドレスバーの表示を変更しない、などの機能も備えているようだ。

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

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

前回までにATL/WTLのアプリケーションウイザードのタブ型ビューMDIをひな形にタブブラウザーを作ってきた。だんだんと機能も増えて少しずつ形になってきた。

しかし機能が増えるに従ってソースコードがごちゃごちゃとしてきて大変なことになっている。作り上げる目標もなく、思いつきのままに実装をしているため初期に実装したものの今では不要なものまででてきている。

今回は前回までに作成したソースコードを少し整理する。



stdafx.cppへの追い出し

ソースコードの中に「インターネットショートカットを作る」「インターネットショートカットからURLを取り出す」というような汎用的に使える関数がいくつかある。それらをコピペでstdafx.cppへ移動する。

これらは一度作ったら編集する可能性も少ないので関数宣言をstdafx.hに置いた。
#include "atlmisc.h"
#include "atlstr.h"

bool	CreateInternetShortcut(LPCTSTR pszURL, LPCTSTR pszFileName);
HRESULT	IUnknown_Exec(IUnknown* pUnk,const GUID *pguidCmdGroup,DWORD nCmdID,DWORD nCmdExecOpt,VARIANTARG *pvaIn,VARIANTARG *pvaOut);
BOOL	SafeSHGetSpecialFolderPath(HWND hwndOwner,LPTSTR lpszPath,int nFolder,BOOL fCreate);
bool	GetInternetShortcut(LPCTSTR pszFile,CAtlString& strURL);
HBITMAP	GetHBitmapFromFile(LPCTSTR pszFile);
bool	DoOrganizeFavDlg(HWND hWnd,LPTSTR pszFolder=NULL);






重複コードの関数化(その1)ページビューの取得

MainFrm.h内では、
{
	int		nPage;
	CTabBrowser100View*	pView = NULL;

	nPage = m_view.GetActivePage();
	if(nPage >= 0)
		pView = (CTabBrowser100View*)m_view.GetPageData(nPage);
	if(pView)
	{
		....
	}
}
というようにビュークラスへのポインタを取得する処理がいたるところに散在している。

同じようなソースをその都度書いていると、処理を変更したいときに変更漏れが生じたり、処理そのものを間違えてバグを生み出したりする。もちろん重複コードがたくさんあるとそれだけでソースコードの可読性も落ちる。

そのためこの部分を、、、
	//指定されたタブのビュークラスを取得
	CTabBrowser100View*	GetPageView(int nPage)
	{
		if(nPage < 0)
			return	NULL;
		return	(CTabBrowser100View*)m_view.GetPageData(nPage);
	}

	//アクティブページのビュークラスを取得
	CTabBrowser100View*	GetActivePageView(void)
	{
		return	GetPageView(m_view.GetActivePage());
	}
という2つの関数を用意して、
{
	CTabBrowser100View*	pView;

	pView = GetActivePageView();
	if(pView)
	{
		....
	}
}
と簡潔に書けるようにする。これで重複するソースコードをいくらか削除できる。






重複コードの関数化(その2)タブの新規作成

タブが開いていない状態で「お気に入り」が選択されたとき、リンクを「新しいウインドウで開く」ときなどでタブを作る処理は
	pView = new CTabBrowser100View(&m_view);	//タブビューのポインタを渡しておく
	pView->Create(m_view, rcDefault, _T("about:blank"), WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_HSCROLL | WS_VSCROLL, 0);
	m_view.AddPage(pView->m_hWnd, _T("Document"),-1,pView);
というようなコードをその都度書いてきた。これを関数化して重複コードを減らす。
	//タブの新規作成
	//nPosはタブを追加する場所。nPos<0(もしくはnPos=m_view.GetPageCount())で一番後ろ、
	//そのほかの数値はCTabView::InsertPageにそのまま渡す
	//
	//戻ったポインタは自動削除されるため、deleteの必要なし
	//
	CTabBrowser100View*	CreateNewTab(LPCTSTR pszURL,LPCTSTR pszTitle,int nPos=-1,int nImage=-1)
	{
		bool	ret;
		CTabBrowser100View*	pView;

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

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

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

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

		return	pView;
	}

この関数の実装によりCMainFrame内であれば、簡単にタブを作れるようになった。しかし、ビュークラスからタブを作りたい場合はこのままでは直接CreateNewTabを呼びだせない。

そのためWM_DNP_CREATENEWTABという独自メッセージを利用してビューからのメッセージによりタブを作れるようにする。今回は、、、
class	CTabBrowser100View;

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

	CTabBrowser100View*	pView;

	CDnpCreateNewTabInfo()
	{
		strURL	= _T("about:blank");
		pView	= NULL;
		nImage	= -1;
		nPos	= -1;
	}
};



	//WM_DNP_CREATENEWTABによりタブの作成
	//WPARAMはCDnpCreateNewTabInfoへのポインタを渡す
	LRESULT OnDnpCreateNewTab(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		CDnpCreateNewTabInfo*	pInfo = (CDnpCreateNewTabInfo*)wParam;

		if(pInfo == NULL)
			return	0;

		pInfo->pView = CreateNewTab(pInfo->strURL,pInfo->strTitle,pInfo->nPos,pInfo->nImage);

		return	0;
	}
というような雰囲気で実装した。






ビュークラスの単純機能をほかのクラスに追い出す

CTabBrowser100View の中には
	void	Back(void)
	{
		if(_pIWebBrowser2)
			_pIWebBrowser2->GoBack();
	}

	void	Next(void)
	{
		if(_pIWebBrowser2)
			_pIWebBrowser2->GoForward();
	}
のようにIWebBrowser2のメソッドを呼び出すだけの単純な関数が多くある(また今後も増えるだろう)。 それらをCIEUtilityというクラスに追い出して、CTabBrowser100View派生元に追加する。
class	CIEUtility
{
protected:
	CComPtr<IWebBrowser2>		_pIWebBrowser2;

public:

	//URLを開く
	bool	Navigate(LPCTSTR pszURL)
	{
		HRESULT	hr;

		if(_pIWebBrowser2 == NULL || pszURL == NULL || *pszURL == NULL)
			return	false;

		hr = _pIWebBrowser2->Navigate(CComBSTR(pszURL),&CComVariant(),&CComVariant(),&CComVariant(),&CComVariant());

		return	SUCCEEDED(hr) ? true : false;
	}

	void	Back(void)
	{
		if(_pIWebBrowser2)
			_pIWebBrowser2->GoBack();
	}

(・・・省略・・・)

	//「戻る」や「進む」ための履歴がIEにあるかどうかのチェック
	bool	IsButtonEnable(bool& bBack,bool& bNext)
	{
		HRESULT	hr;
		DWORD	dwCount;

		CComPtr<ITravelLogStg>			pITravelLogStg;
		CComPtr<IServiceProvider>		pIServiceProvider;

		bBack = false;
		bNext = false;

		if(_pIWebBrowser2)
			_pIWebBrowser2->QueryInterface(&pIServiceProvider);
		if(pIServiceProvider)
			pIServiceProvider->QueryService(SID_STravelLogCursor,IID_ITravelLogStg,(void**)&pITravelLogStg);
		if(pITravelLogStg == NULL)
			return	false;

		hr = pITravelLogStg->GetCount(TLEF_RELATIVE_BACK,&dwCount);
		if(dwCount)
			bBack = true;
		if(FAILED(hr))
			return	false;

		hr = pITravelLogStg->GetCount(TLEF_RELATIVE_FORE,&dwCount);
		if(FAILED(hr))
			return	false;
		if(dwCount)
			bNext = true;

		return	true;
	}
};






外部からビュークラスのIWebBrowser2に直接アクセスしないようにする

現状のCMainFrame::OnDnpChangeFocus() では
	//フォーカス変更時処理
	LRESULT OnDnpChangeFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		BOOL	bHasFocus = (BOOL)wParam;		//アドレスバーなどがフォーカスを受け取っていたらTRUE

		CTabBrowser100View*	pView;

		pView = GetActivePageView();
		if(pView == NULL)
			return	0;

		if(bHasFocus)
		{
			//アドレスバーなどIE以外がフォーカスを受け取った

			CComPtr<IOleInPlaceObject> pIOleInPlaceObject;

			pView->_pIWebBrowser2->QueryInterface(&pIOleInPlaceObject);
			if(pIOleInPlaceObject)
				pIOleInPlaceObject->UIDeactivate();		//IEのUIを無効化
		}

		return	0;
	}
のようにビュークラス内の_pIWebBrowser2に直接アクセスしている。このような実装は行儀がわるいので修正する。 ここではCIEUtility::SetFocusChange()を作り、それを呼ぶようにした。






必要ないコードを削除

ビュークラス内のCTabBrowser100View::GetBrowserCtrlとCTabBrowser100View::PreTranslateMessage()は必要ないので削除する。

GetBrowserCtrlの削除に伴ってCTabBrowser100View::_pIWebBrowser2のインターフェースを確保する部分がなくなったのでしその処理をOnCreate()内で行っておく。
	//Create関数のオーバーライド。内部でIEの取得、接続などを行う
	HWND Create(HWND hWndParent, _U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
			DWORD dwStyle = 0, DWORD dwExStyle = 0,
			_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
	{
		HWND	hWnd;

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

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

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

		return	hWnd;
	}



各クラス用のヘッダーファイルを作成する

今まではMainFrm.h内に複数のクラスを記述するなど、どんどん増やしていた。これをCFavoritesMenuは「FavoritesMenu.h」内に、、、というようにヘッダーファイルに分ける。






(その他。。。?)

現状ではクラス内のpublic、private、protectedの分類やコメントが全然ない。
そこまで整理しておこうと思ったのだがだんだん面倒になってきたのでこのくらいでソースコードの整理は終わりにした。

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

前の10件 5  6  7  8  9  10  11  12  13  14  15