https://git.reactos.org/?p=reactos.git;a=commitdiff;h=29fbe60abe3c1487886c5…
commit 29fbe60abe3c1487886c52928c58abf68c0ce899
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Mon Aug 28 07:16:11 2023 +0900
Commit: GitHub <noreply(a)github.com>
CommitDate: Mon Aug 28 07:16:11 2023 +0900
[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
---
dll/win32/shlwapi/propbag.cpp | 171 +++++++++++++++++++++++++++++++-----
sdk/include/reactos/shlguid_undoc.h | 2 +
sdk/include/reactos/shlobj_undoc.h | 28 ++++++
3 files changed, 178 insertions(+), 23 deletions(-)
diff --git a/dll/win32/shlwapi/propbag.cpp b/dll/win32/shlwapi/propbag.cpp
index a1cbe199e6c..227a0f3c296 100644
--- a/dll/win32/shlwapi/propbag.cpp
+++ b/dll/win32/shlwapi/propbag.cpp
@@ -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;
diff --git a/sdk/include/reactos/shlguid_undoc.h b/sdk/include/reactos/shlguid_undoc.h
index 4cb0ac39859..e233df556bd 100644
--- a/sdk/include/reactos/shlguid_undoc.h
+++ b/sdk/include/reactos/shlguid_undoc.h
@@ -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… */
DEFINE_GUID(IID_IAggregateFilterCondition, 0x86228AA3, 0xA736, 0x4733, 0xBD, 0x8A, 0x10,
0xA8, 0x3C, 0x69, 0xBF, 0x84);
diff --git a/sdk/include/reactos/shlobj_undoc.h b/sdk/include/reactos/shlobj_undoc.h
index a4cf836d7a2..3ed3b8a8962 100644
--- a/sdk/include/reactos/shlobj_undoc.h
+++ b/sdk/include/reactos/shlobj_undoc.h
@@ -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
*/