[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
This commit is contained in:
Whindmar Saksit 2024-08-29 20:45:59 +02:00 committed by GitHub
parent a75ed2acd9
commit 6ae11ba09d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 606 additions and 309 deletions

View file

@ -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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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.@]
*/

View file

@ -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_ */

View file

@ -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 */

View file

@ -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()
};

View file

@ -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));
if (_ILSimpleGetTextW(pidl, szFileName, _countof(szFileName)) && (pExtension = PathFindExtensionW(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 (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)
{

View file

@ -16,117 +16,115 @@
* 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)
#define DEFAULTSORTORDERINDEX 0x80 // The default for registry items according to Geoff Chappell
static HRESULT CRegItemContextMenu_CreateInstance(PCIDLIST_ABSOLUTE pidlFolder, HWND hwnd, UINT cidl,
PCUITEMID_CHILD_ARRAY apidl, IShellFolder *psf, IContextMenu **ppcm);
static inline UINT GetRegItemCLSIDOffset(PIDLTYPE type)
{
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;
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
{
/* Tell the caller to run the default action */
hr = S_FALSE;
}
SHFree(pidlFolder);
_ILFreeaPidl(apidl, cidl);
return hr;
return type == PT_CONTROLS_NEWREGITEM ? 14 : 4;
}
HRESULT CGuidItemContextMenu_CreateInstance(PCIDLIST_ABSOLUTE pidlFolder,
HWND hwnd,
UINT cidl,
PCUITEMID_CHILD_ARRAY apidl,
IShellFolder *psf,
IContextMenu **ppcm)
static LPITEMIDLIST CreateRegItem(PIDLTYPE type, REFCLSID clsid, BYTE order = 0)
{
HKEY hKeys[10];
UINT cKeys = 0;
GUID *pGuid = _ILGetGUIDPointer(apidl[0]);
if (pGuid)
#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)
{
WCHAR key[60];
wcscpy(key, L"CLSID\\");
StringFromGUID2(*pGuid, &key[6], 39);
AddClassKeyToArray(key, hKeys, &cKeys);
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;
}
// 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 LPITEMIDLIST CreateRegItem(PIDLTYPE type, LPCWSTR clsidstr)
{
CLSID clsid;
return SUCCEEDED(CLSIDFromString(clsidstr, &clsid)) ? CreateRegItem(type, clsid) : NULL;
}
HRESULT FormatGUIDKey(LPWSTR KeyName, SIZE_T KeySize, LPCWSTR RegPath, const GUID* riid)
{
WCHAR xriid[40];
if (!StringFromGUID2(*riid, xriid, _countof(xriid) - 1))
return E_FAIL;
WCHAR xriid[CHARS_IN_GUID];
StringFromGUID2(*riid, xriid, _countof(xriid));
return StringCchPrintfW(KeyName, KeySize, RegPath, xriid);
}
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)
{
wcscpy(Path + 6 + 38, L"\\");
wcscpy(Path + 6 + 39, SubKey);
}
return RegGetValueW(HKEY_CLASSES_ROOT, Path, Value, RRF_RT_ANY, NULL, pData, pSize);
}
static bool HasCLSIDShellFolderValue(REFCLSID clsid, LPCWSTR Value)
{
return SHELL_QueryCLSIDValue(clsid, L"ShellFolder", Value, NULL, NULL) == ERROR_SUCCESS;
}
struct CRegFolderInfo
{
const REGFOLDERINFO *m_pInfo;
void InitializeFolderInfo(const REGFOLDERINFO *pInfo)
{
m_pInfo = pInfo;
}
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)
{
CComPtr<IDefaultExtractIconInit> initIcon;
@ -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;
}
/* 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)
static HRESULT CALLBACK RegFolderContextMenuCallback(IShellFolder *psf, HWND hwnd, IDataObject *pdtobj,
UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return ShellObjectCreatorInit<CRegFolder>(pGuid, pidlRoot, lpszPath, lpszEnumKeyName, riid, ppv);
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(PREGFOLDERINITDATA pInit, LPCITEMIDLIST pidlRoot, REFIID riid, void **ppv)
{
return ShellObjectCreatorInit<CRegFolder>(pInit, pidlRoot, riid, ppv);
}

View file

@ -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;

View file

@ -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,

View file

@ -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,

View file

@ -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 )
{

View file

@ -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;

View file

@ -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) \
{\

View file

@ -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
*/

View file

@ -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)
{