第16回 「タブ」にアイコンを表示する (タブブラウザーを作る)

tabbrowser62.gif
今回は「タブ」にそのとき開いているホームページのアイコンを表示する。
WTLのCTabViewはCImageList(HIMAGELIST)を渡すことで画像を表示できるようにできている。その機能を利用して実装する。

前回までに作成したプロジェクトを開き、「MainFrm.h」にCImageListの作成/割り当て/破棄処理を追加する。
	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);

		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));

		//■2行追加 
		_cTabImageList.Create(16,16,ILC_COLOR | ILC_MASK,1,10);
		m_view.SetImageList(_cTabImageList);

		return 0;
	}


	CImageList	_cTabImageList;		//■追加 タブに表示するアイコン用イメージリスト


	LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
	{
		_cTabImageList.Destroy();		//■追加

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

		bHandled = FALSE;
		return 1;
	}

tabbrowser63.gif 次にビュー側で開いているホームページのアイコンを取得してタブに割り当てる処理を実装する。 まずはそのためのヘッダーファイルを追加する。
#include "intshcut.h"		//■追加

tabbrowser64.gif そして実際の処理を追加する。ここでは(かえって複雑になっているかもしれないが)簡単にするため、開いているURLのショートカットをテンポラリフォルダに一度作成し、そのショートカットからアイコンを取り出すという方法を採用した。
	//HTMLページが読み終わったときに呼ばれる処理
	void	_stdcall OnDocumentComplete(IDispatch* pDisp, VARIANT* vURL)
	{
		//■処理内容実装
		if(pDisp != _pIWebBrowser2)
			return;			//フレームなどの読み込み終了は無視

		HICON		hIcon;
		CAtlString	strFile;

		//テンポラリファイルパス取得
		{
			DWORD	dwRet;
			TCHAR	pszPath[MAX_PATH + 1024];
			TCHAR	pszFile[MAX_PATH + 1024];

			dwRet = ::GetTempPath(MAX_PATH + 1024,pszPath);				//テンポラリフォルダ取得
			if(dwRet)
				dwRet = ::GetTempFileName(pszPath,NULL,0,pszFile);		//テンポラリファイル名自動生成
			if(dwRet)
				strFile = pszFile;
			if(strFile == _T(""))
				return;
		}

		//インターネットショートカットファイル作成
		{
			bool	ret;

			strFile += _T(".url");
			ret = CreateInternetShortcut((CAtlString)vURL->bstrVal,strFile);
			if(ret == false)
				return;

			//インターネットショートカットにアイコンが適用されるのを待つ(//■■これだとダメ?要調査)
			::SHChangeNotify(SHCNE_CREATE,SHCNF_PATH | SHCNF_FLUSH,(LPCTSTR)strFile,NULL);
		}

		//ファイルからHICONを取得
		{
			SHFILEINFO	sShFileInfo;
			HIMAGELIST	hImageList;

			//パスからアイコン取得
			hImageList = (HIMAGELIST)::SHGetFileInfo(strFile,0,&sShFileInfo,sizeof(SHFILEINFO),SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
			hIcon = ::ImageList_GetIcon(hImageList,sShFileInfo.iIcon,ILD_NORMAL);
			::ImageList_Destroy(hImageList);
		}
		::remove((CAtlStringA)strFile);		//ファイル削除
		if(hIcon == NULL)
			return;

		//タブにHICONを割り当てる
		{
			int			nPage;
			int			nImage;
			CImageList	cImageList;

			nPage = _pTabView->PageIndexFromHwnd(m_hWnd);
			cImageList = _pTabView->GetImageList();			//タブのイメージリスト取得

			nImage = _pTabView->GetPageImage(nPage);		//現在のイメージ番号取得
			if(nImage < 0)
			{
				//タブに画像がなければ新しく追加して使う
				nImage = cImageList.AddIcon(hIcon);
			}
			else
			{
				//タブに画像があればそれと置き換える
				cImageList.ReplaceIcon(nImage,hIcon);
			}
			_pTabView->SetPageImage(nPage,nImage);		//nImageが変わらなくても再描画のためにセットしなおす
		}
		::DestroyIcon(hIcon);
	}


	//■追加
	//インターネットショートカットの作成
	//pszFileNameは必ず拡張子を.urlにすること!
	bool	CreateInternetShortcut(LPCTSTR pszURL, LPCTSTR pszFileName)
	{
		HRESULT	hr;

		CComPtr<IUniformResourceLocator>	pIUniformResourceLocator;
		CComPtr<IPersistFile>				pIPersistFile;

		::CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER,IID_IUniformResourceLocator,(void**)&pIUniformResourceLocator);
		if(pIUniformResourceLocator == NULL)
			return	false;

		pIUniformResourceLocator->QueryInterface(IID_IPersistFile,(void**)&pIPersistFile);
		if(pIPersistFile == NULL)
			return	false;

		hr = pIUniformResourceLocator->SetURL((CAtlStringW)pszURL,0);

		if(SUCCEEDED(hr))
			hr = pIPersistFile->Save((CAtlStringW)pszFileName,TRUE);

		return	SUCCEEDED(hr) ? true : false;
	}

tabbrowser65.gif
これでタブにアイコンが表示されるようになった。しかしアイコンの設定がOnDocumentComplete内だけのためほかのページを開いている最中にも前のホームページのアイコンが表示されていたり、きちんとアイコンが取得できないホームページがあったりする。それらの点は今後修正することにして今は保留しておく。

さすがにここまで来るとソースコードが分かりにくくなってきたので、次回は重い腰を上げてソースコードの整理をする。

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


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