[BROWSEUI] CBandSiteMenu: Implement the Desktop, Quick Launch and New Toolbar menu items

This commit is contained in:
Giannis Adamopoulos 2017-10-20 16:17:10 +03:00 committed by Giannis Adamopoulos
parent 0ed80264f9
commit 37e6151b40
2 changed files with 325 additions and 51 deletions

View File

@ -22,9 +22,20 @@
#include "shellbars.h"
#include <strsafe.h>
/* The menu consists of 3 parts. The first is loaded from the resources,
the second is populated with the classes of the CATID_DeskBand comcat
and the third part consists of the entries for each CISFBand in the band side.
The first 5 ids are reserved for the resource menu, the following ids will be
for the CATID_DeskBand classes and the rest for the CISFBands.
The ids for the CISFBand menu items are not continuous, in this range
each menu id is calculated by adding the band id to the last id for the CATID_DeskBand range */
#define FIRST_COMCAT_MENU_ID 0x5
CBandSiteMenu::CBandSiteMenu():
m_menuDsa(NULL),
m_hmenu(NULL)
m_comcatDsa(NULL),
m_hmenu(NULL),
m_DesktopPidl(NULL),
m_QLaunchPidl(NULL)
{
}
@ -33,14 +44,37 @@ CBandSiteMenu::~CBandSiteMenu()
if (m_hmenu)
DestroyMenu(m_hmenu);
if (m_menuDsa)
DSA_Destroy(m_menuDsa);
if (m_comcatDsa)
DSA_Destroy(m_comcatDsa);
if (m_DesktopPidl)
ILFree(m_DesktopPidl);
if (m_QLaunchPidl)
ILFree(m_QLaunchPidl);
m_BandSite = NULL;
}
HRESULT WINAPI CBandSiteMenu::FinalConstruct()
{
HRESULT hr = SHGetFolderLocation(0, CSIDL_DESKTOP, NULL, 0, &m_DesktopPidl);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
HRESULT CBandSiteMenu::CreateMenuPart()
WCHAR buffer[MAX_PATH];
hr = SHGetFolderPathAndSubDirW(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, L"Microsoft\\Internet Explorer\\Quick Launch", buffer);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
m_QLaunchPidl = ILCreateFromPathW(buffer);
if (m_QLaunchPidl == NULL)
return E_FAIL;
return S_OK;
}
HRESULT CBandSiteMenu::_CreateMenuPart()
{
WCHAR wszBandName[MAX_PATH];
WCHAR wszBandGUID[MAX_PATH];
@ -56,16 +90,16 @@ HRESULT CBandSiteMenu::CreateMenuPart()
if (m_hmenu)
DestroyMenu(m_hmenu);
if (m_menuDsa)
DSA_Destroy(m_menuDsa);
if (m_comcatDsa)
DSA_Destroy(m_comcatDsa);
/* Load the template we will fill in */
m_hmenu = LoadMenuW(GetModuleHandleW(L"browseui.dll"), MAKEINTRESOURCEW(IDM_TASKBAR_TOOLBARS));
if (!m_hmenu)
return HRESULT_FROM_WIN32(GetLastError());
m_menuDsa = DSA_Create(sizeof(GUID), 5);
if (!m_menuDsa)
m_comcatDsa = DSA_Create(sizeof(GUID), 5);
if (!m_comcatDsa)
return E_OUTOFMEMORY;
/* Get the handle of the submenu where the available items will be shown */
@ -94,8 +128,8 @@ HRESULT CBandSiteMenu::CreateMenuPart()
SHGetValue(HKEY_CLASSES_ROOT, wRegKey, NULL, NULL, wszBandName, &dwDataSize);
/* Insert it */
InsertMenu(hmenuToolbars, cBands, MF_BYPOSITION, DSA_GetItemCount(m_menuDsa), wszBandName);
DSA_AppendItem(m_menuDsa, &iter);
InsertMenu(hmenuToolbars, cBands, MF_BYPOSITION, DSA_GetItemCount(m_comcatDsa) + FIRST_COMCAT_MENU_ID, wszBandName);
DSA_AppendItem(m_comcatDsa, &iter);
cBands++;
}
while (dwRead > 0);
@ -103,12 +137,197 @@ HRESULT CBandSiteMenu::CreateMenuPart()
return S_OK;
}
HRESULT CBandSiteMenu::_CreateNewISFBand(HWND hwnd, REFIID riid, void** ppv)
{
WCHAR path[MAX_PATH];
WCHAR message[256];
BROWSEINFOW bi = { hwnd, NULL, path };
if (LoadStringW(GetModuleHandleW(L"browseui.dll"), IDS_BROWSEFORNEWTOOLAR, message, _countof(message)))
bi.lpszTitle = message;
else
bi.lpszTitle = L"Choose a folder";
LPITEMIDLIST pidlSelected = SHBrowseForFolderW(&bi);
if (pidlSelected == NULL)
return S_FALSE;
CComPtr<IShellFolderBand> pISFB;
HRESULT hr = CISFBand_CreateInstance(IID_IShellFolderBand, (PVOID*)&pISFB);
if (FAILED_UNEXPECTEDLY(hr))
goto done;
hr = pISFB->InitializeSFB(NULL, pidlSelected);
if (FAILED_UNEXPECTEDLY(hr))
goto done;
hr = pISFB->QueryInterface(riid, ppv);
done:
ILFree(pidlSelected);
return hr;
}
HRESULT CBandSiteMenu::_CreateBuiltInISFBand(UINT uID, REFIID riid, void** ppv)
{
LPITEMIDLIST pidl;
HRESULT hr;
pidl = (uID == IDM_TASKBAR_TOOLBARS_DESKTOP) ? m_DesktopPidl : m_QLaunchPidl;
CComPtr<IShellFolderBand> pISFB;
hr = CISFBand_CreateInstance(IID_IShellFolderBand, (PVOID*)&pISFB);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
hr = pISFB->InitializeSFB(NULL, pidl);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
return pISFB->QueryInterface(riid, ppv);
}
HRESULT CBandSiteMenu::_AddISFBandToMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, IUnknown* pBand, DWORD dwBandID, UINT *newMenuId)
{
CComPtr<IShellFolderBand> psfb;
HRESULT hr = pBand->QueryInterface(IID_PPV_ARG(IShellFolderBand, &psfb));
if (FAILED_UNEXPECTEDLY(hr))
return hr;
BANDINFOSFB bi = {ISFB_MASK_IDLIST};
hr = psfb->GetBandInfoSFB(&bi);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
if (!bi.pidl)
return E_OUTOFMEMORY;
WCHAR buffer[MAX_PATH];
hr = ILGetDisplayNameEx(NULL, bi.pidl, buffer, ILGDN_INFOLDER) ? S_OK : E_FAIL;
if (FAILED_UNEXPECTEDLY(hr))
return hr;
UINT id = idCmdFirst + DSA_GetItemCount(m_comcatDsa) + FIRST_COMCAT_MENU_ID + dwBandID;
if (id >= idCmdLast)
return E_FAIL;
*newMenuId = id;
InsertMenu(hmenu, indexMenu, MF_BYPOSITION, id, buffer);
return S_OK;
}
UINT CBandSiteMenu::_GetMenuIdFromISFBand(IUnknown *pBand)
{
UINT ret = UINT_MAX;
CComPtr<IShellFolderBand> psfb;
HRESULT hr = pBand->QueryInterface(IID_PPV_ARG(IShellFolderBand, &psfb));
if (FAILED_UNEXPECTEDLY(hr))
return ret;
BANDINFOSFB bi = {ISFB_MASK_IDLIST};
hr = psfb->GetBandInfoSFB(&bi);
if (FAILED_UNEXPECTEDLY(hr))
return ret;
CComPtr<IShellFolder> psfDesktop;
LPITEMIDLIST pidl = bi.pidl;
if (!pidl)
return ret;
if (pidl->mkid.cb == 0)
{
ret = IDM_TASKBAR_TOOLBARS_DESKTOP;
goto done;
}
hr = SHGetDesktopFolder(&psfDesktop);
if (FAILED_UNEXPECTEDLY(hr))
goto done;
hr = psfDesktop->CompareIDs(0, pidl, m_QLaunchPidl);
if (FAILED_UNEXPECTEDLY(hr))
goto done;
if (HRESULT_CODE(hr) == 0)
ret = IDM_TASKBAR_TOOLBARS_QUICKLAUNCH;
done:
if (pidl)
ILFree(pidl);
return ret;
}
UINT CBandSiteMenu::_GetMenuIdFromBand(CLSID *BandCLSID)
{
/* Try to find the clsid of the band in the dsa */
UINT count = DSA_GetItemCount(m_comcatDsa);
for (UINT i = 0; i < count; i++)
{
GUID* pdsaGUID = (GUID*)DSA_GetItemPtr(m_comcatDsa, i);
if (IsEqualGUID(*pdsaGUID, *BandCLSID))
{
/* The index in the dsa is also the index in the menu */
return i + FIRST_COMCAT_MENU_ID;
}
}
return UINT_MAX;
}
UINT CBandSiteMenu::_GetBandIdFromClsid(CLSID* pclsid)
{
CComPtr<IPersist> pBand;
CLSID BandCLSID;
DWORD dwBandID;
for (UINT uBand = 0; SUCCEEDED(m_BandSite->EnumBands(uBand, &dwBandID)); uBand++)
{
if (FAILED(m_BandSite->GetBandObject(dwBandID, IID_PPV_ARG(IPersist, &pBand))))
continue;
if (FAILED(pBand->GetClassID(&BandCLSID)))
continue;
if (IsEqualGUID(*pclsid, BandCLSID))
return dwBandID;
}
return UINT_MAX;
}
UINT CBandSiteMenu::_GetBandIdForBuiltinISFBand(UINT uID)
{
CComPtr<IPersist> pBand;
CLSID BandCLSID;
DWORD dwBandID;
for (UINT uBand = 0; SUCCEEDED(m_BandSite->EnumBands(uBand, &dwBandID)); uBand++)
{
if (FAILED(m_BandSite->GetBandObject(dwBandID, IID_PPV_ARG(IPersist, &pBand))))
continue;
if (FAILED(pBand->GetClassID(&BandCLSID)))
continue;
if (!IsEqualGUID(BandCLSID, CLSID_ISFBand))
continue;
UINT menuID = _GetMenuIdFromISFBand(pBand);
if (menuID == uID)
return dwBandID;
}
return UINT_MAX;
}
HRESULT STDMETHODCALLTYPE CBandSiteMenu::SetOwner(IUnknown *pOwner)
{
TRACE("CBandSiteMenu::SetOwner(%p, %p)\n", this, pOwner);
/* Cache the menu that will be merged every time QueryContextMenu is called */
CreateMenuPart();
_CreateMenuPart();
return pOwner->QueryInterface(IID_PPV_ARG(IBandSite, &m_BandSite));
}
@ -119,11 +338,12 @@ HRESULT STDMETHODCALLTYPE CBandSiteMenu::QueryContextMenu(
CComPtr<IPersist> pBand;
CLSID BandCLSID;
DWORD dwBandID;
UINT idMax;
TRACE("CBandSiteMenu::QueryContextMenu(%p, %p, %u, %u, %u, 0x%x)\n", this, hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
/* First Merge the menu with the available bands */
Shell_MergeMenus(hmenu, m_hmenu, indexMenu, idCmdFirst, idCmdLast, MM_DONTREMOVESEPS | MM_SUBMENUSHAVEIDS);
idMax = Shell_MergeMenus(hmenu, m_hmenu, indexMenu, idCmdFirst, idCmdLast, MM_DONTREMOVESEPS | MM_SUBMENUSHAVEIDS);
HMENU hmenuToolbars = GetSubMenu(hmenu, indexMenu);
@ -136,63 +356,107 @@ HRESULT STDMETHODCALLTYPE CBandSiteMenu::QueryContextMenu(
if (FAILED(pBand->GetClassID(&BandCLSID)))
continue;
/* Try to find the clsid of the band in the dsa */
UINT count = DSA_GetItemCount(m_menuDsa);
for (UINT i = 0; i < count; i++)
UINT menuID;
if (IsEqualGUID(BandCLSID, CLSID_ISFBand))
{
GUID* pdsaGUID = (GUID*)DSA_GetItemPtr(m_menuDsa, i);
if (memcmp(pdsaGUID, &BandCLSID, sizeof(GUID)) == 0)
menuID = _GetMenuIdFromISFBand(pBand);
if (menuID == UINT_MAX)
{
/* The index in the dsa is also the index in the menu */
CheckMenuItem(hmenuToolbars, i, MF_CHECKED | MF_BYPOSITION);
HRESULT hr;
hr = _AddISFBandToMenu(hmenuToolbars, 0, idCmdFirst, idCmdLast, pBand, dwBandID, &menuID);
if (SUCCEEDED(hr) && menuID > idMax)
idMax = menuID;
menuID -= idCmdFirst;
}
}
else
{
menuID = _GetMenuIdFromBand(&BandCLSID);
}
if (menuID != UINT_MAX)
CheckMenuItem(hmenuToolbars, menuID + idCmdFirst, MF_CHECKED);
}
return S_OK;
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(idMax - idCmdFirst +1));
}
HRESULT STDMETHODCALLTYPE CBandSiteMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
{
HRESULT hRet;
DWORD dwBandID;
/* FIXME: do we need to handle this and how? */
if (HIWORD(lpici->lpVerb) != NULL)
return E_FAIL;
/* Get the GUID of the item that was clicked */
UINT uID = LOWORD(lpici->lpVerb);
GUID *pguidToolbar = (GUID *)DSA_GetItemPtr(m_menuDsa, uID);
if (uID == IDM_TASKBAR_TOOLBARS_NEW)
{
CComPtr<IDeskBand> pDeskBand;
hRet = _CreateNewISFBand(lpici->hwnd, IID_PPV_ARG(IDeskBand, &pDeskBand));
if (FAILED_UNEXPECTEDLY(hRet))
return hRet;
hRet = m_BandSite->AddBand(pDeskBand);
if (FAILED_UNEXPECTEDLY(hRet))
return hRet;
return S_OK;
}
else if (uID > (UINT)DSA_GetItemCount(m_comcatDsa) + FIRST_COMCAT_MENU_ID )
{
dwBandID = uID - (DSA_GetItemCount(m_comcatDsa) + FIRST_COMCAT_MENU_ID );
m_BandSite->RemoveBand(dwBandID);
return S_OK;
}
else if (uID == IDM_TASKBAR_TOOLBARS_DESKTOP || uID == IDM_TASKBAR_TOOLBARS_QUICKLAUNCH)
{
dwBandID = _GetBandIdForBuiltinISFBand(uID);
if (dwBandID != UINT_MAX)
{
m_BandSite->RemoveBand(dwBandID);
}
else
{
CComPtr<IDeskBand> pDeskBand;
hRet = _CreateBuiltInISFBand(uID, IID_PPV_ARG(IDeskBand, &pDeskBand));
if (FAILED_UNEXPECTEDLY(hRet))
return hRet;
hRet = m_BandSite->AddBand(pDeskBand);
if (FAILED_UNEXPECTEDLY(hRet))
return hRet;
}
return S_OK;
}
/* Get the GUID of the item that was clicked */
GUID *pguidToolbar = (GUID *)DSA_GetItemPtr(m_comcatDsa, uID - FIRST_COMCAT_MENU_ID);
if (!pguidToolbar)
return E_FAIL;
/* Try to find if a band with a guid is present. If it is remove it and return */
CComPtr<IPersist> pBand;
CLSID BandCLSID;
DWORD dwBandID;
for (UINT uBand = 0; SUCCEEDED(m_BandSite->EnumBands(uBand, &dwBandID)); uBand++)
/* Try to find if a band with a guid is present. If it is, remove it and return */
dwBandID = _GetBandIdFromClsid(pguidToolbar);
if (dwBandID != UINT_MAX)
{
if (FAILED(m_BandSite->GetBandObject(dwBandID, IID_PPV_ARG(IPersist, &pBand))))
continue;
if (FAILED(pBand->GetClassID(&BandCLSID)))
continue;
if (memcmp(pguidToolbar, &BandCLSID, sizeof(GUID)) == 0)
{
/* We found it, remove it */
m_BandSite->RemoveBand(dwBandID);
return S_OK;
}
/* We found it, remove it */
m_BandSite->RemoveBand(dwBandID);
}
else
{
/* It is not present. Add it. */
CComPtr<IDeskBand> pDeskBand;
hRet = CoCreateInstance(*pguidToolbar, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IDeskBand, &pDeskBand));
if (FAILED_UNEXPECTEDLY(hRet))
return hRet;
/* It is not present. Add it. */
CComPtr<IDeskBand> pDeskBand;
HRESULT hRet = CoCreateInstance(*pguidToolbar, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IDeskBand, &pDeskBand));
if (FAILED(hRet))
return hRet;
hRet = m_BandSite->AddBand(pDeskBand);
if (FAILED_UNEXPECTEDLY(hRet))
return hRet;
hRet = m_BandSite->AddBand(pDeskBand);
if (FAILED_UNEXPECTEDLY(hRet))
return hRet;
}
return S_OK;
}

View File

@ -29,14 +29,24 @@ class CBandSiteMenu :
public IShellService
{
CComPtr<IBandSite> m_BandSite;
HDSA m_menuDsa;
HDSA m_comcatDsa;
HMENU m_hmenu;
LPITEMIDLIST m_DesktopPidl;
LPITEMIDLIST m_QLaunchPidl;
HRESULT CreateMenuPart();
HRESULT _CreateMenuPart();
HRESULT _CreateNewISFBand(HWND hwnd, REFIID riid, void** ppv);
HRESULT _CreateBuiltInISFBand(UINT uID, REFIID riid, void** ppv);
HRESULT _AddISFBandToMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, IUnknown* pBand, DWORD dwBandID, UINT *newMenuId);
UINT _GetMenuIdFromISFBand(IUnknown *pBand);
UINT _GetMenuIdFromBand(CLSID *BandCLSID);
UINT _GetBandIdFromClsid(CLSID* pclsid);
UINT _GetBandIdForBuiltinISFBand(UINT uID);
public:
CBandSiteMenu();
~CBandSiteMenu();
HRESULT WINAPI FinalConstruct();
// *** IShellService methods ***
virtual HRESULT STDMETHODCALLTYPE SetOwner(IUnknown *);