[RSHELL]
[reactos.git] / base / shell / rshell / CStartMenu.cpp
index fa10931..79c7864 100644 (file)
  */
 #include "precomp.h"
 
+#include "CMergedFolder.h"
+
+// TODO: declare these GUIDs and interfaces in the right place (whatever that may be)
+IID IID_IAugmentedShellFolder = { 0x91EA3F8C, 0xC99B, 0x11D0, { 0x98, 0x15, 0x00, 0xC0, 0x4F, 0xD9, 0x19, 0x72 } };
+IID IID_IAugmentedShellFolder2 = { 0x8DB3B3F4, 0x6CFE, 0x11D1, { 0x8A, 0xE9, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0 } };
+CLSID CLSID_MergedFolder = { 0x26FDC864, 0xBE88, 0x46E7, { 0x92, 0x35, 0x03, 0x2D, 0x8E, 0xA5, 0x16, 0x2E } };
+
 //#define TEST_TRACKPOPUPMENU_SUBMENUS
 
 
@@ -63,6 +70,9 @@ private:
     CComPtr<IBandSite> m_pBandSite;
     CComPtr<IDeskBar> m_pDeskBar;
     CComPtr<ITrayPriv> m_pTrayPriv;
+    CComPtr<IShellFolder> m_psfPrograms;
+    
+    LPITEMIDLIST m_pidlPrograms;
 
     HRESULT OnInitMenu()
     {
@@ -141,13 +151,6 @@ private:
         int csidl = 0;
         IShellMenu *pShellMenu;
 
-        switch (psmd->uId)
-        {
-        case IDM_PROGRAMS:  csidl = CSIDL_PROGRAMS; break;
-        case IDM_FAVORITES: csidl = CSIDL_FAVORITES; break;
-        case IDM_DOCUMENTS: csidl = CSIDL_RECENT; break;
-        }
-
 #if USE_SYSTEM_MENUBAND
         hr = CoCreateInstance(CLSID_MenuBand,
             NULL,
@@ -158,22 +161,32 @@ private:
 #endif
         if (FAILED_UNEXPECTEDLY(hr))
             return hr;
-#if WRAP_MENUBAND
-        hr = CMenuBand_Wrapper(pShellMenu, IID_PPV_ARG(IShellMenu, &pShellMenu));
-        if (FAILED_UNEXPECTEDLY(hr))
-            return hr;
-#endif
 
         hr = pShellMenu->Initialize(this, 0, ANCESTORDEFAULT, SMINIT_VERTICAL);
 
+        switch (psmd->uId)
+        {
+        case IDM_PROGRAMS:  csidl = CSIDL_PROGRAMS; break;
+        case IDM_FAVORITES: csidl = CSIDL_FAVORITES; break;
+        case IDM_DOCUMENTS: csidl = CSIDL_RECENT; break;
+        }
+
         if (csidl)
         {
-            LPITEMIDLIST pidlStartMenu;
-            IShellFolder *psfDestop, *psfStartMenu;
+            IShellFolder *psfStartMenu;
 
-            hr = SHGetFolderLocation(NULL, csidl, 0, 0, &pidlStartMenu);
-            hr = SHGetDesktopFolder(&psfDestop);
-            hr = psfDestop->BindToObject(pidlStartMenu, NULL, IID_PPV_ARG(IShellFolder, &psfStartMenu));
+            if (csidl == CSIDL_PROGRAMS && m_psfPrograms)
+            {
+                psfStartMenu = m_psfPrograms;
+            }
+            else
+            {
+                LPITEMIDLIST pidlStartMenu;
+                IShellFolder *psfDestop;
+                hr = SHGetFolderLocation(NULL, csidl, 0, 0, &pidlStartMenu);
+                hr = SHGetDesktopFolder(&psfDestop);
+                hr = psfDestop->BindToObject(pidlStartMenu, NULL, IID_PPV_ARG(IShellFolder, &psfStartMenu));
+            }
 
             hr = pShellMenu->SetShellFolder(psfStartMenu, NULL, NULL, 0);
         }
@@ -215,12 +228,21 @@ private:
 
     HRESULT OnExec(LPSMDATA psmd)
     {
+        // H   H   A    CCC  K   K  ! ! !
+        // H   H  A A  C   C K  K   ! ! !
+        // HHHHH AAAAA C     KKK    ! ! !
+        // H   H A   A C   C K  K   ! ! !
+        // H   H A   A  CCC  K   K  . . .
+        //
+        // HACK: Instead of running explorer.exe with the path, we should be using ShellExecute to "open" the path directly!
+        // Remove once ShellExecute can handle CLSID path components.
+
         if (psmd->uId == IDM_CONTROLPANEL)
-            ShellExecuteW(NULL, L"open", L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}", NULL, NULL, 1);
+            ShellExecuteW(NULL, NULL, L"explorer.exe", L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}", NULL, SW_SHOWNORMAL);
         else if (psmd->uId == IDM_NETWORKCONNECTIONS)
-            ShellExecuteW(NULL, L"open", L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{7007ACC7-3202-11D1-AAD2-00805FC1270E}", NULL, NULL, 1);
+            ShellExecuteW(NULL, NULL, L"explorer.exe", L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{7007ACC7-3202-11D1-AAD2-00805FC1270E}", NULL, SW_SHOWNORMAL);
         else if (psmd->uId == IDM_PRINTERSANDFAXES)
-            ShellExecuteW(NULL, L"open", L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{2227A280-3AEA-1069-A2DE-08002B30309D}", NULL, NULL, 1);
+            {}/* FIXME: crashes: ShellExecuteW(NULL, NULL, L"explorer.exe", L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{2227A280-3AEA-1069-A2DE-08002B30309D}", NULL, SW_SHOWNORMAL);*/
         else
             PostMessageW(m_hwndTray, WM_COMMAND, psmd->uId, 0);
 
@@ -240,16 +262,20 @@ public:
         IBandSite* pBandSite,
         IDeskBar* pDeskBar)
     {
-        m_pShellMenu.Attach(pShellMenu);
-        m_pBandSite.Attach(pBandSite);
-        m_pDeskBar.Attach(pDeskBar);
+        m_pShellMenu = pShellMenu;
+        m_pBandSite = pBandSite;
+        m_pDeskBar = pDeskBar;
     }
 
     ~CShellMenuCallback()
     {
-        m_pShellMenu.Release();
-        m_pBandSite.Release();
-        m_pDeskBar.Release();
+    }
+
+    HRESULT _SetProgramsFolder(IShellFolder * psf, LPITEMIDLIST pidl)
+    {
+        m_psfPrograms = psf;
+        m_pidlPrograms = pidl;
+        return S_OK;
     }
 
     HRESULT STDMETHODCALLTYPE CallbackSM(
@@ -271,30 +297,106 @@ public:
         case SMC_SFEXEC:
             m_pTrayPriv->Execute(psmd->psf, psmd->pidlItem);
             break;
+        case 0x10000000: // _FilterPIDL from CMenuSFToolbar
+            if (psmd->psf->CompareIDs(0, psmd->pidlItem, m_pidlPrograms) == 0)
+                return S_FALSE;
+            return S_OK;
         }
 
         return S_FALSE;
     }
 };
 
+HRESULT BindToDesktop(LPCITEMIDLIST pidl, IShellFolder ** ppsfResult)
+{
+    HRESULT hr;
+    CComPtr<IShellFolder> psfDesktop;
+
+    *ppsfResult = NULL;
+
+    hr = SHGetDesktopFolder(&psfDesktop);
+    if (FAILED(hr))
+        return hr;
+
+    hr = psfDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, ppsfResult));
+
+    return hr;
+}
+
+static HRESULT GetStartMenuFolder(IShellFolder ** ppsfStartMenu)
+{
+    HRESULT hr;
+    LPITEMIDLIST pidlUserStartMenu;
+    LPITEMIDLIST pidlCommonStartMenu;
+    CComPtr<IShellFolder> psfUserStartMenu;
+    CComPtr<IShellFolder> psfCommonStartMenu;
+    CComPtr<IAugmentedShellFolder> pasf;
+
+    *ppsfStartMenu = NULL;
+
+    hr = SHGetSpecialFolderLocation(NULL, CSIDL_STARTMENU, &pidlUserStartMenu);
+    if (FAILED(hr))
+        return hr;
+
+    if (FAILED(SHGetSpecialFolderLocation(NULL, CSIDL_COMMON_STARTMENU, &pidlCommonStartMenu)))
+    {
+        hr = BindToDesktop(pidlUserStartMenu, ppsfStartMenu);
+        ILFree(pidlUserStartMenu);
+        return hr;
+    }
+
+    hr = BindToDesktop(pidlUserStartMenu, &psfUserStartMenu);
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
+
+    hr = BindToDesktop(pidlCommonStartMenu, &psfCommonStartMenu);
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
+
+#if 1
+    hr = CMergedFolder_Constructor(IID_PPV_ARG(IAugmentedShellFolder, &pasf));
+#else
+    hr = CoCreateInstance(CLSID_MergedFolder, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IAugmentedShellFolder, &pasf));
+#endif
+    if (FAILED_UNEXPECTEDLY(hr))
+    {
+        *ppsfStartMenu = psfUserStartMenu.Detach();
+        ILFree(pidlCommonStartMenu);
+        ILFree(pidlUserStartMenu);
+        return hr;
+    }
+
+    hr = pasf->AddNameSpace(NULL, psfUserStartMenu, pidlUserStartMenu, 0xFF00);
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
+
+    hr = pasf->AddNameSpace(NULL, psfCommonStartMenu, pidlCommonStartMenu, 0);
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
+
+    hr = pasf->QueryInterface(IID_PPV_ARG(IShellFolder, ppsfStartMenu));
+    pasf.Release();
+
+    ILFree(pidlCommonStartMenu);
+    ILFree(pidlUserStartMenu);
+
+    return hr;
+}
+
 extern "C"
 HRESULT WINAPI
 CStartMenu_Constructor(REFIID riid, void **ppv)
 {
-    IShellMenu* pShellMenu;
-    IBandSite* pBandSite;
-    IDeskBar* pDeskBar;
+    CComPtr<IShellMenu> pShellMenu;
+    CComPtr<IBandSite> pBandSite;
+    CComPtr<IDeskBar> pDeskBar;
 
     HRESULT hr;
-    IShellFolder *shellFolder;
+    IShellFolder * psf;
 
-    LPITEMIDLIST pidlStartMenuUser;
-    IShellFolder *psfStartMenuUser;
-
-#if MERGE_FOLDERS
-    LPITEMIDLIST pidlStartMenuAll;
-    IShellFolder *psfStartMenuAll;
-#endif
+    LPITEMIDLIST pidlProgramsAbsolute;
+    LPITEMIDLIST pidlPrograms;
+    CComPtr<IShellFolder> psfPrograms;
 
 #if USE_SYSTEM_MENUBAND
     hr = CoCreateInstance(CLSID_MenuBand,
@@ -306,11 +408,6 @@ CStartMenu_Constructor(REFIID riid, void **ppv)
 #endif
     if (FAILED_UNEXPECTEDLY(hr))
         return hr;
-#if WRAP_MENUBAND
-    hr = CMenuBand_Wrapper(pShellMenu, IID_PPV_ARG(IShellMenu, &pShellMenu));
-    if (FAILED_UNEXPECTEDLY(hr))
-        return hr;
-#endif
 
 #if USE_SYSTEM_MENUSITE
     hr = CoCreateInstance(CLSID_MenuBandSite,
@@ -322,11 +419,6 @@ CStartMenu_Constructor(REFIID riid, void **ppv)
 #endif
     if (FAILED_UNEXPECTEDLY(hr))
         return hr;
-#if WRAP_MENUSITE
-    hr = CMenuSite_Wrapper(pBandSite, IID_PPV_ARG(IBandSite, &pBandSite));
-    if (FAILED_UNEXPECTEDLY(hr))
-        return hr;
-#endif
 
 #if USE_SYSTEM_MENUDESKBAR
     hr = CoCreateInstance(CLSID_MenuDeskBar,
@@ -338,11 +430,6 @@ CStartMenu_Constructor(REFIID riid, void **ppv)
 #endif
     if (FAILED_UNEXPECTEDLY(hr))
         return hr;
-#if WRAP_MENUDESKBAR
-    hr = CMenuDeskBar_Wrapper(pDeskBar, IID_PPV_ARG(IDeskBar, &pDeskBar));
-    if (FAILED_UNEXPECTEDLY(hr))
-        return hr;
-#endif
 
     CComObject<CShellMenuCallback> *pCallback;
     hr = CComObject<CShellMenuCallback>::CreateInstance(&pCallback);
@@ -351,35 +438,32 @@ CStartMenu_Constructor(REFIID riid, void **ppv)
     pCallback->AddRef(); // CreateInstance returns object with 0 ref count */
     pCallback->Initialize(pShellMenu, pBandSite, pDeskBar);
 
-    pShellMenu->Initialize(pCallback, (UINT)-1, 0, SMINIT_TOPLEVEL | SMINIT_VERTICAL);
+    pShellMenu->Initialize(pCallback, (UINT) -1, 0, SMINIT_TOPLEVEL | SMINIT_VERTICAL);
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
+    
+    hr = GetStartMenuFolder(&psf);
     if (FAILED_UNEXPECTEDLY(hr))
         return hr;
 
-    hr = SHGetDesktopFolder(&shellFolder);
-
-    /* FIXME: Use CLSID_MergedFolder class and IID_IAugmentedShellFolder2 interface here */
-    /* CLSID_MergedFolder 26fdc864-be88-46e7-9235-032d8ea5162e */
-    /* IID_IAugmentedShellFolder2 8db3b3f4-6cfe-11d1-8ae9-00c04fd918d0 */
-    hr = SHGetFolderLocation(NULL, CSIDL_STARTMENU, 0, 0, &pidlStartMenuUser);
-    hr = shellFolder->BindToObject(pidlStartMenuUser, NULL, IID_IShellFolder, (void**) &psfStartMenuUser);
+    hr = SHGetSpecialFolderLocation(NULL, CSIDL_PROGRAMS, &pidlProgramsAbsolute);
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
 
-#if MERGE_FOLDERS
-    hr = SHGetFolderLocation(NULL, CSIDL_COMMON_STARTMENU, 0, 0, &pidlStartMenuAll);
-    hr = shellFolder->BindToObject(pidlStartMenuAll, NULL, IID_IShellFolder, (void**) &psfStartMenuAll);
+    pidlPrograms = ILClone(ILFindLastID(pidlProgramsAbsolute));
+    ILFree(pidlProgramsAbsolute);
 
-    IShellFolder * psfMerged;
-    hr = CMergedFolder_Constructor(psfStartMenuUser, psfStartMenuAll, IID_PPV_ARG(IShellFolder, &psfMerged));
+    hr = psf->BindToObject(pidlPrograms, NULL, IID_PPV_ARG(IShellFolder, &psfPrograms));
     if (FAILED_UNEXPECTEDLY(hr))
         return hr;
 
-    hr = pShellMenu->SetShellFolder(psfMerged, NULL, NULL, 0);
+    hr = pCallback->_SetProgramsFolder(psfPrograms, pidlPrograms);
     if (FAILED_UNEXPECTEDLY(hr))
         return hr;
-#else
-    hr = pShellMenu->SetShellFolder(psfStartMenuUser, NULL, NULL, 0);
+
+    hr = pShellMenu->SetShellFolder(psf, NULL, NULL, 0);
     if (FAILED_UNEXPECTEDLY(hr))
         return hr;
-#endif
 
     hr = pDeskBar->SetClient(pBandSite);
     if (FAILED_UNEXPECTEDLY(hr))