From 9804a12efff12ceac311fd8ac25c2d6b75acf79d Mon Sep 17 00:00:00 2001 From: David Quintana Date: Wed, 9 Jul 2014 23:05:37 +0000 Subject: [PATCH] [RSHELL] * Now that CMergedFolder works, try to make it more like windows. * CMergedFolder: Declare and expose the undocumented IAugmentedShellFolder2 (all methods unimplemented yet). It will require major changes to the way I implemented it, but it will be for the best. * CStartMenu: Make use of the real CMergedFolder in Windows 2003 (does not exist in win7). svn path=/branches/shell-experiments/; revision=63703 --- base/shell/rshell/CMergedFolder.cpp | 100 ++++++++++++++--- base/shell/rshell/CMergedFolder.h | 38 ++++++- base/shell/rshell/CStartMenu.cpp | 161 +++++++++++++++++++++------- 3 files changed, 243 insertions(+), 56 deletions(-) diff --git a/base/shell/rshell/CMergedFolder.cpp b/base/shell/rshell/CMergedFolder.cpp index 73731b83081..40f3f342ddb 100644 --- a/base/shell/rshell/CMergedFolder.cpp +++ b/base/shell/rshell/CMergedFolder.cpp @@ -30,6 +30,7 @@ struct LocalPidlInfo BOOL shared; IShellFolder * parent; LPITEMIDLIST pidl; + LPITEMIDLIST pidlCommon; }; class CEnumMergedFolder : @@ -67,7 +68,7 @@ public: HRESULT SetSources(IShellFolder * userLocal, IShellFolder * allUSers); HRESULT Begin(HWND hwndOwner, SHCONTF flags); - HRESULT FindPidlInList(LPCITEMIDLIST pcidl, LocalPidlInfo * pinfo); + HRESULT FindPidlInList(HWND hwndOwner, LPCITEMIDLIST pcidl, LocalPidlInfo * pinfo); virtual HRESULT STDMETHODCALLTYPE Next( ULONG celt, @@ -86,9 +87,10 @@ CEnumMergedFolder::CEnumMergedFolder() : m_AllUSers(NULL), m_HwndOwner(NULL), m_Flags(0), - m_hDsaIndex(0) + m_hDsa(NULL), + m_hDsaIndex(0), + m_hDsaCount(0) { - m_hDsa = DSA_Create(sizeof(LocalPidlInfo), 10); } CEnumMergedFolder::~CEnumMergedFolder() @@ -119,8 +121,8 @@ HRESULT CEnumMergedFolder::SetSources(IShellFolder * userLocal, IShellFolder * a HRESULT CEnumMergedFolder::Begin(HWND hwndOwner, SHCONTF flags) { HRESULT hr; - - if (m_HwndOwner == hwndOwner && m_Flags == flags) + + if (m_hDsa && m_HwndOwner == hwndOwner && m_Flags == flags) { return Reset(); } @@ -137,6 +139,11 @@ HRESULT CEnumMergedFolder::Begin(HWND hwndOwner, SHCONTF flags) return hr; } + if (!m_hDsa) + { + m_hDsa = DSA_Create(sizeof(LocalPidlInfo), 10); + } + DSA_EnumCallback(m_hDsa, s_DsaDeleteCallback, this); DSA_DeleteAllItems(m_hDsa); m_hDsaCount = 0; @@ -242,10 +249,15 @@ HRESULT CEnumMergedFolder::Begin(HWND hwndOwner, SHCONTF flags) return Reset(); } -HRESULT CEnumMergedFolder::FindPidlInList(LPCITEMIDLIST pcidl, LocalPidlInfo * pinfo) +HRESULT CEnumMergedFolder::FindPidlInList(HWND hwndOwner, LPCITEMIDLIST pcidl, LocalPidlInfo * pinfo) { HRESULT hr; + if (!m_hDsa) + { + Begin(hwndOwner, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS); + } + TRACE("Searching for pidl { cb=%d } in a list of %d items\n", pcidl->mkid.cb, m_hDsaCount); for (int i = 0; i < (int)m_hDsaCount; i++) @@ -299,10 +311,9 @@ HRESULT STDMETHODCALLTYPE CEnumMergedFolder::Next( // FIXME: ILClone shouldn't be needed here! This should be causing leaks if (rgelt) rgelt[i] = ILClone(info.pidl); - - m_hDsaIndex++; i++; + m_hDsaIndex++; if (m_hDsaIndex == m_hDsaCount) { if (pceltFetched) *pceltFetched = i; @@ -376,6 +387,37 @@ HRESULT CMergedFolder::_SetSources(IShellFolder* userLocal, IShellFolder* allUse return m_EnumSource->SetSources(m_UserLocal, m_AllUSers); } +// IAugmentedShellFolder2 +HRESULT STDMETHODCALLTYPE CMergedFolder::AddNameSpace(LPGUID lpGuid, IShellFolder * psf, LPCITEMIDLIST pcidl, ULONG dwUnknown) +{ + UNIMPLEMENTED; + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMergedFolder::GetNameSpaceID(LPCITEMIDLIST pcidl, LPGUID lpGuid) +{ + UNIMPLEMENTED; + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMergedFolder::QueryNameSpace(ULONG dwUnknown, LPGUID lpGuid, IShellFolder ** ppsf) +{ + UNIMPLEMENTED; + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMergedFolder::EnumNameSpace(ULONG dwUnknown, PULONG lpUnknown) +{ + UNIMPLEMENTED; + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMergedFolder::UnWrapIDList(LPCITEMIDLIST pcidl, LONG lUnknown, IShellFolder ** ppsf, LPITEMIDLIST * ppidl1, LPITEMIDLIST *ppidl2, LONG * lpUnknown) +{ + UNIMPLEMENTED; + return E_NOTIMPL; +} + // IShellFolder HRESULT STDMETHODCALLTYPE CMergedFolder::ParseDisplayName( HWND hwndOwner, @@ -385,8 +427,34 @@ HRESULT STDMETHODCALLTYPE CMergedFolder::ParseDisplayName( LPITEMIDLIST *ppidl, ULONG *pdwAttributes) { - UNIMPLEMENTED; - return E_NOTIMPL; + HRESULT hr; + LocalPidlInfo info; + + if (!ppidl) return E_FAIL; + + if (pchEaten) *pchEaten = 0; + if (pdwAttributes) *pdwAttributes = 0; + + hr = m_UserLocal->ParseDisplayName(hwndOwner, pbcReserved, lpszDisplayName, pchEaten, ppidl, pdwAttributes); + if (SUCCEEDED(hr)) + { + hr = m_EnumSource->FindPidlInList(hwndOwner, *ppidl, &info); + if (SUCCEEDED(hr)) + return hr; + } + + hr = m_AllUSers->ParseDisplayName(hwndOwner, pbcReserved, lpszDisplayName, pchEaten, ppidl, pdwAttributes); + if (SUCCEEDED(hr)) + { + hr = m_EnumSource->FindPidlInList(hwndOwner, *ppidl, &info); + if (SUCCEEDED(hr)) + return hr; + } + + if (ppidl) *ppidl = NULL; + if (pchEaten) *pchEaten = 0; + if (pdwAttributes) *pdwAttributes = 0; + return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); } HRESULT STDMETHODCALLTYPE CMergedFolder::EnumObjects( @@ -412,7 +480,7 @@ HRESULT STDMETHODCALLTYPE CMergedFolder::BindToObject( TRACE("BindToObject\n"); - hr = m_EnumSource->FindPidlInList(pidl, &info); + hr = m_EnumSource->FindPidlInList(NULL, pidl, &info); if (FAILED_UNEXPECTEDLY(hr)) return hr; @@ -478,7 +546,7 @@ HRESULT STDMETHODCALLTYPE CMergedFolder::GetAttributesOf( { LPCITEMIDLIST pidl = apidl[i]; - hr = m_EnumSource->FindPidlInList(pidl, &info); + hr = m_EnumSource->FindPidlInList(NULL, pidl, &info); if (FAILED_UNEXPECTEDLY(hr)) return hr; @@ -514,7 +582,7 @@ HRESULT STDMETHODCALLTYPE CMergedFolder::GetUIObjectOf( TRACE("Processing GetUIObjectOf item %d of %u...\n", i, cidl); - hr = m_EnumSource->FindPidlInList(pidl, &info); + hr = m_EnumSource->FindPidlInList(hwndOwner, pidl, &info); if (FAILED_UNEXPECTEDLY(hr)) return hr; @@ -544,7 +612,7 @@ HRESULT STDMETHODCALLTYPE CMergedFolder::GetDisplayNameOf( TRACE("GetDisplayNameOf\n"); - hr = m_EnumSource->FindPidlInList(pidl, &info); + hr = m_EnumSource->FindPidlInList(NULL, pidl, &info); if (FAILED_UNEXPECTEDLY(hr)) return hr; @@ -630,7 +698,7 @@ HRESULT STDMETHODCALLTYPE CMergedFolder::GetDetailsEx( TRACE("GetDetailsEx\n"); - hr = m_EnumSource->FindPidlInList(pidl, &info); + hr = m_EnumSource->FindPidlInList(NULL, pidl, &info); if (FAILED_UNEXPECTEDLY(hr)) return hr; @@ -655,7 +723,7 @@ HRESULT STDMETHODCALLTYPE CMergedFolder::GetDetailsOf( TRACE("GetDetailsOf\n"); - hr = m_EnumSource->FindPidlInList(pidl, &info); + hr = m_EnumSource->FindPidlInList(NULL, pidl, &info); if (FAILED_UNEXPECTEDLY(hr)) return hr; diff --git a/base/shell/rshell/CMergedFolder.h b/base/shell/rshell/CMergedFolder.h index 6eb6400e64f..5b397a67959 100644 --- a/base/shell/rshell/CMergedFolder.h +++ b/base/shell/rshell/CMergedFolder.h @@ -19,12 +19,37 @@ */ #pragma once +static IID IID_IAugmentedShellFolder = { 0x91EA3F8C, 0xC99B, 0x11D0, { 0x98, 0x15, 0x00, 0xC0, 0x4F, 0xD9, 0x19, 0x72 } }; +static IID IID_IAugmentedShellFolder2 = { 0x8DB3B3F4, 0x6CFE, 0x11D1, { 0x8A, 0xE9, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0 } }; +static CLSID CLSID_MergedFolder = { 0x26FDC864, 0xBE88, 0x46E7, { 0x92, 0x35, 0x03, 0x2D, 0x8E, 0xA5, 0x16, 0x2E } }; + +interface IAugmentedShellFolder : public IShellFolder +{ + virtual HRESULT STDMETHODCALLTYPE AddNameSpace(LPGUID, IShellFolder *, LPCITEMIDLIST, ULONG) = 0; + virtual HRESULT STDMETHODCALLTYPE GetNameSpaceID(LPCITEMIDLIST, LPGUID) = 0; + virtual HRESULT STDMETHODCALLTYPE QueryNameSpace(ULONG, LPGUID, IShellFolder **) = 0; + virtual HRESULT STDMETHODCALLTYPE EnumNameSpace(ULONG, PULONG) = 0; +}; + +interface IAugmentedShellFolder2 : public IAugmentedShellFolder +{ + virtual HRESULT STDMETHODCALLTYPE UnWrapIDList(LPCITEMIDLIST, LONG, IShellFolder **, LPITEMIDLIST *, LPITEMIDLIST *, LONG *) = 0; +}; + +/* No idea what QUERYNAMESPACEINFO struct contains -- the prototype comes from the PDB info +interface IAugmentedShellFolder3 : public IAugmentedShellFolder2 +{ + virtual HRESULT STDMETHODCALLTYPE QueryNameSpace2(ULONG, QUERYNAMESPACEINFO *) = 0; +}; +*/ + class CEnumMergedFolder; class CMergedFolder : public CComObjectRootEx, public IShellFolder2, //public IStorage, + public IAugmentedShellFolder2, // -- undocumented //public IAugmentedShellFolder3, // -- undocumented //public IShellService, // -- undocumented //public ITranslateShellChangeNotify,// -- undocumented @@ -52,13 +77,15 @@ public: DECLARE_PROTECT_FINAL_CONSTRUCT() BEGIN_COM_MAP(CMergedFolder) - COM_INTERFACE_ENTRY_IID(IID_IShellFolder, IShellFolder) + COM_INTERFACE_ENTRY2_IID(IID_IShellFolder, IShellFolder, IShellFolder2) COM_INTERFACE_ENTRY_IID(IID_IShellFolder2, IShellFolder2) COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist) COM_INTERFACE_ENTRY_IID(IID_IPersistFolder, IPersistFolder) COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2) - //COM_INTERFACE_ENTRY_IID(IID_IStorage, IStorage) + COM_INTERFACE_ENTRY_IID(IID_IAugmentedShellFolder, IAugmentedShellFolder) + COM_INTERFACE_ENTRY_IID(IID_IAugmentedShellFolder2, IAugmentedShellFolder2) //COM_INTERFACE_ENTRY_IID(IID_IAugmentedShellFolder3, IAugmentedShellFolder3) + //COM_INTERFACE_ENTRY_IID(IID_IStorage, IStorage) //COM_INTERFACE_ENTRY_IID(IID_IShellService, IShellService) //COM_INTERFACE_ENTRY_IID(IID_ITranslateShellChangeNotify,ITranslateShellChangeNotify) //COM_INTERFACE_ENTRY_IID(IID_IPersistPropertyBag,IPersistPropertyBag) @@ -166,4 +193,11 @@ public: // IPersistFolder2 virtual HRESULT STDMETHODCALLTYPE GetCurFolder(LPITEMIDLIST * pidl); + + // IAugmentedShellFolder2 + virtual HRESULT STDMETHODCALLTYPE AddNameSpace(LPGUID lpGuid, IShellFolder * psf, LPCITEMIDLIST pcidl, ULONG dwUnknown); + virtual HRESULT STDMETHODCALLTYPE GetNameSpaceID(LPCITEMIDLIST pcidl, LPGUID lpGuid); + virtual HRESULT STDMETHODCALLTYPE QueryNameSpace(ULONG dwUnknown, LPGUID lpGuid, IShellFolder ** ppsf); + virtual HRESULT STDMETHODCALLTYPE EnumNameSpace(ULONG dwUnknown, PULONG lpUnknown); + virtual HRESULT STDMETHODCALLTYPE UnWrapIDList(LPCITEMIDLIST pcidl, LONG lUnknown, IShellFolder ** ppsf, LPITEMIDLIST * ppidl1, LPITEMIDLIST *ppidl2, LONG * lpUnknown); }; diff --git a/base/shell/rshell/CStartMenu.cpp b/base/shell/rshell/CStartMenu.cpp index 4edb5ee7182..263d9f803bc 100644 --- a/base/shell/rshell/CStartMenu.cpp +++ b/base/shell/rshell/CStartMenu.cpp @@ -19,6 +19,8 @@ */ #include "precomp.h" +#include "CMergedFolder.h" + //#define TEST_TRACKPOPUPMENU_SUBMENUS @@ -63,6 +65,7 @@ private: CComPtr m_pBandSite; CComPtr m_pDeskBar; CComPtr m_pTrayPriv; + CComPtr m_programsFolder; HRESULT OnInitMenu() { @@ -141,6 +144,12 @@ private: int csidl = 0; IShellMenu *pShellMenu; + hr = CMenuBand_Constructor(IID_PPV_ARG(IShellMenu, &pShellMenu)); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + hr = pShellMenu->Initialize(this, 0, ANCESTORDEFAULT, SMINIT_VERTICAL); + switch (psmd->uId) { case IDM_PROGRAMS: csidl = CSIDL_PROGRAMS; break; @@ -148,20 +157,22 @@ private: case IDM_DOCUMENTS: csidl = CSIDL_RECENT; break; } - hr = CMenuBand_Constructor(IID_PPV_ARG(IShellMenu, &pShellMenu)); - if (FAILED_UNEXPECTEDLY(hr)) - return hr; - - hr = pShellMenu->Initialize(this, 0, ANCESTORDEFAULT, SMINIT_VERTICAL); - 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_programsFolder) + { + psfStartMenu = m_programsFolder; + } + 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); } @@ -240,6 +251,12 @@ public: m_pDeskBar.Release(); } + HRESULT _SetProgramsFolder(IShellFolder * programs) + { + m_programsFolder = programs; + return S_OK; + } + HRESULT STDMETHODCALLTYPE CallbackSM( LPSMDATA psmd, UINT uMsg, @@ -265,6 +282,85 @@ public: } }; +HRESULT BindToDesktop(LPCITEMIDLIST pidl, IShellFolder ** ppsfResult) +{ + HRESULT hr; + CComPtr psfDesktop; + + *ppsfResult = NULL; + + hr = SHGetDesktopFolder(&psfDesktop); + if (FAILED(hr)) + return hr; + + hr = psfDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, ppsfResult)); + + return hr; +} + +HRESULT GetStartMenuFolder(IShellFolder ** ppsfStartMenu) +{ + HRESULT hr; + LPITEMIDLIST pidlUserStartMenu; + LPITEMIDLIST pidlCommonStartMenu; + + *ppsfStartMenu = NULL; + + hr = SHGetSpecialFolderLocation(NULL, CSIDL_STARTMENU, &pidlUserStartMenu); + if (FAILED(hr)) + return hr; + + if (FAILED(SHGetSpecialFolderLocation(NULL, CSIDL_COMMON_STARTMENU, &pidlCommonStartMenu))) + { + BindToDesktop(pidlUserStartMenu, ppsfStartMenu); + ILFree(pidlUserStartMenu); + return S_OK; + } + + CComPtr psfUserStartMenu; + hr = BindToDesktop(pidlUserStartMenu, &psfUserStartMenu); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + CComPtr psfCommonStartMenu; + hr = BindToDesktop(pidlCommonStartMenu, &psfCommonStartMenu); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + +#if CUSTOM_MERGE_FOLDERS + IShellFolder * psfMerged; + hr = CMergedFolder_Constructor(psfUserStartMenu, psfCommonStartMenu, IID_PPV_ARG(IShellFolder, &psfMerged)); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; +#else + CComPtr pasf; + hr = CoCreateInstance(CLSID_MergedFolder, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IAugmentedShellFolder, &pasf)); + if (FAILED_UNEXPECTEDLY(hr)) + { + BindToDesktop(pidlUserStartMenu, ppsfStartMenu); + ILFree(pidlCommonStartMenu); + ILFree(pidlUserStartMenu); + return S_OK; + } + + 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(); +#endif + + ILFree(pidlCommonStartMenu); + ILFree(pidlUserStartMenu); + + return hr; +} + extern "C" HRESULT WINAPI CStartMenu_Constructor(REFIID riid, void **ppv) @@ -274,15 +370,10 @@ CStartMenu_Constructor(REFIID riid, void **ppv) IDeskBar* pDeskBar; HRESULT hr; - IShellFolder *shellFolder; + IShellFolder * psf; - LPITEMIDLIST pidlStartMenuUser; - IShellFolder *psfStartMenuUser; - -#if MERGE_FOLDERS - LPITEMIDLIST pidlStartMenuAll; - IShellFolder *psfStartMenuAll; -#endif + LPITEMIDLIST pidlPrograms; + CComPtr psfPrograms; hr = CMenuBand_Constructor(IID_PPV_ARG(IShellMenu, &pShellMenu)); if (FAILED_UNEXPECTEDLY(hr)) @@ -306,32 +397,26 @@ CStartMenu_Constructor(REFIID riid, void **ppv) pShellMenu->Initialize(pCallback, (UINT) -1, 0, SMINIT_TOPLEVEL | SMINIT_VERTICAL); 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_PPV_ARG(IShellFolder, &psfStartMenuUser)); - -#if MERGE_FOLDERS - hr = SHGetFolderLocation(NULL, CSIDL_COMMON_STARTMENU, 0, 0, &pidlStartMenuAll); - hr = shellFolder->BindToObject(pidlStartMenuAll, NULL, IID_PPV_ARG(IShellFolder, &psfStartMenuAll)); - - IShellFolder * psfMerged; - hr = CMergedFolder_Constructor(psfStartMenuUser, psfStartMenuAll, IID_PPV_ARG(IShellFolder, &psfMerged)); + + hr = GetStartMenuFolder(&psf); if (FAILED_UNEXPECTEDLY(hr)) return hr; - hr = pShellMenu->SetShellFolder(psfMerged, NULL, NULL, 0); + hr = psf->ParseDisplayName(NULL, NULL, L"Programs", NULL, &pidlPrograms, NULL); if (FAILED_UNEXPECTEDLY(hr)) return hr; -#else - hr = pShellMenu->SetShellFolder(psfStartMenuUser, NULL, NULL, 0); + + hr = psf->BindToObject(pidlPrograms, NULL, IID_PPV_ARG(IShellFolder, &psfPrograms)); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + hr = pCallback->_SetProgramsFolder(psfPrograms); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + hr = pShellMenu->SetShellFolder(psf, NULL, NULL, 0); if (FAILED_UNEXPECTEDLY(hr)) return hr; -#endif hr = pDeskBar->SetClient(pBandSite); if (FAILED_UNEXPECTEDLY(hr))