前の10件 2  3  4  5  6  7  8  9  10  11  12

記事一覧

第7回 IEコントロールの履歴を調べて「戻る」の状態を切り替える (タブブラウザーを作る)

tabbrowser26.gif
前回までにWTLのタブビューをひな形にアドレスバーや「戻る」「進む」ボタンなどを実装することでだんだんタブブラウザが形になってきた。

今回はIEコントロールから履歴情報を取り出して、「戻る」「進む」ボタンの有効/無効を自動的に切り換える処理を追加する。

前回までに作成したプロジェクトのソリューションウインドウにある「TabBrowser100View.h」をダブルクリックしてビュークラスの編集画面を開く。

IEコントロールからの履歴取得はITravelLogStgを利用する。そのためのinclude定義を追加する。
#include "tlogstg.h"		//■追加 IE5.5以上

tabbrowser27.gif 次に同じビュークラスの中にIEコントロールの履歴があるかどうかを返す関数を追加する。 ここれでは履歴が1つ以上あればbBackやbNextをtrueにすることで履歴情報を返している。
	//■追加
	//「戻る」や「進む」ための履歴が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;
	}

tabbrowser28.gif
次に「MainFrm.h」を開き、ツールバーのボタン状態の有効/無効を、ビュークラスに実装したIsButtonEnableの結果をみて切りかえる処理を実装する。

本来であればIEコントロールがURLを読み込んだことを検出してボタン情報を切り替えた方が効率がいい。しかしここでは実装を簡単にするため、アイドル処理のためのOnIdle()でボタンの有効/無効を切り替えることにした。
	virtual BOOL OnIdle()
	{
		//■追加
		//「戻る」「進む」ボタンの状態設定
		{
			bool	ret;
			int		nPage;
			CTabBrowser100View*	pView = NULL;

			ret = false;
			nPage = m_view.GetActivePage();
			if(nPage >= 0)
				pView = (CTabBrowser100View*)m_view.GetPageData(nPage);
			if(pView)
			{
				bool	bBack;
				bool	bNext;

				ret = pView->IsButtonEnable(bBack,bNext);
				if(ret)
				{
					UIEnable(ID_IE_BACK,bBack ? TRUE : FALSE);
					UIEnable(ID_IE_NEXT,bNext ? TRUE : FALSE);
				}
			}
			if(ret == false)
			{
				UIEnable(ID_IE_BACK,FALSE);
				UIEnable(ID_IE_NEXT,FALSE);
			}
		}

		UIUpdateToolBar();
		return FALSE;
	}

	BEGIN_UPDATE_UI_MAP(CMainFrame)
		UPDATE_ELEMENT(ID_VIEW_TOOLBAR, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_VIEW_STATUS_BAR, UPDUI_MENUPOPUP)
		UPDATE_ELEMENT(ID_IE_BACK, UPDUI_TOOLBAR)			//■追加
		UPDATE_ELEMENT(ID_IE_NEXT, UPDUI_TOOLBAR)			//■追加
	END_UPDATE_UI_MAP()

tabbrowser29.gif
これでビルド/実行すると、「戻る」と「進む」ボタンの有効/無効が自動的に切り替わるようになった。

次回は今まで保留していたアドレスバーで[BackSpace]キーなどが使えない点を修正する。

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

第6回 タブブラウザーに「戻る」や「進む」ボタンを配置する (タブブラウザーを作る)

tabbrowser21.gif
前回までにアドレスバーの実装やリンクを新しいタブで開く機能の実装などにより、タブブラウザーとしてそれらしく動作するようになってきた。今回は「戻る」「進む」「更新」「中止」ボタンをツールバーに作る。

前回までに作成したプロジェクトを開く。まずはツールバーにボタンを追加するため、リソースビューの「Toolbar」にある「IDR_MAINFRAME」をダブルクリックしてツールバーリソースを開いて、ボタンを4つ追加する。

tabbrowser22.gif
さらに「プロパティ」ウインドウを開き、新しく作成したボタンのIDを設定する。ここでは
「戻る」ボタンは「ID_IE_BACK」
「進む」ボタンは「ID_IE_NEXT」
「中止」ボタンは「ID_IE_STOP」
「更新」ボタンは「ID_IE_REFRESH」
とした。これでツールバーリソースに関する設定は終わりだ。

tabbrowser23.gif 次にソースコードを編集する。ソリューションウインドウで「TabBrowser100View.h」をダブルクリックしてビュークラスの編集画面を開く。そしてここにIWebBrowser2::GoBack()を呼びだして「戻る」ための関数などを追加する。
	//■追加
	void	Back(void)
	{
		if(_pIWebBrowser2)
			_pIWebBrowser2->GoBack();
	}

	//■追加
	void	Next(void)
	{
		if(_pIWebBrowser2)
			_pIWebBrowser2->GoForward();
	}

	//■追加
	void	Stop(void)
	{
		if(_pIWebBrowser2)
			_pIWebBrowser2->Stop();
	}

	//■追加
	void	Refresh(void)
	{
		if(_pIWebBrowser2)
			_pIWebBrowser2->Refresh2(&CComVariant(REFRESH_COMPLETELY));
	}

tabbrowser24.gif 次に「MainFrm.h」を開き、ツールバーのボタンが押されたときに実行されるメッセージハンドラを追加する。通常のMDIであればFrame -> Viewの順にWM_COMMANDが届くためメッセージハンドらを直接ビューに書くが、CTabViewになっているため直接ビューには届かないため今回はMainFrm.h内に実装した。
	BEGIN_MSG_MAP(CMainFrame)
		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)		//■追加
		CHAIN_MSG_MAP(CUpdateUI<CMainFrame>)
		CHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>)
	END_MSG_MAP()


	//■追加
	//「戻る」「進む」などのIEコマンド処理
	LRESULT OnIECommand(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
	{
		int		nPage;
		CTabBrowser100View*	pView;

		nPage = m_view.GetActivePage();
		if(nPage < 0)
			return	0;		//アクティブなタブがない

		pView = (CTabBrowser100View*)m_view.GetPageData(nPage);
		if(pView == NULL)
			return	0;		//ビューが取得できなかった

		switch(wID)
		{
		case	ID_IE_BACK:	//戻る
			pView->Back();
			break;

		case	ID_IE_NEXT:	//進む
			pView->Next();
			break;

		case	ID_IE_STOP:	//ストップ
			pView->Stop();
			break;

		case	ID_IE_REFRESH:	//更新
			pView->Refresh();
			break;
		}

		return	0;
	}

tabbrowser25.gif
これでビルド/実行すると、ツールバーに「戻る」や「進む」などのボタンが現れ、実際に「戻る」などの操作ができた。

今回作成した「戻る」「進む」ボタンは常に押せる状態にある。次回はIEコントロールから履歴を取り出して、「戻る」ことができるときだけ「戻る」ボタンを有効になるようにする。

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

2009年04月01日

第5回 新しいタブでリンクを開く (タブブラウザーを作る)

tabbrowser19.gif
前回までにタブブラウザー用のプロジェクトを作成し、アドレスバーの作成やタブにホームページ名が表示されるようにした。

今回はリンクを右クリックして現われるメニューから「新しいウインドウで開く」を選択したときに、そのリンクを新しいタブとして開くようにする。

前回までに作成したプロジェクトを開く。そしてソリューションウインドウにある「TabBrowser100View.h」をダブルクリックしてビュークラスの編集画面を開く。そして2箇所追加する。

IEコントロールでは新しいウインドウで開く直前にDISPID_NEWWINDOW2というイベントが発生する。それを検出したら、新しいタブを作りそこにあるIEコントロールのIDispatchを返せばInternet Explorerではなく「タブ」でリンクが開くようになる。
	BEGIN_SINK_MAP(CTabBrowser100View)
		SINK_ENTRY_EX(SINKID_EVENTS, DIID_DWebBrowserEvents2, DISPID_NEWWINDOW2, OnNewWindow2)		//■追加
		SINK_ENTRY_EX(SINKID_EVENTS, DIID_DWebBrowserEvents2, DISPID_DOCUMENTCOMPLETE, OnDocumentComplete)
	END_SINK_MAP()


	//■追加
	//新しいウインドウで開く前に呼ばれる処理
	//新しいタブで開く
	void	__stdcall OnNewWindow2(IDispatch **ppDisp,VARIANT_BOOL *Cancel)
	{
		//新しいタブを作る
		CTabBrowser100View* pView = new CTabBrowser100View(_pTabView);	//タブビューのポインタを渡しておく
		pView->Create(*_pTabView, rcDefault, _T("about:blank"), WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_HSCROLL | WS_VSCROLL, 0);
		_pTabView->AddPage(pView->m_hWnd, _T("Document"),-1,pView);
		if(pView->_pIWebBrowser2 == NULL)
			return;

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

tabbrowser20.gif
これでビルド/実行し、リンクを右クリックして「新しいウインドウで開く」を選択すると新しいタブで開いた。

次回は「戻る」と「進む」ボタンを実装する。

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

第4回 「タブ」にホームページの名前を表示する (タブブラウザーを作る)

tabbrowser14.gif
前回までにタブブラウザー用のプロジェクトを作成し、手動でURLを入力できるようにアドレスバーを実装した。今回はアクセスしたURLのホームページ名が「タブ」に表示されるようにする。

前回までに作成したプロジェクトを開く。そしてソリューションウインドウにある「TabBrowser100View.h」をダブルクリックしてビュークラスの編集画面を開く。そしてまず4箇所ソースコードを追加する。
#include "atlstr.h"				//■追加
#include "Exdispid.h"			//■追加

#define SINKID_EVENTS 0			//■追加

class CTabBrowser100View : public CWindowImpl<CTabBrowser100View, CAxWindow>
	,public IDispEventImpl<SINKID_EVENTS, CTabBrowser100View, &DIID_DWebBrowserEvents2>		//■追加
{
	CTabView*	_pTabView;		//■追加 タブビューを保持
public:
	DECLARE_WND_SUPERCLASS(NULL, CAxWindow::GetWndClassName())

	//■追加
	CTabBrowser100View(CTabView* pTabView)
	{
		_pTabView = pTabView;
	}


	BOOL PreTranslateMessage(MSG* pMsg)
	{
		if((pMsg->message < WM_KEYFIRST || pMsg->message > WM_KEYLAST) &&
		   (pMsg->message < WM_MOUSEFIRST || pMsg->message > WM_MOUSELAST))
			return FALSE;

		// このメッセージを翻訳する機会をHTML ページに与える
		return (BOOL)SendMessage(WM_FORWARDMSG, 0, (LPARAM)pMsg);
	}

	BEGIN_MSG_MAP(CTabBrowser100View)
		MESSAGE_HANDLER(WM_DESTROY, OnDestroy)		//■追加
	END_MSG_MAP()

tabbrowser15.gif さらに開いたURLが読み込まれたときに呼ばれる処理を追加する。 ここではDISPID_DOCUMENTCOMPLETEを受信したときにタブにホームページの名前を表示するようにした。通常のタブブラウザーの場合はほかのイベントが届いたときにも書き換える処理をしている。しかし処理が煩雑になるため今回は省略した。
	//■以下3行追加
	BEGIN_SINK_MAP(CTabBrowser100View)
		SINK_ENTRY_EX(SINKID_EVENTS, DIID_DWebBrowserEvents2, DISPID_DOCUMENTCOMPLETE, OnDocumentComplete)
	END_SINK_MAP()

	//■関数追加
	//HTMLページが読み終わったときに呼ばれる処理
	void	_stdcall OnDocumentComplete(IDispatch* pDisp, VARIANT* URL)
	{
		bool	ret;

		ret = GetBrowserCtrl();
		if(ret == false)
			return;

		//タブに表示されている名前を変更
		if(_pTabView)
		{
			int			nPage;
			CComBSTR	bstr;
			CAtlString	strName;

			_pIWebBrowser2->get_LocationName(&bstr);		//現在のホームページ名を取得
			strName = bstr;

			nPage = _pTabView->PageIndexFromHwnd(m_hWnd);	//このウインドウに関連づいているタブのインデックス取得
			_pTabView->SetPageTitle(nPage,strName);			//タブの名前を変更
		}
	}

tabbrowser16.gif さらにIEコントロールからのイベントを受信できるように接続処理と、終了時のためにその切断処理を実装する。 本来であればIWebBrowser2を取得したとき、、、この場合はGetBrowserCtrl()内でIEへの接続を行った方がいいが、今回はCreateの中のままにしておく。
	//■追加
	//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)
	{
		bool	ret;
		HWND	hWnd;

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

		ret = GetBrowserCtrl();
		if(ret == false)
			return	hWnd;			//WebBrowser取得失敗

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

		return	hWnd;
	}


	//■追加
	//ビューを閉じるときの処理
	LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		bHandled = FALSE;

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

		return	0;
	}

tabbrowser17.gif 次に「MainFrm.h」を開き、OnFileNew()の中にあるビューの生成時にCTabViewへのポインタを渡すようにする。
	LRESULT OnFileNew(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
	{
		CTabBrowser100View* pView = new CTabBrowser100View(&m_view);	//■変更 ビューのポインタを渡しておく
		//TODO: 必要に応じてURLを書き換えてください。
		pView->Create(m_view, rcDefault, _T("http://www.usefullcode.net/"), WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_HSCROLL | WS_VSCROLL, 0);
		m_view.AddPage(pView->m_hWnd, _T("Document"),-1,pView);

		// TODO: ドキュメント初期化コードの追加

		return 0;
	}

tabbrowser18.gif
以上によりビルド/実行すると、開いたホームページの名前がタブに表示されるようになった。

次回は右クリックして現われるメニューから「新しいウインドウで開く」を選択した場合に、Internet Explorerが起動するのではなく、新しいタブでURLが開くようにする。

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

第3回 アドレスバーを作る(その2) (タブブラウザーを作る)

tabbrowser10.gif
前回はウインドウのツールバー領域にアドレスバー用のコンボボックスを配置した。今回はそのアドレスバーに入力されたURLを実際にビュー内で開く。

まずはビュー内でURLを簡単に開けるようにユーティリティ的な関数を実装する。前回までに作成したプロジェクトで、ソリューションウインドウにある「TabBrowser100View.h」をダブルクリックしてビュークラスの編集画面を開く。そしてここにURLを開くための関数などを追加する。

ここではQueryControlによりCAxWindowとして生成されたIEコントロールのIWebBrowser2を取得して_pIWebBrowser2に保持しておき、Navigate()ではIWebBrowser2::NavigateによりURLを開く。 これによりNavigate()を呼ぶことで指定されたURLをビュー内で開けるようになる。
	CComPtr<IWebBrowser2>		_pIWebBrowser2;		//■追加 このビューのブラウザーコントロールを保持 GetBrowserCtrl() によりこの変数に代入される

	//■関数追加
	//URLを開く
	bool	Navigate(LPCTSTR pszURL)
	{
		bool	ret;
		HRESULT	hr;

		ret = GetBrowserCtrl();
		if(ret == false)
			return	false;

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

		return	SUCCEEDED(hr) ? true : false;
	}

	//■関数追加
	//_pIWebBrowser2にこのビューに関連づいているIEをセットする
	bool	GetBrowserCtrl(void)
	{
		if(_pIWebBrowser2)
			return	true;

		QueryControl(&_pIWebBrowser2);

		return	_pIWebBrowser2 ? true : false;
	}

tabbrowser11.gif 次にソリューションウインドウの「MainFrm.h」をダブルクリックしてメインウインドウの編集画面を開く。 これは今回の作業で一番の肝となる項目だ。WTLのタブウインドウの実装方法はCTabViewImpl::AddPageにHWNDを渡す形となるため、一旦タブを作ってからビュークラスにアクセスするのが非常に煩雑になる。そのためここではタブの独自データ領域にビューへのポインタを格納しておくことで、簡単にビュークラスにアクセスできるようにした。
	LRESULT OnFileNew(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
	{
		CTabBrowser100View* pView = new CTabBrowser100View;
		//TODO: 必要に応じてURLを書き換えてください。
		pView->Create(m_view, rcDefault, _T("http://www.usefullcode.net/"), WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_HSCROLL | WS_VSCROLL, 0);
		m_view.AddPage(pView->m_hWnd, _T("Document"),-1,pView);		//■「,-1,pView」を追加

		// TODO: ドキュメント初期化コードの追加

		return 0;
	}

tabbrowser12.gif 最後にアドレスバー内で[Enter]キーを押されたときに入力されたURLを開くように実装する。前回は入力されたURLをメッセージボックスに表示した。その部分を先ほど作成したビューのNavigate()関数を呼ぶように変更する。
	//アドレスバーで[ENTER]キーが押されたときなどに呼ばれる
	LRESULT OnAddressbarEnter(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
	{
		bHandled = FALSE;

		NMCBEENDEDIT*	pNmCbEndEdit = (NMCBEENDEDIT*)pnmh;
		CAtlString		strURL;

		if(pNmCbEndEdit == NULL || pNmCbEndEdit->iWhy != CBENF_RETURN)
			return	0;			//[ENTER]キーが押されたとき以外はreturn

		_wndAddressBar.GetWindowText(strURL);
		if(strURL == _T(""))
			return	0;		//URLが入力されてなかった

		//■以下の処理を編集/追加
		int		nPage;
		CTabBrowser100View*	pView;

		nPage = m_view.GetActivePage();	//アクティブなタブのインデックス取得
		if(nPage < 0)
			return	0;		//アクティブなタブがない(=タブが1つもない->本来は自動で新しいタブを作るべき)

		pView = (CTabBrowser100View*)m_view.GetPageData(nPage);	//アクティブなタブの独自データを取得
		if(pView == NULL)
			return	0;		//予測外のエラー(ここに入ることはない)

		pView->Navigate(strURL);	//URLを開く

		return	0;
	}

tabbrowser13.gif
以上によりビルド/実行してアドレスバーにGoogleのURLを入れて[Enter]キーを押すと、Googleのホームページが開いた。
このままでは入力されたアドレスの履歴機能、現在開いているホームページのURL表示機能、「移動」ボタンなどなど実際のブラウザーのアドレスバーとしては機能が不十分だ。しかも致命的なことに[BackSpace]キーなどが利用できない。しかし今のところはこのままにしておく。

次回は「Document」となっているタブ表示を、開いているホームページ名が表示されるようにする。

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

第2回 アドレスバーを作る(その1) (タブブラウザーを作る)

tabbrowser06.gif
前回はタブブラウザーのひな形となるプロジェクトをATL/WTLプロジェクトウイザードにより自動生成した。今回はURLを手入力するための「アドレスバー」をウインドウに追加する。

前回のプロジェクトを開き、ソリューションウインドウにある「MainFrm.h」をダブルクリックして編集画面を開く。
そして、「MainFrm.h」にincludeファイル用の定義とアドレスバーとなるコンボボックスのメンバー変数を追加する。

#define WINDOW_MENU_POSITION	3

#include "atlmisc.h"					//■追加
#include "atlstr.h"						//■追加

class CMainFrame : public CFrameWindowImpl<CMainFrame>, public CUpdateUI<CMainFrame>,
		public CMessageFilter, public CIdleHandler
{
	CComboBoxEx	_wndAddressBar;			//■追加 アドレスバー用コンボボックス

public:
	DECLARE_FRAME_WND_CLASS(NULL, IDR_MAINFRAME)

tabbrowser07.gif 次に同じ「MainFrm.h」内にアドレスバー内で[Enter]キーが押されたことを検出して処理するためにメッセージマップにハンドラを追加し、対応した処理用の関数を追加する。 ここではコンボボックス編集終了の通知を示すWM_NOTIFYのCBEN_ENDEDITをとらえ、コンボボックスに入力されている文字をメッセージボックスに出力する処理を実装した(入力されたURLをブラウザで実際に開く処理は次回実装する)。
	BEGIN_MSG_MAP(CMainFrame)
		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)
		CHAIN_MSG_MAP(CUpdateUI<CMainFrame>)
		CHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>)
	END_MSG_MAP()


	//■関数追加
	//アドレスバーで[ENTER]キーが押されたときなどに呼ばれる
	LRESULT OnAddressbarEnter(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
	{
		bHandled = FALSE;

		NMCBEENDEDIT*	pNmCbEndEdit = (NMCBEENDEDIT*)pnmh;
		CAtlString		strURL;

		if(pNmCbEndEdit == NULL || pNmCbEndEdit->iWhy != CBENF_RETURN)
			return	0;			//[ENTER]キーが押されたとき以外はreturn

		_wndAddressBar.GetWindowText(strURL);
		if(strURL == _T(""))
			return	0;		//URLが入力されてなかった

		MessageBox(strURL);	//とりあえず入力されたURLをメッセージボックスで表示する

		return	0;
	}

tabbrowser08.gif 最後に同じく「MainFrm.h」のOnCreate()内にアドレスバーとなるコンボボッククスを生成してツールバーに配置するコードを追加する。ここではコンボボックスのスタイルをドロップダウン式のCBS_DROPDOWNを指定した。
		_wndAddressBar.Create(m_hWnd,CRect(0,0,200,200),0,WS_CHILD | WS_VISIBLE | CBS_DROPDOWN);	//■追加
		AddSimpleReBarBand(_wndAddressBar);											//■追加

tabbrowser09.gif
以上の追加をしてビルド/実行するとツールバーにアドレスバーとなるコンボボックスが配置された。そして文字を入力して[Enter]キーを押すとメッセージボックスとして出力できた。

次回はこのアドレスバーに入力された文字列(URL)をビューで開く実装をする。

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

第1回 VC++でタブブラウザー用プロジェクトを作る (タブブラウザーを作る)

tabbrowser01.gif
最新のWTL 8.0では標準でタブ切り替えのMDIがサポートされている。これを使うとこれまでは考えられなかったぐらい簡単にタブ切り替え型のアプリケーションを作れる。

今回から何回かにわたって例としてシンプルなタブブラウザーを作ってみる。

まずはVisual Studioで「ファイル」メニューにある「新規作成」から「プロジェクト」を選択して新しいプロジェクトを作成する。

tabbrowser02.gif
そしてプロジェクトの種類「WTL」から「ATL/WTLアプリケーションウイザード」を選択する。ここではプロジェクト名は「TabBrowser100」とした。

tabbrowser03.gif
ATL/WTLアプリケーションウイザードが開いたら左側の「アプリケーションの種類」タブで「タブ型ビューアプリケーション」を選択する。
これによりウイザードにより自動生成されるひな形のプロジェクトがタブ切り替え型のMDIとなる。

tabbrowser04.gif
さらに「ユーザーインターフェース機能」タブではビューウインドウの形式から「HTMLページ」を選択する。

tabbrowser05.gif
以上によりアプリケーションウイザードにより自動生成されたプロジェクトをビルド/実行すると画像のようになる。

すでにタブで切り替えできるブラウザーとなっているため、このままで普通にインターネット上のホームページを見ることができる。

とは言うもののアドレスバーがないのでURLを入力してアクセスすることはできないし、タブには「Document」と表示されてホームページ名も表示されない、リンクを新しいタブで開くこともできない。次回はこのプロジェクトに手動でURLを指定するためのアドレスバーを追加する。


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

IE8環境でVisual Studioがきちんと動くようにする

Internet Explorer 8をインストールすると、Visual Studio 2008が「Internet Explorer 8をインストールするとVisual Studioが正常に動かない!」にあるようにウイザードが動かなくなったりとかなり不便です。

その後、調べてみたら「Visual C++ Team Blog」の「Some VS2005 and VS2008 Wizards Pop Up Script Error.」にそのものずばりの解決方法がありました。

解決方法を参考に以下のようなregファイルを作成して、レジストリに書き込めばエラーなくウイザードが動作するようになりました(レジストリ書き込み後にVisual Studioのの再起動が必要)。
Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\1000]
@=""
"1207"=dword:00000000
regファイルをダウンロード

これでIE8環境でもVisual Studio 2008が完全に動作する。。。と言いたいところですが、私の環境ではHTMLファイルを開いたとき「デザイン」画面への切り替えができません。Visual StudioでHTMLファイルを編集することはないからいいのですが。。。

2009年03月31日

バージョン情報(バージョンリソース)を取得する

version.gif
EXEファイルやDLLファイルなどに含まれているバージョンリソースから情報を取り出すにはGetFileVersionInfoSize、GetFileVersionInfo、VerQueryValueの3つを利用する。

ファイルによってはバージョン情報リソースが複数の言語分だけ用意されていたり、ひとつもなかったりすることもある。ここではGetThreadLocaleで得られるロケールのリソースから取得を試みて、ダメならファイルにあるリソースから順番に取得した。


#include "DnpFileVersion.h"

void	Test()
{
	CDnpFileVersion	ver;
	CAtlString	str;

	ver.Load(_T("c:\\windows\\system32\\acw.exe"));
	ver.GetProductVersion(str);
	ver.Unload();

	::MessageBox(NULL,str,_T(""),MB_OK);
}


■「DnpFileVersion.h」の内容
#pragma	once


#include "atlstr.h"
#pragma	comment(lib,"Version.lib")


///
///\brief
///		バージョン情報リソース取得クラス
///
///■使用例
/**	\code
	bool	Test()
	{
		CAtlString		strData;
		CDnpFileVersion	cInfo;

		cInfo.Load("C:\\WINDOWS\\system32\\cmd.exe");
		cInfo.GetValue("FileDescription",strData);

		cInfo.GetComments(strData);
		cInfo.GetInternalName(strData);
		cInfo.GetProductName(strData);
		cInfo.GetCompanyName(strData);
		cInfo.GetLegalCopyright(strData);
		cInfo.GetProductVersion(strData);
		cInfo.GetFileDescription(strData);
		cInfo.GetLegalTrademarks(strData);
		cInfo.GetPrivateBuild(strData);
		cInfo.GetFileVersion(strData);
		cInfo.GetOriginalFilename(strData);
		cInfo.GetSpecialBuild(strData);

		return	true;
	}
	\endcode
*///
///
class	CDnpFileVersion
{
protected:

	///
	///\brief
	///		LCIDを展開するための構造体
	///
	struct LANGANDCODEPAGE
	{
	  WORD wLanguage;
	  WORD wCodePage;
	};


	BYTE*				_pVersionInfo;			//!< 保持しているバージョンリソース
	LANGANDCODEPAGE*	_pTranslation;			//!< コードページ情報配列
	UINT				_nTranslationLen;		//!< コードページ情報配列サイズ(要素数)
	UINT				_nTranslationDefault;	//!< デフォルトで用いるコードページ情報配列へのインデックス



public:
	CDnpFileVersion()
	{
		_pVersionInfo = NULL;
		_pTranslation = NULL;
		_nTranslationLen = 0;
		_nTranslationDefault = 0;
	}

	~CDnpFileVersion()
	{
		Unload();
	}


	///
	///\brief
	///		バージョン情報のロード
	///
	///このクラス内にバージョン情報を保持する
	///
	///\param[in]	pszFile
	///	バージョン情報を取得したファイルへのパス(EXEやDLLなど)
	///
	///\retval	true	成功
	///\retval	false	失敗
	///
	bool	Load(LPCTSTR pszFile)
	{
		BOOL	ret;
		DWORD	dwSize;
		BYTE*	pData;
		BYTE*	pResult;
		UINT	nLen;

		Unload();
		dwSize = ::GetFileVersionInfoSize(pszFile,NULL);
		if(dwSize == 0)
			return	false;

		pData = new BYTE[dwSize];
		if(pData == NULL)
			return	false;

		ret = ::GetFileVersionInfo(pszFile,NULL,dwSize,pData);

		if(ret)
			ret = ::VerQueryValue(pData,_T("\\VarFileInfo\\Translation"),(void**)&pResult,&nLen); 

		if(ret == FALSE)
		{
			delete	pData;
			return	false;
		}


		//デフォルトのコードページがみつかればそれを_nTranslationDefaultに保存しておく
		//
		///\todo
		///	//■■デフォルトLCIDが見つからなかったら、ニュートラル言語などほかのを取得しておくべき
		{
			UINT	i;
			LANGANDCODEPAGE*	pLcid;
			LCID	nCurr;

			pLcid = (LANGANDCODEPAGE*)pResult;
			nCurr = ::GetThreadLocale();
			for(i = 0; i < nLen / sizeof(LANGANDCODEPAGE); i++)
			{
				if(pLcid[i].wLanguage != nCurr)
					continue;

				_nTranslationDefault = i;
			}

		}

		_pVersionInfo = pData;
		_pTranslation = (LANGANDCODEPAGE*)pResult;
		_nTranslationLen = nLen / sizeof(LANGANDCODEPAGE);

		return	true;
	}



	///
	///\brief
	///		保持している情報の破棄
	///
	void	Unload(void)
	{
		if(_pVersionInfo)
			delete	_pVersionInfo;
		_pVersionInfo = NULL;
		_pTranslation = NULL;
		_nTranslationLen = 0;
		_nTranslationDefault = 0;
	}


	///
	///\brief
	///		バージョンリソースの項目を取得する
	///
	///\attention
	///	複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
	///最初に見つかったリソースから文字列を返す
	///
	///\param[in]	pszBlockName
	///	取得したいバージョンリソースの名前
	///
	///\param[out]	strValue
	///	取得した文字列
	///
	///\retval	true	取得成功
	///\retval	false	失敗
	///
	bool	GetValue(LPCTSTR pszBlockName,CAtlString& strValue)
	{
		UINT		i;
		BOOL		ret;
		UINT		nLen;
		BYTE*		pData;
		CAtlString	strPath;

		strValue = _T("");

		if(_pVersionInfo == NULL || _pTranslation == NULL || _nTranslationLen == 0)
			return	false;

		//最初にデフォルトロケールで探しておく(_nTranslationDefault==0ならどのみちforで最初に検索されるから問題なし)
		if(_nTranslationDefault)
		{
			i = _nTranslationDefault;
			strPath.Format(_T("\\StringFileInfo\\%04x%04x\\%s"),_pTranslation[i].wLanguage,_pTranslation[i].wCodePage,pszBlockName);
			ret = ::VerQueryValue(_pVersionInfo,strPath.GetBuffer(0),(void**)&pData,&nLen);
			if(ret)
			{
				strValue = (TCHAR*)pData;
				return	true;
			}
		}

		for(i = 0; i < _nTranslationLen; i++)
		{
			strPath.Format(_T("\\StringFileInfo\\%04x%04x\\%s"),_pTranslation[i].wLanguage,_pTranslation[i].wCodePage,pszBlockName);
			ret = ::VerQueryValue(_pVersionInfo,strPath.GetBuffer(0),(void**)&pData,&nLen);
			if(ret == FALSE)
				continue;

			strValue = (TCHAR*)pData;
			return	true;
		}

		return	false;
	}


	///
	///\brief
	///		バージョン情報の「Comments」を取得する
	///
	///\attention
	///	複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
	///最初に見つかったリソースから文字列を返す
	///
	///\param[out]	strValue
	///		取得した文字列
	///
	///\retval	true	取得成功
	///\retval	false	失敗
	///
	bool	GetComments(CAtlString& strValue)
	{
		return	GetValue(_T("Comments"),strValue);
	}



	///
	///\brief
	///		バージョン情報の「InternalName」を取得する
	///
	///\attention
	///	複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
	///最初に見つかったリソースから文字列を返す
	///
	///\param[out]	strValue
	///		取得した文字列
	///
	///\retval	true	取得成功
	///\retval	false	失敗
	///
	bool	GetInternalName(CAtlString& strValue)
	{
		return	GetValue(_T("InternalName"),strValue);
	}



	///
	///\brief
	///		バージョン情報の「ProductName」を取得する
	///
	///\attention
	///	複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
	///最初に見つかったリソースから文字列を返す
	///
	///\param[out]	strValue
	///		取得した文字列
	///
	///\retval	true	取得成功
	///\retval	false	失敗
	///
	bool	GetProductName(CAtlString& strValue)
	{
		return	GetValue(_T("ProductName"),strValue);
	}



	///
	///\brief
	///		バージョン情報の「CompanyName」を取得する
	///
	///\attention
	///	複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
	///最初に見つかったリソースから文字列を返す
	///
	///\param[out]	strValue
	///		取得した文字列
	///
	///\retval	true	取得成功
	///\retval	false	失敗
	///
	bool	GetCompanyName(CAtlString& strValue)
	{
		return	GetValue(_T("CompanyName"),strValue);
	}



	///
	///\brief
	///		バージョン情報の「LegalCopyright」を取得する
	///
	///\attention
	///	複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
	///最初に見つかったリソースから文字列を返す
	///
	///\param[out]	strValue
	///		取得した文字列
	///
	///\retval	true	取得成功
	///\retval	false	失敗
	///
	bool	GetLegalCopyright(CAtlString& strValue)
	{
		return	GetValue(_T("LegalCopyright"),strValue);
	}



	///
	///\brief
	///		バージョン情報の「ProductVersion」を取得する
	///
	///\attention
	///	複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
	///最初に見つかったリソースから文字列を返す
	///
	///\param[out]	strValue
	///		取得した文字列
	///
	///\retval	true	取得成功
	///\retval	false	失敗
	///
	bool	GetProductVersion(CAtlString& strValue)
	{
		return	GetValue(_T("ProductVersion"),strValue);
	}



	///
	///\brief
	///		バージョン情報の「FileDescription」を取得する
	///
	///\attention
	///	複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
	///最初に見つかったリソースから文字列を返す
	///
	///\param[out]	strValue
	///		取得した文字列
	///
	///\retval	true	取得成功
	///\retval	false	失敗
	///
	bool	GetFileDescription(CAtlString& strValue)
	{
		return	GetValue(_T("FileDescription"),strValue);
	}



	///
	///\brief
	///		バージョン情報の「LegalTrademarks」を取得する
	///
	///\attention
	///	複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
	///最初に見つかったリソースから文字列を返す
	///
	///\param[out]	strValue
	///		取得した文字列
	///
	///\retval	true	取得成功
	///\retval	false	失敗
	///
	bool	GetLegalTrademarks(CAtlString& strValue)
	{
		return	GetValue(_T("LegalTrademarks"),strValue);
	}



	///
	///\brief
	///		バージョン情報の「PrivateBuild」を取得する
	///
	///\attention
	///	複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
	///最初に見つかったリソースから文字列を返す
	///
	///\param[out]	strValue
	///		取得した文字列
	///
	///\retval	true	取得成功
	///\retval	false	失敗
	///
	bool	GetPrivateBuild(CAtlString& strValue)
	{
		return	GetValue(_T("PrivateBuild"),strValue);
	}



	///
	///\brief
	///		バージョン情報の「FileVersion」を取得する
	///
	///\attention
	///	複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
	///最初に見つかったリソースから文字列を返す
	///
	///\param[out]	strValue
	///		取得した文字列
	///
	///\retval	true	取得成功
	///\retval	false	失敗
	///
	bool	GetFileVersion(CAtlString& strValue)
	{
		return	GetValue(_T("FileVersion"),strValue);
	}



	///
	///\brief
	///		バージョン情報の「OriginalFilename」を取得する
	///
	///\attention
	///	複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
	///最初に見つかったリソースから文字列を返す
	///
	///\param[out]	strValue
	///		取得した文字列
	///
	///\retval	true	取得成功
	///\retval	false	失敗
	///
	bool	GetOriginalFilename(CAtlString& strValue)
	{
		return	GetValue(_T("OriginalFilename"),strValue);
	}



	///
	///\brief
	///		バージョン情報の「SpecialBuild」を取得する
	///
	///\attention
	///	複数のバージョンリソースがあった場合、デフォルトロケールを確認後、
	///最初に見つかったリソースから文字列を返す
	///
	///\param[out]	strValue
	///		取得した文字列
	///
	///\retval	true	取得成功
	///\retval	false	失敗
	///
	bool	GetSpecialBuild(CAtlString& strValue)
	{
		return	GetValue(_T("SpecialBuild"),strValue);
	}
};

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

Internet Explorer 8をインストールするとVisual Studioが正常に動かない!

ie8_vs2008.gif







以下の問題は解決しました。
IE8環境でVisual Studioがきちんと動くようにする





IE8をVisual Studio 2008の入っている開発環境にインストールすると、いくつかのウイザードで画像のようなエラーが出てしまう。

セキュリティ関連でIE7からIE8で挙動が変更された「アプリケーションと安全でないファイルの起動」の項目が怪しいと思うのだがどうしてもエラーを解消できず。

ネット上で情報を探してみると「HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones」や
「HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Lockdown_Zones」、
「HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\ProtocolDefaults」
の辺りを変更すればなんとかなる気もするがよく分からなかった。仕方がないので今はウイザードは使わずに手動でソースコードを生成しているので非常に不便。なんとかならないだろうか。。。


前の10件 2  3  4  5  6  7  8  9  10  11  12