https://git.reactos.org/?p=reactos.git;a=commitdiff;h=29fbe60abe3c1487886c52928c58abf68c0ce899

commit 29fbe60abe3c1487886c52928c58abf68c0ce899
Author:     Katayama Hirofumi MZ <katayama.hirofumi...@gmail.com>
AuthorDate: Mon Aug 28 07:16:11 2023 +0900
Commit:     GitHub <nore...@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.htm 
*/
 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
  */

Reply via email to