![]()
次はタブブラウザーに「お気に入り」の選択機能を実装する。一般的に出回っているタブブラウザーの中には独自形式の「お気に入り」を実装しているものもある。独自形式の方が機能追加などが柔軟にでき便利だ。
しかしここでは多機能で一般的に使えるタブブラウザーの開発を目指しているわけでもないので独自形式は避け、Internet Explorerの「お気に入り」を利用する。
前回までに作成した作成したプロジェクトで「リソース」ウインドウを開き、ウインドウフレーム用メニューに「お気に入り」とその下に「dummy」の項目を追加する。
「dummy」のIDは「ID_FAVORITE_DUMMY」とした。この項目は「お気に入り」メニューの場所を特定するために利用するだけで実際にメニューを表示するときには削除する。
![]()
メニューリソースの編集が終わったら一度保存するために「ファイル」メニューの「すべてを保存」を選択する。
![]()
次にソリューションウインドウにある「resource.h」をダブルクリックして開く。このときに警告が出るが、「OK」ボタンを押し警告は無視する。そしてここに2行追加する。
#define ID_FAVORITE_FIRST 34000 //お気に入りは全部で2万アイテムまでサポート #define ID_FAVORITE_LAST 54000 //
![]()
次にソリューションウインドウの「MainFrm.ht」を開き、お気に入りメニュー用のクラスを追加する。
#include "DnpFolderMenu.h" //■追加
#include "shlwapi.h" //■追加
#pragma comment(lib,"shlwapi.lib") //■追加
//■追加
//「お気に入り」メニュークラス
class CFavoritesMenu : public CDnpFolderMenu
{
public:
BEGIN_MSG_MAP(CFavoritesMenu)
CHAIN_MSG_MAP(CDnpFolderMenu)
END_MSG_MAP()
protected:
///
///\brief
/// メニューに表示する文字列の設定
///
///ファイル名とパス(フォルダー名とパス)を参考にメニューにする文字列を決める。
///
///falseを返すとそのアイテムは表示しない
///
virtual bool TranslateMenuString(LPCTSTR pszPath,LPCTSTR pszFileName,CAtlString& strMenuString,bool bFolder)
{
//フォルダはフォルダ名をそのまま表示名として使う
if(bFolder)
{
strMenuString = pszFileName;
return true;
}
//ファイルはインターネットショートカット(拡張子が.url)なら拡張子を除いたファイル名を表示
//それ以外の拡張子のファイルはfalseを返して非表示にする
LPTSTR pszExt;
strMenuString = pszFileName;
pszExt = ::PathFindExtension(strMenuString.GetBuffer(0)); //拡張子の開始ポインタ取得
if(pszExt == NULL)
return false;
if(::_tcsicmp(pszExt,_T(".url")) != 0)
return false; //拡張子が.urlではなかった
*pszExt = NULL; //拡張子を消す
return true;
}
};
メニューが開いたことを知らせる「WM_MENUSELECT」を検出して開いたメニュー項目の最初に「ID_FAVORITE_DUMMY」があれば「お気に入り」用のメニューと判断して処理している。
ユーザーによって異なる「お気に入り」フォルダの取得には「OSに関係なく特殊フォルダのパスを取得する」で作成したSafeSHGetSpecialFolderPathを利用した。
BEGIN_MSG_MAP(CMainFrame)
MESSAGE_HANDLER(WM_DNP_CHANGEFOCUS, OnDnpChangeFocus)
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)
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()
CFavoritesMenu _cFovMenu; //■追加 「お気に入り」メニュー用クラス
//■追加
//メニューを開いたときに呼ばれる処理
//「お気に入り」が最初に開いたときだけ、ウインドウメニューと_cFovMenuを関連付ける
LRESULT OnMenuSelect(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
int nMenuIndex = LOWORD(wParam);
int nFlag = HIWORD(wParam);
BOOL ret;
HMENU hMenu = (HMENU)lParam;
HMENU hSubMenu;
TCHAR pszPath[MAX_PATH + 100];
bHandled = FALSE;
if(!(nFlag & MF_POPUP))
return 0;
hSubMenu = ::GetSubMenu(hMenu,nMenuIndex);
if(hSubMenu == NULL)
return 0;
//「お気に入り」のメニューが開いたかどうかをチェック
//「お気に入り」は一つ目のメニューをID_FAVORITE_DUMMYとした
if(::GetMenuItemCount(hSubMenu) == 0 || ::GetMenuItemID(hSubMenu,0) != ID_FAVORITE_DUMMY)
return 0;
//「お気に入り」フォルダ取得
ret = SafeSHGetSpecialFolderPath(m_hWnd,pszPath,CSIDL_FAVORITES,FALSE);
if(ret == FALSE)
return 0;
//もうダミー項目は必要ないから削除
::RemoveMenu(hSubMenu,ID_FAVORITE_DUMMY,MF_BYCOMMAND);
//ウインドウメニューへ「お気に入り」を関連付ける
_cFovMenu.ShowMenu(pszPath,hSubMenu,ID_FAVORITE_FIRST);
return 0;
}
//■追加
//「お気に入り」が選択されたときの処理
LRESULT OnFavorite(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
CAtlString strFolder;
CAtlString strFile;
_cFovMenu.GetPathFromID(wID,strFolder,strFile);
//選択されたお気に入りのファイル名をメッセージボックスで表示
MessageBox(strFile);
return 0;
}
//■追加
// SHGetSpecialFolderPathの全プラットフォーム対応バージョン
//
//「OSに関係なく特殊フォルダのパスを取得する」
//http://www.usefullcode.net/2006/12/os.html
//
BOOL SafeSHGetSpecialFolderPath(HWND hwndOwner,LPTSTR lpszPath,int nFolder,BOOL fCreate)
{
BOOL (CALLBACK* g_pfnSHGetSpecialFolderPath)(HWND,LPTSTR,int,BOOL);
HRESULT (CALLBACK* g_pfnSHGetFolderPath)(HWND,int,HANDLE,DWORD,LPTSTR);
int i;
BOOL ret;
HRESULT hr;
HMODULE hDLL;
TCHAR pszDllFile[][15] = {_T("shfolder.dll"),_T("shell32.dll")};
if(lpszPath == NULL)
return FALSE;
*lpszPath = NULL;
ret = FALSE;
for(i = 0; i < 2; i++)
{
hDLL = ::LoadLibrary(pszDllFile[i]);
if(hDLL == NULL)
continue;
#ifdef UNICODE
(*(FARPROC*)&g_pfnSHGetSpecialFolderPath = ::GetProcAddress(hDLL,"SHGetSpecialFolderPathW"));
(*(FARPROC*)&g_pfnSHGetFolderPath = ::GetProcAddress(hDLL,"SHGetFolderPathW"));
#else
(*(FARPROC*)&g_pfnSHGetSpecialFolderPath = ::GetProcAddress(hDLL,"SHGetSpecialFolderPathA"));
(*(FARPROC*)&g_pfnSHGetFolderPath = ::GetProcAddress(hDLL,"SHGetFolderPathA"));
#endif
if(g_pfnSHGetSpecialFolderPath)
ret = g_pfnSHGetSpecialFolderPath(hwndOwner,lpszPath,nFolder,fCreate);
if(ret == FALSE && g_pfnSHGetFolderPath)
{
hr = g_pfnSHGetFolderPath(hwndOwner,nFolder | (fCreate ? CSIDL_FLAG_CREATE : 0),NULL,SHGFP_TYPE_DEFAULT,lpszPath);
ret = (SUCCEEDED(hr)) ? TRUE : FALSE;
}
::FreeLibrary(hDLL);
if(ret)
return TRUE;
}
return FALSE;
}
![]()
さらにプロジェクトに「DnpFolderMenu.h」を追加する。
「プロジェクト」メニューから「既存項目に追加」を選択する。
※「DnpFolderMenu.h」はこのホームページの中の「フォルダー構造をそのままメニューとして表示する」からダウンロードできます。またダウンロードできるプロジェクト内にも同梱しています

そして「DnpFolderMenu.h」を選択して「追加」ボタンを押す。
![]()
これでビルド/実行するとInternet Explorerで登録した「お気に入り」がメニューとして表示された。
この「お気に入り」は表示順序がInternet Explorerとは異なり、アイコンも表示されないし、追加や整理する機能もない。それらは今後少しづつ実装する。
次回は選択された「お気に入り」を実際にタブとして開く動作を追加する。
