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