![]()
前回は「お気に入り」メニューをIShellMenuベースに置き換えた。今回はIShellMenu用のコールバックインターフェースを用意して、選択した「お気に入り」がビューで開くようにする。
//■追加
//IEツールバーをホストするためのインターフェース
MIDL_INTERFACE("50AFAFED-815E-4ec4-9A78-231C95958716")
IShellMenuHost : public IUnknown
{
public:
STDMETHOD (put_IShellFolder)(IShellFolder* pIShellFolder) = 0;
STDMETHOD (put_NotifyWindow)(HWND hWnd,UINT nMessageID) = 0;
};
//■追加
class CShellMenuCallback :
public CComObjectRootEx<CComSingleThreadModel>
,public IShellMenuHost
,public IShellMenuCallback
{
UINT _nNotifyMessage;
HWND _hWndNotify;
CComPtr<IShellFolder> _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->QueryInterface(IID_IShellFolder,(void**)&_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->dwMask & SMIM_FLAGS)
pSmInfo->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->pidlItem,pszFile);
::SHGetPathFromIDList(psmd->pidlFolder,pszPath);
strName = pszFile;
nFind = strName.ReverseFind(_T('\\'));
if(nFind >= 0)
strName = strName.Right(strName.GetLength() - nFind);
strName = pszPath + strName;
//ウインドウへメッセージを送る
if(*pszPath && _hWndNotify && ::IsWindow(_hWndNotify) && _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;
}
};
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<CMainFrame>)
CHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>)
END_MSG_MAP()
//■追加
LRESULT OnDnpNavigateFavorite(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& 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("about:blank"),NULL);
}
//URLを開く
if(pView)
pView->Navigate(strURL);
}
return 0;
}
bool PopupMenu(int nX,int nY)
{
LPITEMIDLIST pidl;
CComPtr<IShellFolder> pIShellFolder;
if(_pIMenuBand)
{
//すでにメニューが開いていたら、まずはそのメニューを閉じる
CComPtr<IOleCommandTarget> pIOleCommandTarget;
_pIMenuBand->QueryInterface(&pIOleCommandTarget);
if(pIOleCommandTarget)
pIOleCommandTarget->Exec(&CLSID_MenuBand,22,0,NULL,NULL);
}
//「お気に入り」フォルダのPIDLとIShellFolderを取得
{
CComPtr<IShellFolder> pIShellFolderDesktop;
::SHGetDesktopFolder(&pIShellFolderDesktop);
if(pIShellFolderDesktop == NULL)
return false;
::SHGetSpecialFolderLocation(NULL,CSIDL_FAVORITES,&pidl);
pIShellFolderDesktop->BindToObject(pidl,NULL,IID_IShellFolder,(void **)&pIShellFolder);
}
CComPtr<IDeskBand> pIDeskBand;
//PIDLとIShellFolderの示すIShellMenu(IDeskBand)を取得
{
HRESULT hr;
CRegKey cRegOrder;
CComPtr<IShellMenu> pIShellMenu;
CComPtr<IDeskBar> pIDeskBar;
CComPtr<IMenuPopup> pIMenuPopup;
//並び順用レジストリ。必要ならCreateしてもいいが今回は「お気に入り」のみなのでopen
cRegOrder.Open(HKEY_CURRENT_USER,_T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MenuOrder\\Favorites"));
::CoCreateInstance(CLSID_MenuBand,NULL,CLSCTX_INPROC_SERVER,IID_IShellMenu,(void**)&pIShellMenu);
//■処理変更
if(pIShellMenu)
{
CComPtr<IShellMenuHost> pIShellMenuHost;
CComPtr<IShellMenuCallback> pIShellMenuCallback;
//コールバック生成
pIShellMenuCallback = new CComObject<CShellMenuCallback>;
if(pIShellMenuCallback)
pIShellMenuCallback->QueryInterface(&pIShellMenuHost);
if(pIShellMenuHost)
{
pIShellMenuHost->put_IShellFolder(pIShellFolder);
pIShellMenuHost->put_NotifyWindow(m_hWnd,WM_DNP_NAVIGATEFAVORITE);
}
//IShellMenuの初期化
pIShellMenu->Initialize(pIShellMenuCallback,-1,ANCESTORDEFAULT,SMINIT_TOPLEVEL | SMINIT_VERTICAL);
#ifndef SMSET_USEBKICONEXTRACTION
#define SMSET_USEBKICONEXTRACTION 0x00000008
#endif
//メニューへのフォルダ割り当て
hr = pIShellMenu->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->QueryInterface(&pIMenuPopup);
if(pIMenuPopup)
pIMenuPopup->QueryInterface(&pIDeskBar);
if(pIDeskBar)
pIDeskBar->QueryInterface(&pIDeskBand);
if(pIDeskBand == NULL)
return false;
}
//IShellMenu(IDeskBand)をポップアップメニューで表示
{
POINTL ptl;
GUID rclsid;
CComPtr<IUnknown> pIUnknown;
CComPtr<IBandSite> pIBandSite;
CComPtr<IMenuPopup> pIMenuPopup;
//メニュー用のDeskBar「Menu Desk Bar」
::CLSIDFromString(L"{ECD4FC4F-521C-11D0-B792-00A0C90312E1}",&rclsid);
::CoCreateInstance(rclsid,NULL,CLSCTX_INPROC_SERVER,IID_IUnknown,(void**)&pIUnknown);
//メニュー用のBandSite
::CoCreateInstance(CLSID_MenuBandSite,NULL,CLSCTX_INPROC_SERVER,IID_IBandSite,(void**)&pIBandSite);
if(pIUnknown)
pIUnknown->QueryInterface(&pIMenuPopup); //メニュー用DeskBarだからIMenuPopupを持っている
if(pIMenuPopup)
pIMenuPopup->SetClient(pIBandSite); //DeskBarにIBandSiteを割り当て
if(pIBandSite)
pIBandSite->AddBand(pIDeskBand); //IBandSiteに表示したいIShellMenuを割り当てる
//位置を指定してメニュー表示
ptl.x = nX;
ptl.y = nY;
if(pIMenuPopup)
pIMenuPopup->Popup(&ptl,NULL,MPPF_POS_MASK | MPPF_FORCEZORDER | MPPF_RIGHT | MPPF_BOTTOM);
}
//メニューの_pIMenuBandを保存
{
_pIMenuBand = NULL;
pIDeskBand->QueryInterface(&_pIMenuBand);
if(_pIMenuBand == NULL)
return false;
}
return true;
}
#define WM_DNP_NAVIGATEFAVORITE (WM_APP + 13) //■追加
![]()
これで「お気に入り」を選択したときにそのURLがビューで開くようになった。また「お気に入り」の表示順序をドラッグアンドドロップにより変更できるようになった。
次回は少しフォーカス関連のバグ修正をする。
