diff --git a/reactos/dll/win32/browseui/shellbars/CBandSiteMenu.cpp b/reactos/dll/win32/browseui/shellbars/CBandSiteMenu.cpp index 36d54a9538d..d323c3dcae6 100644 --- a/reactos/dll/win32/browseui/shellbars/CBandSiteMenu.cpp +++ b/reactos/dll/win32/browseui/shellbars/CBandSiteMenu.cpp @@ -20,58 +20,189 @@ */ #include "shellbars.h" +#include -CBandSiteMenu::CBandSiteMenu() +#define IDM_DESKBAND_BEGINCUSTOM 0x10 +#define IDM_DESKBAND_ENDCUSTOM 0x25 + +CBandSiteMenu::CBandSiteMenu(): + m_menuDsa(NULL), + m_hmenu(NULL) { } CBandSiteMenu::~CBandSiteMenu() { + if (m_hmenu) + DestroyMenu(m_hmenu); + + if (m_menuDsa) + DSA_Destroy(m_menuDsa); + + m_BandSite = NULL; +} + + +HRESULT CBandSiteMenu::CreateMenuPart() +{ + WCHAR wszBandName[MAX_PATH]; + WCHAR wszBandGUID[MAX_PATH]; + WCHAR wRegKey[MAX_PATH]; + UINT cBands; + DWORD dwDataSize; + CATID category = CATID_DeskBand; + HMENU hmenuToolbars; + DWORD dwRead; + CComPtr pEnumGUID; + HRESULT hr; + + if (m_hmenu) + DestroyMenu(m_hmenu); + + if (m_menuDsa) + DSA_Destroy(m_menuDsa); + + /* 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) + return E_OUTOFMEMORY; + + /* Get the handle of the submenu where the available items will be shown */ + hmenuToolbars = GetSubMenu(m_hmenu, 0); + + /* Create the category enumerator */ + hr = SHEnumClassesOfCategories(1, &category, 0, NULL, &pEnumGUID); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + /* Enumerate the classes in the CATID_DeskBand category */ + cBands = 0; + do + { + GUID iter; + pEnumGUID->Next(1, &iter, &dwRead); + if (!dwRead) + continue; + + if (!StringFromGUID2(iter, wszBandGUID, MAX_PATH)) + continue; + + /* Get the band name */ + StringCchPrintfW(wRegKey, MAX_PATH, L"CLSID\\%s", wszBandGUID); + dwDataSize = MAX_PATH; + 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); + cBands++; + } + while (dwRead > 0); + + return S_OK; } HRESULT STDMETHODCALLTYPE CBandSiteMenu::SetOwner(IUnknown *pOwner) { TRACE("CBandSiteMenu::SetOwner(%p, %p)\n", this, pOwner); - m_Owner = pOwner; - return S_OK; + + /* Cache the menu that will be merged every time QueryContextMenu is called */ + CreateMenuPart(); + + return pOwner->QueryInterface(IID_PPV_ARG(IBandSite, &m_BandSite)); } HRESULT STDMETHODCALLTYPE CBandSiteMenu::QueryContextMenu( HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) { - BOOL ret; - WCHAR buffer[100]; + CComPtr pBand; + CLSID BandCLSID; + DWORD dwBandID; + UINT uBand = 0; TRACE("CBandSiteMenu::QueryContextMenu(%p, %p, %u, %u, %u, 0x%x)\n", this, hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags); - HMENU hm = LoadMenuW(_AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCEW(IDM_TASKBAR_TOOLBARS)); - if (!hm) - return HRESULT_FROM_WIN32(GetLastError()); + /* First Merge the menu with the available bands */ + Shell_MergeMenus(hmenu, m_hmenu, indexMenu, idCmdFirst, idCmdLast, MM_DONTREMOVESEPS | MM_SUBMENUSHAVEIDS); - MENUITEMINFOW mii = { 0 }; - mii.cbSize = sizeof(mii); - mii.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STATE | MIIM_STRING | MIIM_SUBMENU; - ret = GetMenuItemInfoW(hm, 0, TRUE, &mii); - if (!hm) - return HRESULT_FROM_WIN32(GetLastError()); + HMENU hmenuToolbars = GetSubMenu(hmenu, indexMenu); - mii.dwTypeData = buffer; - mii.cch = mii.cch + 1; + /* Enumerate all present bands and mark them as checked in the menu */ + while (SUCCEEDED(m_BandSite->EnumBands(uBand, &dwBandID))) + { + if (FAILED(m_BandSite->GetBandObject(dwBandID, IID_PPV_ARG(IPersist, &pBand)))) + continue; - ret = GetMenuItemInfoW(hm, 0, TRUE, &mii); - if (!hm) - return HRESULT_FROM_WIN32(GetLastError()); + if (FAILED(pBand->GetClassID(&BandCLSID))) + continue; - ret = InsertMenuItemW(hmenu, 0, TRUE, &mii); + /* Try to find the clsid of the band in the dsa */ + UINT count = DSA_GetItemCount(m_menuDsa); + for (UINT i = 0; i < count; i++) + { + GUID* pdsaGUID = (GUID*)DSA_GetItemPtr(m_menuDsa, i); + if (memcmp(pdsaGUID, &BandCLSID, sizeof(GUID)) == 0) + { + /* The index in the dsa is also the index in the menu */ + CheckMenuItem(hmenuToolbars, i, MF_CHECKED | MF_BYPOSITION); + } + } - RemoveMenu(hm, 0, MF_BYPOSITION); + uBand++; + } - return E_NOTIMPL; + return S_OK; } HRESULT STDMETHODCALLTYPE CBandSiteMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpici) { - FIXME("CBandSiteMenu::InvokeCommand is UNIMPLEMENTED (%p, %p)\n", this, lpici); + /* 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 (!pguidToolbar) + return E_FAIL; + + /* Try to find if a band with a guid is present. If it is remove it and return */ + CComPtr pBand; + CLSID BandCLSID; + DWORD dwBandID; + UINT uBand = 0; + while (SUCCEEDED(m_BandSite->EnumBands(uBand, &dwBandID))) + { + 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; + } + + uBand++; + } + + /* It is not present. Add it. */ + CComPtr 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; + return S_OK; } diff --git a/reactos/dll/win32/browseui/shellbars/CBandSiteMenu.h b/reactos/dll/win32/browseui/shellbars/CBandSiteMenu.h index 4c059c35737..d4d27acdc73 100644 --- a/reactos/dll/win32/browseui/shellbars/CBandSiteMenu.h +++ b/reactos/dll/win32/browseui/shellbars/CBandSiteMenu.h @@ -28,7 +28,12 @@ class CBandSiteMenu : public IContextMenu3, public IShellService { - CComPtr m_Owner; + CComPtr m_BandSite; + HDSA m_menuDsa; + HMENU m_hmenu; + + HRESULT CreateMenuPart(); + public: CBandSiteMenu(); ~CBandSiteMenu();