https://git.reactos.org/?p=reactos.git;a=commitdiff;h=6ae11ba09d4fa8d16336a1ed40a112b3df19a474
commit 6ae11ba09d4fa8d16336a1ed40a112b3df19a474 Author: Whindmar Saksit <whinds...@proton.me> AuthorDate: Thu Aug 29 20:45:59 2024 +0200 Commit: GitHub <nore...@github.com> CommitDate: Thu Aug 29 20:45:59 2024 +0200 [SHELL32] Don't display non-enumerable nor non-folder items in Explorer tree (#7189) This partially implements RegFolder required items as described by Geoff Chappell. CORE-19176 CORE-14061 --- dll/win32/shell32/CDefView.cpp | 12 +- dll/win32/shell32/CEnumIDListBase.cpp | 27 -- dll/win32/shell32/CEnumIDListBase.h | 16 +- dll/win32/shell32/folders/CControlPanelFolder.cpp | 14 +- dll/win32/shell32/folders/CDesktopFolder.cpp | 197 +++++------ dll/win32/shell32/folders/CDesktopFolder.h | 29 ++ dll/win32/shell32/folders/CDrivesFolder.cpp | 56 +++- dll/win32/shell32/folders/CDrivesFolder.h | 13 +- dll/win32/shell32/folders/CFSFolder.cpp | 44 ++- dll/win32/shell32/folders/CRegFolder.cpp | 362 +++++++++++++-------- dll/win32/shell32/shelldesktop/CDesktopBrowser.cpp | 3 +- dll/win32/shell32/shfldr.h | 42 +++ dll/win32/shell32/shlfolder.cpp | 28 ++ dll/win32/shell32/wine/pidl.c | 2 +- dll/win32/shell32/wine/pidl.h | 14 + dll/win32/shell32/wine/shell32_main.h | 2 - sdk/include/psdk/shobjidl.idl | 33 ++ sdk/include/reactos/shellutils.h | 11 + 18 files changed, 601 insertions(+), 304 deletions(-) diff --git a/dll/win32/shell32/CDefView.cpp b/dll/win32/shell32/CDefView.cpp index 7617f85e5d7..bb3e88239c2 100644 --- a/dll/win32/shell32/CDefView.cpp +++ b/dll/win32/shell32/CDefView.cpp @@ -231,6 +231,7 @@ private: CComPtr<IShellFolderViewCB> m_pShellFolderViewCB; CComPtr<IShellBrowser> m_pShellBrowser; CComPtr<ICommDlgBrowser> m_pCommDlgBrowser; + CComPtr<IFolderFilter> m_pFolderFilter; CComPtr<IShellFolderViewDual> m_pShellFolderViewDual; CListView m_ListView; HWND m_hWndParent; @@ -636,14 +637,16 @@ HRESULT WINAPI CDefView::Initialize(IShellFolder *shellFolder) HRESULT CDefView::IncludeObject(PCUITEMID_CHILD pidl) { HRESULT ret = S_OK; - if (m_pCommDlgBrowser && !(GetCommDlgViewFlags() & CDB2GVF_NOINCLUDEITEM)) { TRACE("ICommDlgBrowser::IncludeObject pidl=%p\n", pidl); ret = m_pCommDlgBrowser->IncludeObject(this, pidl); TRACE("-- returns 0x%08x\n", ret); } - + else if (m_pFolderFilter) + { + ret = m_pFolderFilter->ShouldShow(m_pSFParent, m_pidlParent, pidl); + } return ret; } @@ -1484,7 +1487,7 @@ HRESULT CDefView::FillList(BOOL IsRefreshCommand) DWORD dwFetched; HRESULT hRes; HDPA hdpa; - DWORD dFlags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS; + DWORD dFlags = SHCONTF_NONFOLDERS | ((m_FolderSettings.fFlags & FWF_NOSUBFOLDERS) ? 0 : SHCONTF_FOLDERS); TRACE("%p\n", this); @@ -4006,6 +4009,9 @@ HRESULT STDMETHODCALLTYPE CDefView::SetCallback(IShellFolderViewCB *new_cb, ISh *old_cb = m_pShellFolderViewCB.Detach(); m_pShellFolderViewCB = new_cb; + m_pFolderFilter = NULL; + if (new_cb) + new_cb->QueryInterface(IID_PPV_ARG(IFolderFilter, &m_pFolderFilter)); return S_OK; } diff --git a/dll/win32/shell32/CEnumIDListBase.cpp b/dll/win32/shell32/CEnumIDListBase.cpp index 47adf6e2ea8..d0a79b350d1 100644 --- a/dll/win32/shell32/CEnumIDListBase.cpp +++ b/dll/win32/shell32/CEnumIDListBase.cpp @@ -96,33 +96,6 @@ BOOL CEnumIDListBase::DeleteList() return TRUE; } -/************************************************************************** - * HasItemWithCLSID() - */ -BOOL CEnumIDListBase::HasItemWithCLSID(LPITEMIDLIST pidl) -{ - ENUMLIST *pCur; - IID *ptr = _ILGetGUIDPointer(pidl); - - if (ptr) - { - REFIID refid = *ptr; - pCur = mpFirst; - - while(pCur) - { - LPGUID curid = _ILGetGUIDPointer(pCur->pidl); - if (curid && IsEqualGUID(*curid, refid)) - { - return TRUE; - } - pCur = pCur->pNext; - } - } - - return FALSE; -} - HRESULT CEnumIDListBase::AppendItemsFromEnumerator(IEnumIDList* pEnum) { LPITEMIDLIST pidl; diff --git a/dll/win32/shell32/CEnumIDListBase.h b/dll/win32/shell32/CEnumIDListBase.h index 65ec9058c42..68ce0966617 100644 --- a/dll/win32/shell32/CEnumIDListBase.h +++ b/dll/win32/shell32/CEnumIDListBase.h @@ -27,7 +27,7 @@ class CEnumIDListBase : public CComObjectRootEx<CComMultiThreadModelNoCS>, public IEnumIDList { -private: +protected: ENUMLIST *mpFirst; ENUMLIST *mpLast; ENUMLIST *mpCurrent; @@ -37,7 +37,19 @@ public: BOOL AddToEnumList(LPITEMIDLIST pidl); BOOL DeleteList(); BOOL HasItemWithCLSID(LPITEMIDLIST pidl); - HRESULT AppendItemsFromEnumerator(IEnumIDList* pEnum); + HRESULT AppendItemsFromEnumerator(IEnumIDList* pEnum); + + template <class T> BOOL HasItemWithCLSIDImpl(LPCITEMIDLIST pidl) + { + const CLSID * const pClsid = static_cast<T*>(this)->GetPidlClsid((PCUITEMID_CHILD)pidl); + for (ENUMLIST *pCur = mpFirst; pClsid && pCur; pCur = pCur->pNext) + { + const CLSID * const pEnumClsid = static_cast<T*>(this)->GetPidlClsid((PCUITEMID_CHILD)pCur->pidl); + if (pEnumClsid && IsEqualCLSID(*pClsid, *pEnumClsid)) + return TRUE; + } + return FALSE; + } // *** IEnumIDList methods *** STDMETHOD(Next)(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched) override; diff --git a/dll/win32/shell32/folders/CControlPanelFolder.cpp b/dll/win32/shell32/folders/CControlPanelFolder.cpp index 58d5c36353c..729112d68e8 100644 --- a/dll/win32/shell32/folders/CControlPanelFolder.cpp +++ b/dll/win32/shell32/folders/CControlPanelFolder.cpp @@ -23,6 +23,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(shell); +static const REGFOLDERINFO g_RegFolderInfo = +{ + PT_CONTROLS_NEWREGITEM, + 0, NULL, + CLSID_ControlPanel, + L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}", + L"ControlPanel", +}; + /*********************************************************************** * control panel implementation in shell namespace */ @@ -627,11 +636,10 @@ HRESULT WINAPI CControlPanelFolder::Initialize(PCIDLIST_ABSOLUTE pidl) pidlRoot = ILClone(pidl); /* Create the inner reg folder */ + REGFOLDERINITDATA RegInit = { static_cast<IShellFolder*>(this), &g_RegFolderInfo }; HRESULT hr; - hr = CRegFolder_CreateInstance(&CLSID_ControlPanel, + hr = CRegFolder_CreateInstance(&RegInit, pidlRoot, - L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}", - L"ControlPanel", IID_PPV_ARG(IShellFolder2, &m_regFolder)); if (FAILED_UNEXPECTEDLY(hr)) return hr; diff --git a/dll/win32/shell32/folders/CDesktopFolder.cpp b/dll/win32/shell32/folders/CDesktopFolder.cpp index c95828dc6fc..ee1c10834dc 100644 --- a/dll/win32/shell32/folders/CDesktopFolder.cpp +++ b/dll/win32/shell32/folders/CDesktopFolder.cpp @@ -25,11 +25,35 @@ WINE_DEFAULT_DEBUG_CHANNEL(shell); +extern BOOL SHELL32_IsShellFolderNamespaceItemHidden(LPCWSTR SubKey, REFCLSID Clsid); + +static const REQUIREDREGITEM g_RequiredItems[] = +{ + { CLSID_MyComputer, "sysdm.cpl", 0x50 }, + { CLSID_NetworkPlaces, "ncpa.cpl", 0x58 }, + { CLSID_Internet, "inetcpl.cpl", 0x68 }, +}; +static const REGFOLDERINFO g_RegFolderInfo = +{ + PT_DESKTOP_REGITEM, + _countof(g_RequiredItems), g_RequiredItems, + CLSID_ShellDesktop, + L"", + L"Desktop", +}; + static BOOL IsSelf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl) { return cidl == 0 || (cidl == 1 && apidl && _ILIsEmpty(apidl[0])); } +static const CLSID* IsRegItem(PCUITEMID_CHILD pidl) +{ + if (pidl && pidl->mkid.cb == 2 + 2 + sizeof(CLSID) && pidl->mkid.abID[0] == PT_GUID) + return (const CLSID*)(&pidl->mkid.abID[2]); + return NULL; +} + STDMETHODIMP CDesktopFolder::ShellUrlParseDisplayName( HWND hwndOwner, @@ -153,49 +177,13 @@ The CDesktopFolderEnum class should create two enumerators, one for each of the system folders, and enumerate the contents of each folder. Since the CRegFolder implementation of IShellFolder::EnumObjects enumerates the virtual items, the CDesktopFolderEnum is only responsible for returning the physical items. -CDesktopFolderEnum is incorrect where it filters My Computer from the enumeration -if the new start menu is used. The CDesktopViewCallback is responsible for filtering -it from the view by handling the IncludeObject query to return S_FALSE. The enumerator -always shows My Computer. +CDesktopFolderViewCB is responsible for filtering hidden regitems. +The enumerator always shows My Computer. */ /* Undocumented functions from shdocvw */ extern "C" HRESULT WINAPI IEParseDisplayNameWithBCW(DWORD codepage, LPCWSTR lpszDisplayName, LPBC pbc, LPITEMIDLIST *ppidl); -static const WCHAR ClassicStartMenuW[] = L"SOFTWARE\\Microsoft\\Windows\\" - L"CurrentVersion\\Explorer\\HideDesktopIcons\\ClassicStartMenu"; - -static INT -IsNamespaceExtensionHidden(const WCHAR *iid) -{ - DWORD Result, dwResult; - dwResult = sizeof(DWORD); - - if (RegGetValueW(HKEY_CURRENT_USER, /* FIXME use NewStartPanel when activated */ - ClassicStartMenuW, - iid, - RRF_RT_DWORD, - NULL, - &Result, - &dwResult) != ERROR_SUCCESS) - { - return -1; - } - - return Result; -} - -static INT IsNamespaceExtensionHidden(LPCITEMIDLIST pidl) -{ - GUID const *clsid = _ILGetGUIDPointer (pidl); - if (!clsid) - return -1; - - WCHAR pwszGuid[CHARS_IN_GUID]; - SHELL32_GUIDToStringW(*clsid, pwszGuid); - return IsNamespaceExtensionHidden(pwszGuid); -} - class CDesktopFolderEnum : public CEnumIDListBase { @@ -204,85 +192,20 @@ class CDesktopFolderEnum : // CComPtr fCommonDesktopEnumerator; public: - void AddItemsFromClassicStartMenuKey(HKEY hKeyRoot) + HRESULT WINAPI Initialize(IShellFolder *pRegFolder, SHCONTF dwFlags, IEnumIDList *pRegEnumerator, + IEnumIDList *pDesktopEnumerator, IEnumIDList *pCommonDesktopEnumerator) { - DWORD dwResult; - HKEY hkey; - DWORD j = 0, dwVal, Val, dwType, dwIID; - LONG r; - WCHAR iid[50]; - LPITEMIDLIST pidl; - - dwResult = RegOpenKeyExW(hKeyRoot, ClassicStartMenuW, 0, KEY_READ, &hkey); - if (dwResult != ERROR_SUCCESS) - return; - - while(1) - { - dwVal = sizeof(Val); - dwIID = sizeof(iid) / sizeof(WCHAR); - - r = RegEnumValueW(hkey, j++, iid, &dwIID, NULL, &dwType, (LPBYTE)&Val, &dwVal); - if (r != ERROR_SUCCESS) - break; - - if (Val == 0 && dwType == REG_DWORD) - { - pidl = _ILCreateGuidFromStrW(iid); - if (pidl != NULL) - { - if (!HasItemWithCLSID(pidl)) - AddToEnumList(pidl); - else - SHFree(pidl); - } - } - } - RegCloseKey(hkey); - } - - HRESULT WINAPI Initialize(DWORD dwFlags,IEnumIDList * pRegEnumerator, IEnumIDList *pDesktopEnumerator, IEnumIDList *pCommonDesktopEnumerator) - { - BOOL ret = TRUE; - LPITEMIDLIST pidl; - - static const WCHAR MyDocumentsClassString[] = L"{450D8FBA-AD25-11D0-98A8-0800361B1103}"; - static const WCHAR InternetClassString[] = L"{871C5380-42A0-1069-A2EA-08002B30309D}"; - TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags); - /* enumerate the root folders */ - if (dwFlags & SHCONTF_FOLDERS) - { - AddToEnumList(_ILCreateMyComputer()); - if (IsNamespaceExtensionHidden(MyDocumentsClassString) < 1) - AddToEnumList(_ILCreateMyDocuments()); - if (IsNamespaceExtensionHidden(InternetClassString) < 1) - AddToEnumList(_ILCreateIExplore()); - - DWORD dwFetched; - while((S_OK == pRegEnumerator->Next(1, &pidl, &dwFetched)) && dwFetched) - { - if (IsNamespaceExtensionHidden(pidl) < 1) - { - if (!HasItemWithCLSID(pidl)) - AddToEnumList(pidl); - else - SHFree(pidl); - } - } - AddItemsFromClassicStartMenuKey(HKEY_LOCAL_MACHINE); - AddItemsFromClassicStartMenuKey(HKEY_CURRENT_USER); - } + AppendItemsFromEnumerator(pRegEnumerator); /* Enumerate the items in the two fs folders */ AppendItemsFromEnumerator(pDesktopEnumerator); AppendItemsFromEnumerator(pCommonDesktopEnumerator); - return ret ? S_OK : E_FAIL; + return S_OK; } - BEGIN_COM_MAP(CDesktopFolderEnum) COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList) END_COM_MAP() @@ -337,10 +260,9 @@ HRESULT WINAPI CDesktopFolder::FinalConstruct() return hr; /* Create the inner reg folder */ - hr = CRegFolder_CreateInstance(&CLSID_ShellDesktop, + REGFOLDERINITDATA RegInit = { static_cast<IShellFolder*>(this), &g_RegFolderInfo }; + hr = CRegFolder_CreateInstance(&RegInit, pidlRoot, - L"", - L"Desktop", IID_PPV_ARG(IShellFolder2, &m_regFolder)); if (FAILED_UNEXPECTEDLY(hr)) return hr; @@ -621,7 +543,8 @@ HRESULT WINAPI CDesktopFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUM if (FAILED(hr)) ERR("EnumObjects for shared desktop fs folder failed\n"); - return ShellObjectCreatorInit<CDesktopFolderEnum>(dwFlags,pRegEnumerator, pDesktopEnumerator, pCommonDesktopEnumerator, IID_PPV_ARG(IEnumIDList, ppEnumIDList)); + return ShellObjectCreatorInit<CDesktopFolderEnum>(m_regFolder, dwFlags, pRegEnumerator, pDesktopEnumerator, + pCommonDesktopEnumerator, IID_PPV_ARG(IEnumIDList, ppEnumIDList)); } /************************************************************************** @@ -726,8 +649,14 @@ HRESULT WINAPI CDesktopFolder::CreateViewObject( } else if (IsEqualIID (riid, IID_IShellView)) { - SFV_CREATE sfvparams = {sizeof(SFV_CREATE), this}; - hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppvOut); + CComPtr<CDesktopFolderViewCB> sfviewcb; + if (SUCCEEDED(hr = ShellObjectCreator(sfviewcb))) + { + SFV_CREATE create = { sizeof(create), this, NULL, sfviewcb }; + hr = SHCreateShellFolderView(&create, (IShellView**)ppvOut); + if (SUCCEEDED(hr)) + sfviewcb->Initialize((IShellView*)*ppvOut); + } } TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut); return hr; @@ -1102,6 +1031,48 @@ HRESULT WINAPI CDesktopFolder::CallBack(IShellFolder *psf, HWND hwndOwner, IData return SHELL32_DefaultContextMenuCallBack(psf, pdtobj, uMsg); } +/************************************************************************* + * CDesktopFolderViewCB + */ + +bool CDesktopFolderViewCB::IsProgmanHostedBrowser(IShellView *psv) +{ + FOLDERSETTINGS settings; + return SUCCEEDED(psv->GetCurrentInfo(&settings)) && (settings.fFlags & FWF_DESKTOP); +} + +bool CDesktopFolderViewCB::IsProgmanHostedBrowser() +{ + enum { Uninitialized = 0, NotHosted, IsHosted }; + C_ASSERT(Uninitialized == 0); + if (m_IsProgmanHosted == Uninitialized) + m_IsProgmanHosted = m_pShellView && IsProgmanHostedBrowser(m_pShellView) ? IsHosted : NotHosted; + return m_IsProgmanHosted == IsHosted; +} + +HRESULT WINAPI CDesktopFolderViewCB::ShouldShow(IShellFolder *psf, PCIDLIST_ABSOLUTE pidlFolder, PCUITEMID_CHILD pidlItem) +{ + const CLSID* pClsid; + if (IsProgmanHostedBrowser() && (pClsid = IsRegItem(pidlItem)) != NULL) + { + const BOOL NewStart = SHELL_GetSetting(SSF_STARTPANELON, fStartPanelOn); + LPCWSTR SubKey = NewStart ? L"HideDesktopIcons\\NewStartPanel" : L"HideDesktopIcons\\ClassicStartMenu"; + return SHELL32_IsShellFolderNamespaceItemHidden(SubKey, *pClsid) ? S_FALSE : S_OK; + } + return S_OK; +} + +HRESULT WINAPI CDesktopFolderViewCB::MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case SFVM_VIEWRELEASE: + m_pShellView = NULL; + return S_OK; + } + return E_NOTIMPL; +} + /************************************************************************* * SHGetDesktopFolder [SHELL32.@] */ diff --git a/dll/win32/shell32/folders/CDesktopFolder.h b/dll/win32/shell32/folders/CDesktopFolder.h index 66eda8df0ee..0f8ea5a35a2 100644 --- a/dll/win32/shell32/folders/CDesktopFolder.h +++ b/dll/win32/shell32/folders/CDesktopFolder.h @@ -145,4 +145,33 @@ class CDesktopFolder : END_COM_MAP() }; +class CDesktopFolderViewCB : + public CComObjectRootEx<CComMultiThreadModelNoCS>, + public IShellFolderViewCB, + public IFolderFilter +{ + IShellView *m_pShellView; // Not ref-counted! + UINT8 m_IsProgmanHosted; + + public: + CDesktopFolderViewCB() : m_IsProgmanHosted(0) {} + void Initialize(IShellView *psv) { m_pShellView = psv; } + static bool IsProgmanHostedBrowser(IShellView *psv); + bool IsProgmanHostedBrowser(); + + // IShellFolderViewCB + STDMETHOD(MessageSFVCB)(UINT uMsg, WPARAM wParam, LPARAM lParam) override; + + // IFolderFilter + STDMETHOD(ShouldShow)(IShellFolder *psf, PCIDLIST_ABSOLUTE pidlFolder, PCUITEMID_CHILD pidlItem) override; + STDMETHODIMP GetEnumFlags(IShellFolder*, PCIDLIST_ABSOLUTE, HWND*, DWORD*) override { return E_NOTIMPL; } + + DECLARE_NO_REGISTRY() + DECLARE_NOT_AGGREGATABLE(CDesktopFolderViewCB) + BEGIN_COM_MAP(CDesktopFolderViewCB) + COM_INTERFACE_ENTRY_IID(IID_IShellFolderViewCB, IShellFolderViewCB) + COM_INTERFACE_ENTRY_IID(IID_IFolderFilter, IFolderFilter) + END_COM_MAP() +}; + #endif /* _CDESKTOPFOLDER_H_ */ diff --git a/dll/win32/shell32/folders/CDrivesFolder.cpp b/dll/win32/shell32/folders/CDrivesFolder.cpp index 9cc549a842a..56422f83946 100644 --- a/dll/win32/shell32/folders/CDrivesFolder.cpp +++ b/dll/win32/shell32/folders/CDrivesFolder.cpp @@ -55,6 +55,29 @@ static int iDriveTypeIds[7] = { IDS_DRIVE_FIXED, /* DRIVE_UNKNOWN */ IDS_DRIVE_FIXED /* DRIVE_RAMDISK*/ }; +static const REQUIREDREGITEM g_RequiredItems[] = +{ + { CLSID_ControlPanel, 0, 0x50 }, +}; +static const REGFOLDERINFO g_RegFolderInfo = +{ + PT_COMPUTER_REGITEM, + _countof(g_RequiredItems), g_RequiredItems, + CLSID_MyComputer, + L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}", + L"MyComputer", +}; + +static const CLSID* IsRegItem(PCUITEMID_CHILD pidl) +{ + if (pidl && pidl->mkid.cb == 2 + 2 + sizeof(CLSID)) + { + if (pidl->mkid.abID[0] == PT_SHELLEXT || pidl->mkid.abID[0] == PT_GUID) // FIXME: Remove PT_GUID when CRegFolder is fixed + return (const CLSID*)(&pidl->mkid.abID[2]); + } + return NULL; +} + BOOL _ILGetDriveType(LPCITEMIDLIST pidl) { WCHAR szDrive[8]; @@ -66,6 +89,16 @@ BOOL _ILGetDriveType(LPCITEMIDLIST pidl) return ::GetDriveTypeW(szDrive); } +BOOL SHELL32_IsShellFolderNamespaceItemHidden(LPCWSTR SubKey, REFCLSID Clsid) +{ + // If this function returns true, the item should be hidden in DefView but not in the Explorer folder tree. + WCHAR path[MAX_PATH], name[CHARS_IN_GUID]; + wsprintfW(path, L"%s\\%s", REGSTR_PATH_EXPLORER, SubKey); + SHELL32_GUIDToStringW(Clsid, name); + DWORD data = 0, size = sizeof(data); + return !RegGetValueW(HKEY_CURRENT_USER, path, name, RRF_RT_DWORD, NULL, &data, &size) && data; +} + /*********************************************************************** * IShellFolder implementation */ @@ -643,10 +676,9 @@ HRESULT WINAPI CDrivesFolder::FinalConstruct() if (pidlRoot == NULL) return E_OUTOFMEMORY; - HRESULT hr = CRegFolder_CreateInstance(&CLSID_MyComputer, + REGFOLDERINITDATA RegInit = { static_cast<IShellFolder*>(this), &g_RegFolderInfo }; + HRESULT hr = CRegFolder_CreateInstance(&RegInit, pidlRoot, - L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}", - L"MyComputer", IID_PPV_ARG(IShellFolder2, &m_regFolder)); return hr; @@ -901,7 +933,7 @@ HRESULT WINAPI CDrivesFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVO } else if (IsEqualIID(riid, IID_IShellView)) { - SFV_CREATE sfvparams = {sizeof(SFV_CREATE), this}; + SFV_CREATE sfvparams = { sizeof(SFV_CREATE), this, NULL, static_cast<IShellFolderViewCB*>(this) }; hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppvOut); } TRACE("-- (%p)->(interface=%p)\n", this, ppvOut); @@ -937,11 +969,17 @@ HRESULT WINAPI CDrivesFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY a *rgfInOut &= ~SFGAO_CANRENAME; // CD-ROM drive cannot rename } else if (_ILIsControlPanel(apidl[i])) + { *rgfInOut &= dwControlPanelAttributes; + } else if (_ILIsSpecialFolder(*apidl)) + { m_regFolder->GetAttributesOf(1, &apidl[i], rgfInOut); + } else + { ERR("Got unknown pidl type!\n"); + } } } @@ -1302,6 +1340,16 @@ HRESULT WINAPI CDrivesFolder::GetCurFolder(PIDLIST_ABSOLUTE *pidl) return S_OK; } +/************************************************************************** + * CDrivesFolder::ShouldShow + */ +HRESULT WINAPI CDrivesFolder::ShouldShow(IShellFolder *psf, PCIDLIST_ABSOLUTE pidlFolder, PCUITEMID_CHILD pidlItem) +{ + if (const CLSID* pClsid = IsRegItem(pidlItem)) + return SHELL32_IsShellFolderNamespaceItemHidden(L"HideMyComputerIcons", *pClsid) ? S_FALSE : S_OK; + return S_OK; +} + /************************************************************************/ /* IContextMenuCB interface */ diff --git a/dll/win32/shell32/folders/CDrivesFolder.h b/dll/win32/shell32/folders/CDrivesFolder.h index 7958027b545..a4222b88362 100644 --- a/dll/win32/shell32/folders/CDrivesFolder.h +++ b/dll/win32/shell32/folders/CDrivesFolder.h @@ -28,7 +28,9 @@ class CDrivesFolder : public CComObjectRootEx<CComMultiThreadModelNoCS>, public IShellFolder2, public IPersistFolder2, - public IContextMenuCB + public IContextMenuCB, + public IShellFolderViewCB, // Only exists so DefView can get IFolderFilter + public IFolderFilter { private: /* both paths are parsible from the desktop */ @@ -73,6 +75,13 @@ class CDrivesFolder : // IContextMenuCB STDMETHOD(CallBack)(IShellFolder *psf, HWND hwndOwner, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam) override; + // IShellFolderViewCB + STDMETHODIMP MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam) override { return E_NOTIMPL; } + + // IFolderFilter + STDMETHOD(ShouldShow)(IShellFolder *psf, PCIDLIST_ABSOLUTE pidlFolder, PCUITEMID_CHILD pidlItem) override; + STDMETHODIMP GetEnumFlags(IShellFolder*, PCIDLIST_ABSOLUTE, HWND*, DWORD*) override { return E_NOTIMPL; } + DECLARE_REGISTRY_RESOURCEID(IDR_MYCOMPUTER) DECLARE_CENTRAL_INSTANCE_NOT_AGGREGATABLE(CDrivesFolder) @@ -85,6 +94,8 @@ class CDrivesFolder : COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2) COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist) COM_INTERFACE_ENTRY_IID(IID_IContextMenuCB, IContextMenuCB) + COM_INTERFACE_ENTRY_IID(IID_IShellFolderViewCB, IShellFolderViewCB) + COM_INTERFACE_ENTRY_IID(IID_IFolderFilter, IFolderFilter) END_COM_MAP() }; diff --git a/dll/win32/shell32/folders/CFSFolder.cpp b/dll/win32/shell32/folders/CFSFolder.cpp index 8b444f05635..bde0d6dbb42 100644 --- a/dll/win32/shell32/folders/CFSFolder.cpp +++ b/dll/win32/shell32/folders/CFSFolder.cpp @@ -596,13 +596,33 @@ HRESULT SHELL32_GetFSItemAttributes(IShellFolder * psf, LPCITEMIDLIST pidl, LPDW BOOL bDirectory = (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; + if (SFGAO_VALIDATE & *pdwAttributes) + { + STRRET strret; + LPWSTR path; + if (SUCCEEDED(psf->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &strret)) && + SUCCEEDED(StrRetToStrW(&strret, pidl, &path))) + { + BOOL exists = PathFileExistsW(path); + SHFree(path); + if (!exists) + return E_FAIL; + } + } + if (!bDirectory) { // https://git.reactos.org/?p=reactos.git;a=blob;f=dll/shellext/zipfldr/res/zipfldr.rgs;hb=032b5aacd233cd7b83ab6282aad638c161fdc400#l9 WCHAR szFileName[MAX_PATH]; LPWSTR pExtension; + BOOL hasName = _ILSimpleGetTextW(pidl, szFileName, _countof(szFileName)); + + // Vista+ feature: Hidden files with a leading tilde treated as super-hidden + // See https://devblogs.microsoft.com/oldnewthing/20170526-00/?p=96235 + if (hasName && szFileName[0] == '~' && (dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)) + dwShellAttributes |= SFGAO_HIDDEN | SFGAO_SYSTEM; - if (_ILSimpleGetTextW(pidl, szFileName, _countof(szFileName)) && (pExtension = PathFindExtensionW(szFileName))) + if (hasName && (pExtension = PathFindExtensionW(szFileName))) { CLSID clsidFile; // FIXME: Cache this? @@ -626,7 +646,7 @@ HRESULT SHELL32_GetFSItemAttributes(IShellFolder * psf, LPCITEMIDLIST pidl, LPDW ::RegCloseKey(hkey); // This should be presented as directory! - bDirectory = TRUE; + bDirectory = (dwAttributes & SFGAO_FOLDER) != 0 || dwAttributes == 0; TRACE("Treating '%S' as directory!\n", szFileName); } } @@ -650,10 +670,26 @@ HRESULT SHELL32_GetFSItemAttributes(IShellFolder * psf, LPCITEMIDLIST pidl, LPDW } if (dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) - dwShellAttributes |= SFGAO_HIDDEN; + dwShellAttributes |= SFGAO_HIDDEN | SFGAO_GHOSTED; if (dwFileAttributes & FILE_ATTRIBUTE_READONLY) - dwShellAttributes |= SFGAO_READONLY; + dwShellAttributes |= SFGAO_READONLY; + + if (dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) + dwShellAttributes |= SFGAO_SYSTEM; + + if (dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) + dwShellAttributes |= SFGAO_COMPRESSED; + + if (dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) + dwShellAttributes |= SFGAO_ENCRYPTED; + + if ((SFGAO_NONENUMERATED & *pdwAttributes) && (dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)) + { + SHCONTF shcf = SHELL_GetDefaultFolderEnumSHCONTF(); + if ((!(shcf & SHCONTF_INCLUDEHIDDEN)) || ((dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) && !(shcf & SHCONTF_INCLUDESUPERHIDDEN))) + dwShellAttributes |= SFGAO_NONENUMERATED; + } if (SFGAO_LINK & *pdwAttributes) { diff --git a/dll/win32/shell32/folders/CRegFolder.cpp b/dll/win32/shell32/folders/CRegFolder.cpp index 8d8223c3924..510727a6b67 100644 --- a/dll/win32/shell32/folders/CRegFolder.cpp +++ b/dll/win32/shell32/folders/CRegFolder.cpp @@ -16,116 +16,114 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * The required-regitem design is based on the research by Geoff Chappell + * https://www.geoffchappell.com/studies/windows/shell/shell32/classes/regfolder.htm */ #include <precomp.h> WINE_DEFAULT_DEBUG_CHANNEL (shell); -HRESULT CALLBACK RegFolderContextMenuCallback(IShellFolder *psf, - HWND hwnd, - IDataObject *pdtobj, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) -{ - if (uMsg != DFM_INVOKECOMMAND || wParam != DFM_CMD_PROPERTIES) - return SHELL32_DefaultContextMenuCallBack(psf, pdtobj, uMsg); +#define DEFAULTSORTORDERINDEX 0x80 // The default for registry items according to Geoff Chappell - PIDLIST_ABSOLUTE pidlFolder; - PUITEMID_CHILD *apidl; - UINT cidl; - HRESULT hr = SH_GetApidlFromDataObject(pdtobj, &pidlFolder, &apidl, &cidl); - if (FAILED_UNEXPECTEDLY(hr)) - return hr; +static HRESULT CRegItemContextMenu_CreateInstance(PCIDLIST_ABSOLUTE pidlFolder, HWND hwnd, UINT cidl, + PCUITEMID_CHILD_ARRAY apidl, IShellFolder *psf, IContextMenu **ppcm); - if (_ILIsMyComputer(apidl[0])) - { - if (!SHELL_ExecuteControlPanelCPL(hwnd, L"sysdm.cpl")) - { - hr = E_FAIL; - } - } - else if (_ILIsDesktop(apidl[0])) - { - if (!SHELL_ExecuteControlPanelCPL(hwnd, L"desk.cpl")) - { - hr = E_FAIL; - } - } - else if (_ILIsNetHood(apidl[0])) - { - // FIXME path! - if (32 >= (UINT_PTR)ShellExecuteW(NULL, - L"open", - L"explorer.exe", - L"::{7007ACC7-3202-11D1-AAD2-00805FC1270E}", - NULL, - SW_SHOWDEFAULT)) - { - hr = E_FAIL; - } - } - else if (_ILIsBitBucket(apidl[0])) - { - /* FIXME: detect the drive path of bitbucket if appropiate */ - if (!SH_ShowRecycleBinProperties(L'C')) - hr = E_FAIL; - } - else +static inline UINT GetRegItemCLSIDOffset(PIDLTYPE type) +{ + return type == PT_CONTROLS_NEWREGITEM ? 14 : 4; +} + +static LPITEMIDLIST CreateRegItem(PIDLTYPE type, REFCLSID clsid, BYTE order = 0) +{ +#if 1 // FIXME: CControlPanelFolder is not ready for this yet + if (type == PT_CONTROLS_NEWREGITEM) + type = PT_CONTROLS_OLDREGITEM; +#endif + const UINT offset = GetRegItemCLSIDOffset(type); + const UINT cb = offset + sizeof(CLSID), cbTotal = cb + sizeof(WORD); + LPITEMIDLIST pidl = (LPITEMIDLIST)SHAlloc(cbTotal); + if (pidl) { - /* Tell the caller to run the default action */ - hr = S_FALSE; + ZeroMemory(pidl, cbTotal); // Note: This also initializes the terminator WORD + pidl->mkid.cb = cb; + pidl->mkid.abID[0] = type; + pidl->mkid.abID[1] = order; + *(CLSID*)(SIZE_T(pidl) + offset) = clsid; } + return pidl; +} - SHFree(pidlFolder); - _ILFreeaPidl(apidl, cidl); - - return hr; +static LPITEMIDLIST CreateRegItem(PIDLTYPE type, LPCWSTR clsidstr) +{ + CLSID clsid; + return SUCCEEDED(CLSIDFromString(clsidstr, &clsid)) ? CreateRegItem(type, clsid) : NULL; } -HRESULT CGuidItemContextMenu_CreateInstance(PCIDLIST_ABSOLUTE pidlFolder, - HWND hwnd, - UINT cidl, - PCUITEMID_CHILD_ARRAY apidl, - IShellFolder *psf, - IContextMenu **ppcm) +HRESULT FormatGUIDKey(LPWSTR KeyName, SIZE_T KeySize, LPCWSTR RegPath, const GUID* riid) { - HKEY hKeys[10]; - UINT cKeys = 0; + WCHAR xriid[CHARS_IN_GUID]; + StringFromGUID2(*riid, xriid, _countof(xriid)); + return StringCchPrintfW(KeyName, KeySize, RegPath, xriid); +} - GUID *pGuid = _ILGetGUIDPointer(apidl[0]); - if (pGuid) +static DWORD SHELL_QueryCLSIDValue(_In_ REFCLSID clsid, _In_opt_ LPCWSTR SubKey, _In_opt_ LPCWSTR Value, _In_opt_ PVOID pData, _In_opt_ PDWORD pSize) +{ + WCHAR Path[MAX_PATH]; + wcscpy(Path, L"CLSID\\"); + StringFromGUID2(clsid, Path + 6, 39); + if (SubKey) { - WCHAR key[60]; - wcscpy(key, L"CLSID\\"); - StringFromGUID2(*pGuid, &key[6], 39); - AddClassKeyToArray(key, hKeys, &cKeys); + wcscpy(Path + 6 + 38, L"\\"); + wcscpy(Path + 6 + 39, SubKey); } + return RegGetValueW(HKEY_CLASSES_ROOT, Path, Value, RRF_RT_ANY, NULL, pData, pSize); +} - // FIXME: CRegFolder should be aggregated by its outer folder and should - // provide the attributes for all required non-registry folders. - // It currently does not so we have to ask the outer folder ourself so - // that we get the correct attributes for My Computer etc. - CComPtr<IShellFolder> pOuterSF; - SHBindToObject(NULL, pidlFolder, IID_PPV_ARG(IShellFolder, &pOuterSF)); - - SFGAOF att = (psf && cidl) ? SHGetAttributes(pOuterSF ? pOuterSF.p : psf, apidl[0], SFGAO_FOLDER) : 0; - if (att & SFGAO_FOLDER) - AddClassKeyToArray(L"Folder", hKeys, &cKeys); - - return CDefFolderMenu_Create2(pidlFolder, hwnd, cidl, apidl, psf, RegFolderContextMenuCallback, cKeys, hKeys, ppcm); +static bool HasCLSIDShellFolderValue(REFCLSID clsid, LPCWSTR Value) +{ + return SHELL_QueryCLSIDValue(clsid, L"ShellFolder", Value, NULL, NULL) == ERROR_SUCCESS; } -HRESULT FormatGUIDKey(LPWSTR KeyName, SIZE_T KeySize, LPCWSTR RegPath, const GUID* riid) +struct CRegFolderInfo { - WCHAR xriid[40]; + const REGFOLDERINFO *m_pInfo; - if (!StringFromGUID2(*riid, xriid, _countof(xriid) - 1)) - return E_FAIL; + void InitializeFolderInfo(const REGFOLDERINFO *pInfo) + { + m_pInfo = pInfo; + } - return StringCchPrintfW(KeyName, KeySize, RegPath, xriid); -} + const CLSID* IsRegItem(LPCITEMIDLIST pidl) const + { + if (pidl && pidl->mkid.cb >= sizeof(WORD) + 1 + 1 + sizeof(GUID)) + { + if (pidl->mkid.abID[0] == m_pInfo->PidlType) + return (CLSID*)(SIZE_T(pidl) + GetCLSIDOffset()); + if (pidl->mkid.abID[0] == PT_CONTROLS_OLDREGITEM) + return (CLSID*)(SIZE_T(pidl) + GetRegItemCLSIDOffset(PT_CONTROLS_OLDREGITEM)); + } + if (const IID* pIID = _ILGetGUIDPointer(pidl)) + { + FIXME("Unexpected GUID PIDL type %#x\n", pidl->mkid.abID[0]); + return pIID; // FIXME: Remove this when all folders have been fixed + } + return NULL; + } + + LPITEMIDLIST CreateItem(size_t i) const + { + const REQUIREDREGITEM &item = GetAt(i); + return CreateRegItem(GetPidlType(), item.clsid, item.Order); + } + + LPCWSTR GetParsingPath() const { return m_pInfo->pszParsingPath; } + UINT GetCLSIDOffset() const { return GetRegItemCLSIDOffset(m_pInfo->PidlType); } + PIDLTYPE GetPidlType() const { return m_pInfo->PidlType; } + UINT GetRequiredItemsCount() const { return m_pInfo->Count; } + const REQUIREDREGITEM& GetAt(size_t i) const { return m_pInfo->Items[i]; } +}; HRESULT CGuidItemExtractIcon_CreateInstance(LPCITEMIDLIST pidl, REFIID iid, LPVOID * ppvOut) { @@ -213,47 +211,52 @@ HRESULT CGuidItemExtractIcon_CreateInstance(LPCITEMIDLIST pidl, REFIID iid, LPVO } class CRegFolderEnum : - public CEnumIDListBase + public CEnumIDListBase, + public CRegFolderInfo { + SHCONTF m_SHCTF; public: - CRegFolderEnum(); - ~CRegFolderEnum(); - HRESULT Initialize(LPCWSTR lpszEnumKeyName, DWORD dwFlags); - HRESULT AddItemsFromKey(HKEY hkey_root, LPCWSTR szRepPath); + HRESULT Initialize(const REGFOLDERINFO *pInfo, IShellFolder *pSF, DWORD dwFlags); + HRESULT AddItemsFromKey(IShellFolder *pSF, HKEY hkey_root, LPCWSTR szRepPath); + + const CLSID* GetPidlClsid(PCUITEMID_CHILD pidl) { return IsRegItem(pidl); } + BOOL HasItemWithCLSID(LPCITEMIDLIST pidl) { return HasItemWithCLSIDImpl<CRegFolderEnum>(pidl); } BEGIN_COM_MAP(CRegFolderEnum) COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList) END_COM_MAP() }; -CRegFolderEnum::CRegFolderEnum() +HRESULT CRegFolderEnum::Initialize(const REGFOLDERINFO *pInfo, IShellFolder *pSF, DWORD dwFlags) { -} - -CRegFolderEnum::~CRegFolderEnum() -{ -} - -HRESULT CRegFolderEnum::Initialize(LPCWSTR lpszEnumKeyName, DWORD dwFlags) -{ - WCHAR KeyName[MAX_PATH]; - + InitializeFolderInfo(pInfo); + m_SHCTF = (SHCONTF)dwFlags; if (!(dwFlags & SHCONTF_FOLDERS)) return S_OK; - HRESULT hr = StringCchPrintfW(KeyName, MAX_PATH, + WCHAR KeyName[MAX_PATH]; + HRESULT hr = StringCchPrintfW(KeyName, _countof(KeyName), L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\%s\\Namespace", - lpszEnumKeyName); + pInfo->pszEnumKeyName); if (FAILED_UNEXPECTEDLY(hr)) return hr; - AddItemsFromKey(HKEY_LOCAL_MACHINE, KeyName); - AddItemsFromKey(HKEY_CURRENT_USER, KeyName); - + // First add the required items and then the items from the registry + SFGAOF query = SHELL_CreateFolderEnumItemAttributeQuery(m_SHCTF, TRUE); + for (size_t i = 0; i < GetRequiredItemsCount(); ++i) + { + LPITEMIDLIST pidl = CreateItem(i); + if (pidl && SHELL_IncludeItemInFolderEnum(pSF, pidl, query, m_SHCTF)) + AddToEnumList(pidl); + else + ILFree(pidl); + } + AddItemsFromKey(pSF, HKEY_LOCAL_MACHINE, KeyName); + AddItemsFromKey(pSF, HKEY_CURRENT_USER, KeyName); return S_OK; } -HRESULT CRegFolderEnum::AddItemsFromKey(HKEY hkey_root, LPCWSTR szRepPath) +HRESULT CRegFolderEnum::AddItemsFromKey(IShellFolder *pSF, HKEY hkey_root, LPCWSTR szRepPath) { WCHAR name[MAX_PATH]; HKEY hkey; @@ -275,13 +278,16 @@ HRESULT CRegFolderEnum::AddItemsFromKey(HKEY hkey_root, LPCWSTR szRepPath) if (*name == '{') { - LPITEMIDLIST pidl = _ILCreateGuidFromStrW(name); - - if (pidl) - AddToEnumList(pidl); + if (LPITEMIDLIST pidl = CreateRegItem(GetPidlType(), name)) + { + SFGAOF query = SHELL_CreateFolderEnumItemAttributeQuery(m_SHCTF, TRUE); + if (SHELL_IncludeItemInFolderEnum(pSF, pidl, query, m_SHCTF) && !HasItemWithCLSID(pidl)) + AddToEnumList(pidl); + else + ILFree(pidl); + } } } - RegCloseKey(hkey); return S_OK; @@ -301,12 +307,11 @@ enum REGFOLDERCOLUMNINDEX class CRegFolder : public CComObjectRootEx<CComMultiThreadModelNoCS>, - public IShellFolder2 + public IShellFolder2, + public CRegFolderInfo { private: - GUID m_guid; - CAtlStringW m_rootPath; - CAtlStringW m_enumKeyName; + IShellFolder *m_pOuterFolder; // Not ref-counted CComHeapPtr<ITEMIDLIST> m_pidlRoot; HRESULT GetGuidItemAttributes (LPCITEMIDLIST pidl, LPDWORD pdwAttributes); @@ -315,7 +320,19 @@ class CRegFolder : public: CRegFolder(); ~CRegFolder(); - HRESULT WINAPI Initialize(const GUID *pGuid, LPCITEMIDLIST pidlRoot, LPCWSTR lpszPath, LPCWSTR lpszEnumKeyName); + HRESULT WINAPI Initialize(PREGFOLDERINITDATA pInit, LPCITEMIDLIST pidlRoot); + + const REQUIREDREGITEM* IsRequiredItem(LPCITEMIDLIST pidl) const + { + const CLSID* const pCLSID = IsRegItem(pidl); + for (size_t i = 0; pCLSID && i < GetRequiredItemsCount(); ++i) + { + const REQUIREDREGITEM &item = GetAt(i); + if (item.clsid == *pCLSID) + return &item; + } + return NULL; + } // IShellFolder STDMETHOD(ParseDisplayName)(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, ULONG *pchEaten, PIDLIST_RELATIVE *ppidl, ULONG *pdwAttributes) override; @@ -356,17 +373,10 @@ CRegFolder::~CRegFolder() { } -HRESULT WINAPI CRegFolder::Initialize(const GUID *pGuid, LPCITEMIDLIST pidlRoot, LPCWSTR lpszPath, LPCWSTR lpszEnumKeyName) +HRESULT WINAPI CRegFolder::Initialize(PREGFOLDERINITDATA pInit, LPCITEMIDLIST pidlRoot) { - memcpy(&m_guid, pGuid, sizeof(m_guid)); - - m_rootPath = lpszPath; - if (!m_rootPath) - return E_OUTOFMEMORY; - - m_enumKeyName = lpszEnumKeyName; - if (!m_enumKeyName) - return E_OUTOFMEMORY; + InitializeFolderInfo(pInit->pInfo); + m_pOuterFolder = pInit->psfOuter; m_pidlRoot.Attach(ILClone(pidlRoot)); if (!m_pidlRoot) @@ -442,7 +452,7 @@ HRESULT WINAPI CRegFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR l return E_FAIL; } - CComHeapPtr<ITEMIDLIST> pidlTemp(_ILCreateGuid(PT_GUID, clsid)); + CComHeapPtr<ITEMIDLIST> pidlTemp(CreateRegItem(GetPidlType(), clsid)); if (!pidlTemp) return E_OUTOFMEMORY; @@ -471,7 +481,8 @@ HRESULT WINAPI CRegFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR l HRESULT WINAPI CRegFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList) { - return ShellObjectCreatorInit<CRegFolderEnum>(m_enumKeyName, dwFlags, IID_PPV_ARG(IEnumIDList, ppEnumIDList)); + return ShellObjectCreatorInit<CRegFolderEnum>(m_pInfo, m_pOuterFolder, dwFlags, + IID_PPV_ARG(IEnumIDList, ppEnumIDList)); } HRESULT WINAPI CRegFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut) @@ -529,14 +540,10 @@ HRESULT WINAPI CRegFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, P /* Guid folders come first compared to everything else */ /* And Drives come before folders in My Computer */ - if (_ILIsMyComputer(m_pidlRoot)) - { + if (GetPidlType() == PT_COMPUTER_REGITEM) return MAKE_COMPARE_HRESULT(clsid1 ? 1 : -1); - } else - { return MAKE_COMPARE_HRESULT(clsid1 ? -1 : 1); - } } HRESULT WINAPI CRegFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut) @@ -591,7 +598,7 @@ HRESULT WINAPI CRegFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CH return E_FAIL; } - hr = CGuidItemContextMenu_CreateInstance(m_pidlRoot, hwndOwner, cidl, apidl, static_cast<IShellFolder*>(this), (IContextMenu**)&pObj); + hr = CRegItemContextMenu_CreateInstance(m_pidlRoot, hwndOwner, cidl, apidl, static_cast<IShellFolder*>(this), (IContextMenu**)&pObj); } else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1)) { @@ -626,7 +633,7 @@ HRESULT WINAPI CRegFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, /* parsing name like ::{...} */ pszPath[0] = ':'; pszPath[1] = ':'; - SHELL32_GUIDToStringW(m_guid, &pszPath[2]); + SHELL32_GUIDToStringW(m_pInfo->clsid, &pszPath[2]); strRet->uType = STRRET_WSTR; strRet->pOleStr = pszPath; return S_OK; @@ -635,7 +642,7 @@ HRESULT WINAPI CRegFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, { BOOL bRet; WCHAR wstrName[MAX_PATH+1]; - bRet = HCR_GetClassNameW(m_guid, wstrName, MAX_PATH); + bRet = HCR_GetClassNameW(m_pInfo->clsid, wstrName, MAX_PATH); if (!bRet) return E_FAIL; @@ -698,7 +705,7 @@ HRESULT WINAPI CRegFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, PWCHAR pItemName = pszPath; // GET_SHGDN_RELATION(dwFlags) == SHGDN_INFOLDER if (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER) { - hr = StringCchCopyW(pszPath, cchPath, m_rootPath); + hr = StringCchCopyW(pszPath, cchPath, GetParsingPath()); if (SUCCEEDED(hr)) { pathlen = wcslen(pszPath); @@ -861,8 +868,79 @@ HRESULT WINAPI CRegFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid) return E_NOTIMPL; } +static HRESULT CALLBACK RegFolderContextMenuCallback(IShellFolder *psf, HWND hwnd, IDataObject *pdtobj, + UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if (uMsg != DFM_INVOKECOMMAND || wParam != DFM_CMD_PROPERTIES) + return SHELL32_DefaultContextMenuCallBack(psf, pdtobj, uMsg); + + PIDLIST_ABSOLUTE pidlFolder; + PUITEMID_CHILD *apidl; + UINT cidl; + HRESULT hr = SH_GetApidlFromDataObject(pdtobj, &pidlFolder, &apidl, &cidl); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + CRegFolder *pRegFolder = static_cast<CRegFolder*>(psf); + const REQUIREDREGITEM* pRequired = pRegFolder->IsRequiredItem(apidl[0]); + if (pRequired && pRequired->pszCpl) + { + WCHAR buf[MAX_PATH]; + wsprintfW(buf, L"%hs", const_cast<LPCSTR>(pRequired->pszCpl)); + hr = SHELL_ExecuteControlPanelCPL(hwnd, buf) ? S_OK : E_FAIL; + } +#if 0 // Should never happen, CDesktopFolder.cpp handles this + else if (_ILIsDesktop(pidlFolder) && _ILIsDesktop(apidl[0])) + { + hr = SHELL_ExecuteControlPanelCPL(hwnd, L"desk.cpl") ? S_OK : E_FAIL; + } +#endif + else if (_ILIsDesktop(pidlFolder) && _ILIsBitBucket(apidl[0])) + { + FIXME("Use SHOpenPropSheet on Recyclers PropertySheetHandlers from the registry\n"); + hr = SH_ShowRecycleBinProperties(L'C') ? S_OK : E_FAIL; + } + else + { + hr = S_FALSE; // Tell the caller to run the default action + } + + SHFree(pidlFolder); + _ILFreeaPidl(apidl, cidl); + return hr; +} + +static HRESULT CRegItemContextMenu_CreateInstance(PCIDLIST_ABSOLUTE pidlFolder, HWND hwnd, UINT cidl, + PCUITEMID_CHILD_ARRAY apidl, IShellFolder *psf, IContextMenu **ppcm) +{ + HKEY hKeys[3]; + UINT cKeys = 0; + + const GUID *pGuid = _ILGetGUIDPointer(apidl[0]); + if (pGuid) + { + WCHAR key[sizeof("CLSID\\") + 38]; + wcscpy(key, L"CLSID\\"); + StringFromGUID2(*pGuid, &key[6], 39); + AddClassKeyToArray(key, hKeys, &cKeys); + } + + // FIXME: CRegFolder should be aggregated by its outer folder and should + // provide the attributes for all required non-registry folders. + // It currently does not so we have to ask the outer folder ourself so + // that we get the correct attributes for My Computer etc. + CComPtr<IShellFolder> pOuterSF; + SHBindToObject(NULL, pidlFolder, IID_PPV_ARG(IShellFolder, &pOuterSF)); + + SFGAOF att = (psf && cidl) ? SHGetAttributes(pOuterSF ? pOuterSF.p : psf, apidl[0], SFGAO_FOLDER) : 0; + if ((att & SFGAO_FOLDER) && (!pGuid || !HasCLSIDShellFolderValue(*pGuid, L"HideFolderVerbs"))) + AddClassKeyToArray(L"Folder", hKeys, &cKeys); + + return CDefFolderMenu_Create2(pidlFolder, hwnd, cidl, apidl, psf, RegFolderContextMenuCallback, cKeys, hKeys, ppcm); +} + /* In latest windows version this is exported but it takes different arguments! */ -HRESULT CRegFolder_CreateInstance(const GUID *pGuid, LPCITEMIDLIST pidlRoot, LPCWSTR lpszPath, LPCWSTR lpszEnumKeyName, REFIID riid, void **ppv) +HRESULT CRegFolder_CreateInstance(PREGFOLDERINITDATA pInit, LPCITEMIDLIST pidlRoot, REFIID riid, void **ppv) { - return ShellObjectCreatorInit<CRegFolder>(pGuid, pidlRoot, lpszPath, lpszEnumKeyName, riid, ppv); + return ShellObjectCreatorInit<CRegFolder>(pInit, pidlRoot, riid, ppv); } diff --git a/dll/win32/shell32/shelldesktop/CDesktopBrowser.cpp b/dll/win32/shell32/shelldesktop/CDesktopBrowser.cpp index 11c65fb9819..d14c1c15626 100644 --- a/dll/win32/shell32/shelldesktop/CDesktopBrowser.cpp +++ b/dll/win32/shell32/shelldesktop/CDesktopBrowser.cpp @@ -226,8 +226,7 @@ HRESULT CDesktopBrowser::Initialize(IShellDesktopTray *ShellDesk) if (!m_hWnd) return E_FAIL; - CSFV csfv = {sizeof(CSFV), psfDesktop}; - hRet = SHCreateShellFolderViewEx(&csfv, &m_ShellView); + hRet = psfDesktop->CreateViewObject(m_hWnd, IID_PPV_ARG(IShellView, &m_ShellView)); if (FAILED_UNEXPECTEDLY(hRet)) return hRet; diff --git a/dll/win32/shell32/shfldr.h b/dll/win32/shell32/shfldr.h index 2b055833464..ff397123b8e 100644 --- a/dll/win32/shell32/shfldr.h +++ b/dll/win32/shell32/shfldr.h @@ -47,11 +47,53 @@ https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_co #define SHFSF_COL_FATTS 4 // File attributes #define SHFSF_COL_COMMENT 5 +typedef struct _REQUIREDREGITEM +{ + REFCLSID clsid; + LPCSTR pszCpl; + BYTE Order; // According to Geoff Chappell, required items have a fixed sort order +} REQUIREDREGITEM; + +typedef struct _REGFOLDERINFO +{ + PIDLTYPE PidlType; + BYTE Count; // Count of required items + const REQUIREDREGITEM *Items; + REFCLSID clsid; + LPCWSTR pszParsingPath; + LPCWSTR pszEnumKeyName; +} REGFOLDERINFO; + +typedef struct _REGFOLDERINITDATA +{ + IShellFolder *psfOuter; + const REGFOLDERINFO *pInfo; +} REGFOLDERINITDATA, *PREGFOLDERINITDATA; + +HRESULT CRegFolder_CreateInstance(PREGFOLDERINITDATA pInit, LPCITEMIDLIST pidlRoot, REFIID riid, void **ppv); + #define GET_SHGDN_FOR(dwFlags) ((DWORD)dwFlags & (DWORD)0x0000FF00) #define GET_SHGDN_RELATION(dwFlags) ((DWORD)dwFlags & (DWORD)0x000000FF) #define IS_SHGDN_FOR_PARSING(flags) ( ((flags) & (SHGDN_FORADDRESSBAR | SHGDN_FORPARSING)) == SHGDN_FORPARSING) #define IS_SHGDN_DESKTOPABSOLUTEPARSING(flags) ( ((flags) & (SHGDN_FORADDRESSBAR | SHGDN_FORPARSING | 0xFF)) == SHGDN_FORPARSING) +static inline SFGAOF +SHELL_CreateFolderEnumItemAttributeQuery(SHCONTF Flags, BOOL ForRegItem) +{ + SFGAOF query = SFGAO_FOLDER | (ForRegItem ? SFGAO_NONENUMERATED : 0); + if (!(Flags & SHCONTF_INCLUDEHIDDEN)) + query |= SFGAO_HIDDEN; + if (!(Flags & SHCONTF_INCLUDESUPERHIDDEN)) + query |= SFGAO_HIDDEN | SFGAO_SYSTEM; + return query; +} + +SHCONTF +SHELL_GetDefaultFolderEnumSHCONTF(); + +BOOL +SHELL_IncludeItemInFolderEnum(IShellFolder *pSF, PCUITEMID_CHILD pidl, SFGAOF Query, SHCONTF Flags); + HRESULT Shell_NextElement( _Inout_ LPWSTR *ppch, diff --git a/dll/win32/shell32/shlfolder.cpp b/dll/win32/shell32/shlfolder.cpp index a6ea823212f..1d32793d746 100644 --- a/dll/win32/shell32/shlfolder.cpp +++ b/dll/win32/shell32/shlfolder.cpp @@ -26,6 +26,34 @@ WINE_DEFAULT_DEBUG_CHANNEL(shell); +SHCONTF SHELL_GetDefaultFolderEnumSHCONTF() +{ + SHCONTF Flags = SHCONTF_FOLDERS | SHCONTF_NONFOLDERS; + SHELLSTATE ss; + SHGetSetSettings(&ss, SSF_SHOWALLOBJECTS | SSF_SHOWSUPERHIDDEN, FALSE); + if (ss.fShowAllObjects) + Flags |= SHCONTF_INCLUDEHIDDEN; + if (ss.fShowSuperHidden) + Flags |= SHCONTF_INCLUDESUPERHIDDEN; + return Flags; +} + +BOOL SHELL_IncludeItemInFolderEnum(IShellFolder *pSF, PCUITEMID_CHILD pidl, SFGAOF Query, SHCONTF Flags) +{ + if (SUCCEEDED(pSF->GetAttributesOf(1, &pidl, &Query))) + { + if (Query & SFGAO_NONENUMERATED) + return FALSE; + if ((Query & SFGAO_HIDDEN) && !(Flags & SHCONTF_INCLUDEHIDDEN)) + return FALSE; + if ((Query & (SFGAO_HIDDEN | SFGAO_SYSTEM)) == (SFGAO_HIDDEN | SFGAO_SYSTEM) && !(Flags & SHCONTF_INCLUDESUPERHIDDEN)) + return FALSE; + if ((Flags & (SHCONTF_FOLDERS | SHCONTF_NONFOLDERS)) != (SHCONTF_FOLDERS | SHCONTF_NONFOLDERS)) + return (Flags & SHCONTF_FOLDERS) ? (Query & SFGAO_FOLDER) : !(Query & SFGAO_FOLDER); + } + return TRUE; +} + HRESULT Shell_NextElement( _Inout_ LPWSTR *ppch, diff --git a/dll/win32/shell32/wine/pidl.c b/dll/win32/shell32/wine/pidl.c index 09b09112adb..54751ded772 100644 --- a/dll/win32/shell32/wine/pidl.c +++ b/dll/win32/shell32/wine/pidl.c @@ -1767,7 +1767,6 @@ LPITEMIDLIST _ILCreateGuidFromStrA(LPCSTR szGUID) } return _ILCreateGuid(PT_GUID, &iid); } -#endif LPITEMIDLIST _ILCreateGuidFromStrW(LPCWSTR szGUID) { @@ -1784,6 +1783,7 @@ LPITEMIDLIST _ILCreateGuidFromStrW(LPCWSTR szGUID) } return _ILCreateGuid(PT_GUID, &iid); } +#endif /* __REACTOS__ */ LPITEMIDLIST _ILCreateFromFindDataW( const WIN32_FIND_DATAW *wfd ) { diff --git a/dll/win32/shell32/wine/pidl.h b/dll/win32/shell32/wine/pidl.h index b25481bd6c8..304ce1cc19b 100644 --- a/dll/win32/shell32/wine/pidl.h +++ b/dll/win32/shell32/wine/pidl.h @@ -104,6 +104,18 @@ extern "C" { #define PT_IESPECIAL2 0xb1 #define PT_SHARE 0xc3 +#ifdef __REACTOS__ +#define PT_DESKTOP_REGITEM 0x1F // => SHDID_ROOT_REGITEM +#define PT_COMPUTER_REGITEM 0x2E // => SHDID_COMPUTER_OTHER +#define PT_FS 0x30 // Win95 SHSimpleIDListFromPath +#define PT_FS_FOLDER_FLAG 0x01 +#define PT_FS_FILE_FLAG 0x02 +#define PT_FS_UNICODE_FLAG 0x04 +// PT_NET_REGITEM 0x4? // => SHDID_NET_OTHER +#define PT_CONTROLS_OLDREGITEM 0x70 +#define PT_CONTROLS_NEWREGITEM 0x71 +#endif + #include "pshpack1.h" typedef BYTE PIDLTYPE; @@ -263,9 +275,11 @@ BOOL _ILIsEmpty (LPCITEMIDLIST pidl) { return _ILIsDesktop(pidl) */ LPITEMIDLIST _ILCreateGuid(PIDLTYPE type, REFIID guid) DECLSPEC_HIDDEN; +#ifndef __REACTOS__ /* Like _ILCreateGuid, but using the string szGUID. */ LPITEMIDLIST _ILCreateGuidFromStrA(LPCSTR szGUID) DECLSPEC_HIDDEN; LPITEMIDLIST _ILCreateGuidFromStrW(LPCWSTR szGUID) DECLSPEC_HIDDEN; +#endif /* Commonly used PIDLs representing file system objects. */ LPITEMIDLIST _ILCreateDesktop (void) DECLSPEC_HIDDEN; diff --git a/dll/win32/shell32/wine/shell32_main.h b/dll/win32/shell32/wine/shell32_main.h index db03e2ad794..73bebc71d3b 100644 --- a/dll/win32/shell32/wine/shell32_main.h +++ b/dll/win32/shell32/wine/shell32_main.h @@ -90,8 +90,6 @@ HRESULT WINAPI IFileSystemBindData_Constructor(const WIN32_FIND_DATAW *pfd, LPBC HRESULT WINAPI CPanel_ExtractIconA(LPITEMIDLIST pidl, LPCSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize) DECLSPEC_HIDDEN; HRESULT WINAPI CPanel_ExtractIconW(LPITEMIDLIST pidl, LPCWSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize) DECLSPEC_HIDDEN; -HRESULT CRegFolder_CreateInstance(const GUID *pGuid, LPCITEMIDLIST pidlRoot, LPCWSTR lpszPath, LPCWSTR lpszEnumKeyName, REFIID riid, void **ppv); - /* initialisation for FORMATETC */ #define InitFormatEtc(fe, cf, med) \ {\ diff --git a/sdk/include/psdk/shobjidl.idl b/sdk/include/psdk/shobjidl.idl index a31a145190b..8738863eb55 100644 --- a/sdk/include/psdk/shobjidl.idl +++ b/sdk/include/psdk/shobjidl.idl @@ -195,6 +195,7 @@ interface IShellFolder : IUnknown cpp_quote("#define SFGAO_HASPROPSHEET 0x00000040L") cpp_quote("#define SFGAO_DROPTARGET 0x00000100L") cpp_quote("#define SFGAO_CAPABILITYMASK 0x00000177L") + cpp_quote("#define SFGAO_SYSTEM 0x00001000L") cpp_quote("#define SFGAO_ENCRYPTED 0x00002000L") cpp_quote("#define SFGAO_ISSLOW 0x00004000L") cpp_quote("#define SFGAO_GHOSTED 0x00008000L") @@ -1485,6 +1486,38 @@ interface ICommDlgBrowser3 : ICommDlgBrowser2 [in] IShellView *ppshv); } +/***************************************************************************** + * IFolderFilterSite & IFolderFilter interfaces + */ +[ + object, + uuid(C0A651F5-B48B-11d2-B5ED-006097C686F6), + pointer_default(unique) +] +interface IFolderFilterSite : IUnknown +{ + HRESULT SetFilter([in] IUnknown* punk); +} + +[ + object, + uuid(9CC22886-DC8E-11d2-B1D0-00C04F8EEB3E), + pointer_default(unique) +] +interface IFolderFilter : IUnknown +{ + HRESULT ShouldShow( + [in] IShellFolder* psf, + [in, unique] PCIDLIST_ABSOLUTE pidlFolder, + [in] PCUITEMID_CHILD pidlItem); + + HRESULT GetEnumFlags( + [in] IShellFolder* psf, + [in] PCIDLIST_ABSOLUTE pidlFolder, + [out] HWND *phwnd, + [in, out] DWORD *pgrfFlags); +} + /***************************************************************************** * IDockingWindow interface */ diff --git a/sdk/include/reactos/shellutils.h b/sdk/include/reactos/shellutils.h index 17d7e0e74e7..825e834897b 100644 --- a/sdk/include/reactos/shellutils.h +++ b/sdk/include/reactos/shellutils.h @@ -293,6 +293,17 @@ HRESULT inline ShellDebugObjectCreator(REFIID riid, R ** ppv) return S_OK; } +template<class T> +HRESULT inline ShellObjectCreator(CComPtr<T> &objref) +{ + _CComObject<T> *pobj; + HRESULT hResult = _CComObject<T>::CreateInstance(&pobj); + objref = pobj; // AddRef() gets called here + if (FAILED(hResult)) + return hResult; + return S_OK; +} + template<class T> HRESULT inline ShellObjectCreator(REFIID riid, void ** ppv) {