[SHLWAPI][SDK] Implement SHGetViewStatePropertyBag Part 3 (#5615)

Follow-up to #5610.
- Add _EnsureWriteBag, _PruneMRUTree, _GetMRUSize and
  _GetMRUSlots helper functions.
- Add code into _GetMRUSlot, _FindNearestInheritBag, and Write.
- Add CLSID_MruPidlList and IID_IMruPidlList definitions into
  <shlguid_undoc.h>.
- Add IMruPidlList interface into <shlobj_undoc.h>.
CORE-9283
This commit is contained in:
Katayama Hirofumi MZ 2023-08-28 07:16:11 +09:00 committed by GitHub
parent ff63d06406
commit 29fbe60abe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 178 additions and 23 deletions

View file

@ -9,6 +9,8 @@
#include "precomp.h"
#include <shlwapi.h>
#include <shlwapi_undoc.h>
#include <shlobj_undoc.h>
#include <shlguid_undoc.h>
#include <atlstr.h> // for CStringW
#include <atlsimpcoll.h> // for CSimpleMap
#include <atlcomcli.h> // for CComVariant
@ -17,6 +19,11 @@
WINE_DEFAULT_DEBUG_CHANNEL(shell);
#define MODE_CAN_READ(dwMode) \
(((dwMode) & (STGM_READ | STGM_WRITE | STGM_READWRITE)) != STGM_WRITE)
#define MODE_CAN_WRITE(dwMode) \
(((dwMode) & (STGM_READ | STGM_WRITE | STGM_READWRITE)) != STGM_READ)
class CBasePropertyBag
: public IPropertyBag
#if (_WIN32_WINNT < _WIN32_WINNT_VISTA)
@ -39,6 +46,9 @@ public:
// IUnknown interface
STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject) override
{
if (!ppvObject)
return E_POINTER;
#if (_WIN32_WINNT < _WIN32_WINNT_VISTA)
if (::IsEqualGUID(riid, IID_IPropertyBag2))
{
@ -54,8 +64,8 @@ public:
return S_OK;
}
ERR("%p: %s: E_NOTIMPL\n", this, debugstr_guid(&riid));
return E_NOTIMPL;
ERR("%p: %s: E_NOINTERFACE\n", this, debugstr_guid(&riid));
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) AddRef() override
{
@ -153,7 +163,7 @@ CMemPropertyBag::Read(
::VariantInit(pvari);
#if (_WIN32_WINNT < _WIN32_WINNT_VISTA)
if ((m_dwMode & (STGM_READ | STGM_WRITE | STGM_READWRITE)) == STGM_WRITE)
if (!MODE_CAN_READ(m_dwMode))
{
ERR("%p: 0x%X\n", this, m_dwMode);
return E_ACCESSDENIED;
@ -198,7 +208,7 @@ CMemPropertyBag::Write(
TRACE("%p: %s %p\n", this, debugstr_w(pszPropName), pvari);
#if (_WIN32_WINNT < _WIN32_WINNT_VISTA)
if ((m_dwMode & (STGM_READ | STGM_WRITE | STGM_READWRITE)) == STGM_READ)
if (!MODE_CAN_WRITE(m_dwMode))
{
ERR("%p: 0x%X\n", this, m_dwMode);
return E_ACCESSDENIED;
@ -288,9 +298,9 @@ public:
HRESULT CRegPropertyBag::Init(HKEY hKey, LPCWSTR lpSubKey)
{
REGSAM nAccess = 0;
if ((m_dwMode & (STGM_READ | STGM_WRITE | STGM_READWRITE)) != STGM_WRITE)
if (MODE_CAN_READ(m_dwMode))
nAccess |= KEY_READ;
if ((m_dwMode & (STGM_READ | STGM_WRITE | STGM_READWRITE)) != STGM_READ)
if (MODE_CAN_WRITE(m_dwMode))
nAccess |= KEY_WRITE;
LONG error;
@ -409,7 +419,7 @@ CRegPropertyBag::Read(
TRACE("%p: %s %p %p\n", this, debugstr_w(pszPropName), pvari, pErrorLog);
if ((m_dwMode & (STGM_READ | STGM_WRITE | STGM_READWRITE)) == STGM_WRITE)
if (!MODE_CAN_READ(m_dwMode))
{
ERR("%p: 0x%X\n", this, m_dwMode);
::VariantInit(pvari);
@ -479,7 +489,7 @@ CRegPropertyBag::Write(_In_z_ LPCWSTR pszPropName, _In_ VARIANT *pvari)
{
TRACE("%p: %s %p\n", this, debugstr_w(pszPropName), pvari);
if ((m_dwMode & (STGM_READ | STGM_WRITE | STGM_READWRITE)) == STGM_READ)
if (!MODE_CAN_WRITE(m_dwMode))
{
ERR("%p: 0x%X\n", this, m_dwMode);
return E_ACCESSDENIED;
@ -856,7 +866,7 @@ CIniPropertyBag::Read(
::VariantInit(pvari);
if ((m_dwMode & (STGM_READ | STGM_WRITE | STGM_READWRITE)) == STGM_WRITE)
if (!MODE_CAN_READ(m_dwMode))
{
ERR("%p: 0x%X\n", this, m_dwMode);
return E_ACCESSDENIED;
@ -890,7 +900,7 @@ CIniPropertyBag::Write(_In_z_ LPCWSTR pszPropName, _In_ VARIANT *pvari)
{
TRACE("%p: %s %p\n", this, debugstr_w(pszPropName), pvari);
if ((m_dwMode & (STGM_READ | STGM_WRITE | STGM_READWRITE)) == STGM_READ)
if (!MODE_CAN_WRITE(m_dwMode))
{
ERR("%p: 0x%X\n", this, m_dwMode);
return E_ACCESSDENIED;
@ -1017,6 +1027,7 @@ public:
STDMETHODIMP Write(_In_z_ LPCWSTR pszPropName, _In_ VARIANT *pvari) override
{
ERR("%p: %s: Read-only\n", this, debugstr_w(pszPropName));
return E_NOTIMPL;
}
};
@ -1224,6 +1235,16 @@ protected:
HKEY _GetHKey(DWORD dwVspbFlags);
UINT _GetMRUSize(HKEY hKey);
HRESULT _GetMRUSlots(
LPCITEMIDLIST pidl,
DWORD dwMode,
HKEY hKey,
UINT *puSlots,
UINT cSlots,
UINT *pcSlots);
HRESULT _GetMRUSlot(LPCITEMIDLIST pidl, DWORD dwMode, HKEY hKey, UINT *pSlot);
HRESULT _GetRegKey(
@ -1254,12 +1275,14 @@ protected:
BOOL _EnsureUserDefaultsBag(DWORD dwMode, REFIID riid);
BOOL _EnsureFolderDefaultsBag(DWORD dwMode, REFIID riid);
BOOL _EnsureGlobalDefaultsBag(DWORD dwMode, REFIID riid);
BOOL _EnsureWriteBag(DWORD dwMode, REFIID riid);
HRESULT _ReadPidlBag(LPCWSTR pszPropName, VARIANT *pvari, IErrorLog *pErrorLog);
HRESULT _ReadInheritBag(LPCWSTR pszPropName, VARIANT *pvari, IErrorLog *pErrorLog);
HRESULT _ReadUpgradeBag(LPCWSTR pszPropName, VARIANT *pvari, IErrorLog *pErrorLog);
HRESULT _ReadUserDefaultsBag(LPCWSTR pszPropName, VARIANT *pvari, IErrorLog *pErrorLog);
HRESULT _ReadFolderDefaultsBag(LPCWSTR pszPropName, VARIANT *pvari, IErrorLog *pErrorLog);
HRESULT _ReadGlobalDefaultsBag(LPCWSTR pszPropName, VARIANT *pvari, IErrorLog *pErrorLog);
void _PruneMRUTree();
public:
CViewStatePropertyBag() : CBasePropertyBag(STGM_READ) { }
@ -1278,11 +1301,7 @@ public:
_Inout_ VARIANT *pvari,
_Inout_opt_ IErrorLog *pErrorLog) override;
STDMETHODIMP Write(_In_z_ LPCWSTR pszPropName, _In_ VARIANT *pvari) override
{
ERR("%p: %s: Read-only\n", this, debugstr_w(pszPropName));
return E_NOTIMPL;
}
STDMETHODIMP Write(_In_z_ LPCWSTR pszPropName, _In_ VARIANT *pvari) override;
};
// CViewStatePropertyBag is cached
@ -1413,11 +1432,50 @@ HKEY CViewStatePropertyBag::_GetHKey(DWORD dwVspbFlags)
return SHGetShellKey(SHKEY_Key_ShellNoRoam | SHKEY_Root_HKCU, NULL, TRUE);
}
UINT CViewStatePropertyBag::_GetMRUSize(HKEY hKey)
{
DWORD dwValue, cbValue = sizeof(dwValue);
if (SHGetValueW(hKey, NULL, L"BagMRU Size", NULL, &dwValue, &cbValue) != ERROR_SUCCESS)
return 400; // The default size of the MRU (most recently used) list
return (UINT)dwValue;
}
HRESULT
CViewStatePropertyBag::_GetMRUSlots(
LPCITEMIDLIST pidl,
DWORD dwMode,
HKEY hKey,
UINT *puSlots,
UINT cSlots,
UINT *pcSlots)
{
CComPtr<IMruPidlList> pMruList;
HRESULT hr = ::CoCreateInstance(CLSID_MruPidlList, NULL, CLSCTX_INPROC_SERVER,
IID_IMruPidlList, (void**)&pMruList);
if (FAILED(hr))
return hr;
UINT cMRUSize = _GetMRUSize(hKey);
hr = pMruList->InitList(cMRUSize, hKey, L"BagMRU");
if (FAILED(hr))
return hr;
hr = pMruList->QueryPidl(pidl, cSlots, puSlots, pcSlots);
if (hr == S_OK && MODE_CAN_WRITE(dwMode))
hr = pMruList->UsePidl(pidl, puSlots);
else if (cSlots == 1)
hr = E_FAIL;
return hr;
}
HRESULT
CViewStatePropertyBag::_GetMRUSlot(LPCITEMIDLIST pidl, DWORD dwMode, HKEY hKey, UINT *pSlot)
{
FIXME("Stub\n");
return E_NOTIMPL;
UINT cSlots;
return _GetMRUSlots(pidl, dwMode, hKey, pSlot, 1, &cSlots);
}
HRESULT
@ -1439,14 +1497,14 @@ CViewStatePropertyBag::_GetRegKey(
if (SUCCEEDED(hr))
{
if (dwFlags & SHGVSPB_INHERIT)
wnsprintfW(pszDest, cchDest, L"Bags\\%d\\%s\\Inherit", nSlot, pszBagName);
StringCchPrintfW(pszDest, cchDest, L"Bags\\%d\\%s\\Inherit", nSlot, pszBagName);
else
wnsprintfW(pszDest, cchDest, L"Bags\\%d\\%s", nSlot, pszBagName);
StringCchPrintfW(pszDest, cchDest, L"Bags\\%d\\%s", nSlot, pszBagName);
}
}
else
{
wnsprintfW(pszDest, cchDest, L"Bags\\AllFolders\\%s", pszBagName);
StringCchPrintfW(pszDest, cchDest, L"Bags\\AllFolders\\%s", pszBagName);
}
return hr;
@ -1487,7 +1545,7 @@ CViewStatePropertyBag::_CreateBag(
CComPtr<IShellFolder> psf;
WCHAR szBuff[64];
if ((dwMode & (STGM_READ | STGM_WRITE | STGM_READWRITE)) != STGM_READ)
if (MODE_CAN_WRITE(dwMode))
dwMode |= STGM_CREATE;
if ((dwVspbFlags & SHGVSPB_ALLUSERS) && (dwVspbFlags & SHGVSPB_PERFOLDER))
@ -1523,8 +1581,32 @@ CViewStatePropertyBag::_CreateBag(
HRESULT
CViewStatePropertyBag::_FindNearestInheritBag(REFIID riid, IPropertyBag **pppb)
{
FIXME("Stub\n");
return E_NOTIMPL;
*pppb = NULL;
HKEY hKey = _GetHKey(SHGVSPB_INHERIT);
if (!hKey)
return E_FAIL;
UINT cSlots, anSlots[64];
if (FAILED(_GetMRUSlots(m_pidl, 0, hKey, anSlots, _countof(anSlots), &cSlots)) || !cSlots)
{
::RegCloseKey(hKey);
return E_FAIL;
}
HRESULT hr = E_FAIL;
WCHAR szBuff[64];
for (UINT iSlot = 0; iSlot < cSlots; ++iSlot)
{
StringCchPrintfW(szBuff, _countof(szBuff), L"Bags\\%d\\%s\\Inherit", anSlots[iSlot],
m_pszPath);
hr = SHCreatePropertyBagOnRegKey(hKey, szBuff, STGM_READ, riid, (void**)pppb);
if (SUCCEEDED(hr))
break;
}
::RegCloseKey(hKey);
return hr;
}
BOOL CViewStatePropertyBag::_EnsureReadBag(DWORD dwMode, REFIID riid)
@ -1710,6 +1792,49 @@ CViewStatePropertyBag::Read(
return _ReadGlobalDefaultsBag(pszPropName, pvari, pErrorLog);
}
void CViewStatePropertyBag::_PruneMRUTree()
{
HKEY hKey = _GetHKey(SHGVSPB_INHERIT);
if (!hKey)
return;
CComPtr<IMruPidlList> pMruList;
HRESULT hr = ::CoCreateInstance(CLSID_MruPidlList, NULL, CLSCTX_INPROC_SERVER,
IID_IMruPidlList, (void**)&pMruList);
if (SUCCEEDED(hr))
{
hr = pMruList->InitList(200, hKey, L"BagMRU");
if (SUCCEEDED(hr))
pMruList->PruneKids(m_pidl);
}
::RegCloseKey(hKey);
}
BOOL CViewStatePropertyBag::_EnsureWriteBag(DWORD dwMode, REFIID riid)
{
if (!m_pWriteBag && !m_bWriteBag)
{
m_bWriteBag = TRUE;
_CreateBag(m_pidl, m_pszPath, m_dwVspbFlags, dwMode, riid, &m_pWriteBag);
if (m_pWriteBag)
{
_ResetTryAgainFlag();
if (m_dwVspbFlags & SHGVSPB_INHERIT)
_PruneMRUTree();
}
}
return (m_pWriteBag != NULL);
}
STDMETHODIMP CViewStatePropertyBag::Write(_In_z_ LPCWSTR pszPropName, _In_ VARIANT *pvari)
{
if (!_EnsureWriteBag(STGM_WRITE, IID_IPropertyBag))
return E_FAIL;
return m_pWriteBag->Write(pszPropName, pvari);
}
static BOOL SHIsRemovableDrive(LPCITEMIDLIST pidl)
{
STRRET strret;

View file

@ -142,6 +142,8 @@ DEFINE_GUID(CLSID_SharedTaskScheduler, 0x603D3801, 0xBD81, 0x11d0, 0xA3, 0xA
DEFINE_GUID(CLSID_SendToMenu, 0x7BA4C740, 0x9E81, 0x11CF, 0x99, 0xD3, 0x00, 0xAA, 0x00, 0x4A, 0xE8, 0x37);
DEFINE_GUID(CLSID_CopyToMenu, 0xC2FBB630, 0x2971, 0x11D1, 0xA1, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0x5D, 0x13);
DEFINE_GUID(CLSID_MoveToMenu, 0xC2FBB631, 0x2971, 0x11D1, 0xA1, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0x5D, 0x13);
DEFINE_GUID(CLSID_MruPidlList, 0x42AEDC87, 0x2188, 0x41FD, 0xB9, 0xA3, 0x0C, 0x96, 0x6F, 0xEA, 0xBE, 0xC1);
DEFINE_GUID(IID_IMruPidlList, 0x47851649, 0xA2EF, 0x4E67, 0xBA, 0xEC, 0xC6, 0xA1, 0x53, 0xAC, 0x72, 0xEC);
/* The following list of interfaces was taken from here: http://www.geoffchappell.com/studies/windows/shell/shell32/interfaces/index.htm */
DEFINE_GUID(IID_IAggregateFilterCondition, 0x86228AA3, 0xA736, 0x4733, 0xBD, 0x8A, 0x10, 0xA8, 0x3C, 0x69, 0xBF, 0x84);

View file

@ -678,6 +678,34 @@ DECLARE_INTERFACE_(IShellBrowserService, IUnknown)
#define IShellBrowserService_GetPropertyBag(T,a,b,c) (T)->lpVtbl->GetPropertyBag(T,a,b,c)
#endif
/*****************************************************************************
* IMruPidlList interface
*/
#define INTERFACE IMruPidlList
DECLARE_INTERFACE_(IMruPidlList, IUnknown)
{
/*** IUnknown ***/
STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
STDMETHOD_(ULONG,AddRef)(THIS) PURE;
STDMETHOD_(ULONG,Release)(THIS) PURE;
/*** IMruPidlList ***/
STDMETHOD(InitList)(THIS_ UINT, HKEY, LPCWSTR) PURE;
STDMETHOD(UsePidl)(THIS_ LPCITEMIDLIST, UINT*) PURE;
STDMETHOD(QueryPidl)(THIS_ LPCITEMIDLIST, UINT, UINT*, UINT*) PURE;
STDMETHOD(PruneKids)(THIS_ LPCITEMIDLIST) PURE;
};
#undef INTERFACE
#ifdef COBJMACROS
#define IMruPidlList_QueryInterface(T,a,b) (T)->lpVtbl->QueryInterface(T,a,b)
#define IMruPidlList_AddRef(T) (T)->lpVtbl->AddRef(T)
#define IMruPidlList_Release(T) (T)->lpVtbl->Release(T)
#define IMruPidlList_InitList(T,a,b,c) (T)->lpVtbl->InitList(T,a,b,c)
#define IMruPidlList_UsePidl(T,a,b) (T)->lpVtbl->UsePidl(T,a,b)
#define IMruPidlList_QueryPidl(T,a,b,c,d) (T)->lpVtbl->QueryPidl(T,a,b,c,d)
#define IMruPidlList_PruneKids(T,a) (T)->lpVtbl->PruneKids(T,a)
#endif
/*****************************************************************************
* ITrayPriv interface
*/