[BROWSEUI] -CBandSiteMenu: Add preliminary support for adding and removing bands...
authorGiannis Adamopoulos <gadamopoulos@reactos.org>
Mon, 17 Apr 2017 09:02:49 +0000 (09:02 +0000)
committerGiannis Adamopoulos <gadamopoulos@reactos.org>
Mon, 17 Apr 2017 09:02:49 +0000 (09:02 +0000)
svn path=/trunk/; revision=74345

reactos/dll/win32/browseui/shellbars/CBandSiteMenu.cpp
reactos/dll/win32/browseui/shellbars/CBandSiteMenu.h

index 36d54a9..d323c3d 100644 (file)
  */
 
 #include "shellbars.h"
+#include <strsafe.h>
 
-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<IEnumGUID> 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<IPersist> 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<IPersist> 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<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;
+
     return S_OK;
 }
 
index 4c059c3..d4d27ac 100644 (file)
@@ -28,7 +28,12 @@ class CBandSiteMenu :
     public IContextMenu3,
     public IShellService
 {
-    CComPtr<IUnknown> m_Owner;
+    CComPtr<IBandSite> m_BandSite;
+    HDSA m_menuDsa;
+    HMENU m_hmenu;
+
+    HRESULT CreateMenuPart();
+
 public:
     CBandSiteMenu();
     ~CBandSiteMenu();