https://git.reactos.org/?p=reactos.git;a=commitdiff;h=21925d935cf991be7db64…
commit 21925d935cf991be7db64c593a061a13ae6d708a
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Wed Aug 23 15:00:07 2023 +0900
Commit: GitHub <noreply(a)github.com>
CommitDate: Wed Aug 23 15:00:07 2023 +0900
[SHLWAPI][SDK] Implement SHGetViewStatePropertyBag Part 1 (#5605)
Follow-up to #5590.
- Add CViewStatePropertyBag class.
- Add SHGetViewStatePropertyBag definition.
- Add FreeViewStatePropertyBagCache function and
use it in DllMain to free the cache.
CORE-9283
---
dll/win32/shlwapi/ordinal.c | 2 +
dll/win32/shlwapi/propbag.cpp | 341 +++++++++++++++++++++++++++++++++++++++
dll/win32/shlwapi/shlwapi_main.c | 12 ++
sdk/include/psdk/shlwapi.h | 4 +-
4 files changed, 357 insertions(+), 2 deletions(-)
diff --git a/dll/win32/shlwapi/ordinal.c b/dll/win32/shlwapi/ordinal.c
index 985b79a9f40..37181442f48 100644
--- a/dll/win32/shlwapi/ordinal.c
+++ b/dll/win32/shlwapi/ordinal.c
@@ -5105,6 +5105,7 @@ HRESULT WINAPI SHCreatePropertyBagOnRegKey (HKEY hKey, LPCWSTR
subkey,
}
#endif
+#ifndef __REACTOS__ /* See propbag.cpp */
/***********************************************************************
* SHGetViewStatePropertyBag [SHLWAPI.515]
*
@@ -5131,6 +5132,7 @@ HRESULT WINAPI SHGetViewStatePropertyBag(LPCITEMIDLIST pidl, LPWSTR
bag_name,
return E_NOTIMPL;
}
+#endif
/***********************************************************************
* SHFormatDateTimeW [SHLWAPI.354]
diff --git a/dll/win32/shlwapi/propbag.cpp b/dll/win32/shlwapi/propbag.cpp
index fbd5b87a49b..3a937019a51 100644
--- a/dll/win32/shlwapi/propbag.cpp
+++ b/dll/win32/shlwapi/propbag.cpp
@@ -1188,3 +1188,344 @@ HRESULT SHGetDesktopUpgradePropertyBag(REFIID riid, void
**ppvObj)
CComPtr<CDesktopUpgradePropertyBag> pPropBag(new
CDesktopUpgradePropertyBag());
return pPropBag->QueryInterface(riid, ppvObj);
}
+
+class CViewStatePropertyBag : public CBasePropertyBag
+{
+protected:
+ LPITEMIDLIST m_pidl = NULL;
+ LPWSTR m_pszPath = NULL;
+ DWORD m_dwVspbFlags = 0; // SHGVSPB_... flags
+ CComPtr<IPropertyBag> m_pPidlBag;
+ CComPtr<IPropertyBag> m_pUpgradeBag;
+ CComPtr<IPropertyBag> m_pInheritBag;
+ CComPtr<IPropertyBag> m_pUserDefaultsBag;
+ CComPtr<IPropertyBag> m_pFolderDefaultsBag;
+ CComPtr<IPropertyBag> m_pGlobalDefaultsBag;
+ CComPtr<IPropertyBag> m_pReadBag;
+ CComPtr<IPropertyBag> m_pWriteBag;
+ BOOL m_bPidlBag = FALSE;
+ BOOL m_bUpgradeBag = FALSE;
+ BOOL m_bInheritBag = FALSE;
+ BOOL m_bUserDefaultsBag = FALSE;
+ BOOL m_bFolderDefaultsBag = FALSE;
+ BOOL m_bGlobalDefaultsBag = FALSE;
+ BOOL m_bReadBag = FALSE;
+ BOOL m_bWriteBag = FALSE;
+
+ BOOL _IsSamePidl(LPCITEMIDLIST pidlOther) const;
+ BOOL _IsSystemFolder() const;
+ BOOL _CanAccessPidlBag() const;
+ BOOL _CanAccessUserDefaultsBag() const;
+ BOOL _CanAccessFolderDefaultsBag() const;
+ BOOL _CanAccessGlobalDefaultsBag() const;
+ BOOL _CanAccessInheritBag() const;
+ BOOL _CanAccessUpgradeBag() const;
+
+ HKEY _GetHKey(DWORD dwVspbFlags);
+
+ HRESULT _GetRegKey(
+ LPCITEMIDLIST pidl,
+ LPCWSTR pszBagName,
+ DWORD dwFlags,
+ char unknown,
+ HKEY hKey,
+ LPWSTR pszDest,
+ INT cchDest);
+
+ HRESULT _CreateBag(
+ LPITEMIDLIST pidl,
+ LPCWSTR pszPath,
+ DWORD dwVspbFlags,
+ DWORD dwMode,
+ REFIID riid,
+ void **ppvObj);
+
+ void _ResetTryAgainFlag();
+
+public:
+ CViewStatePropertyBag() : CBasePropertyBag(0)
+ {
+ }
+
+ ~CViewStatePropertyBag() override
+ {
+ ::ILFree(m_pidl);
+ ::LocalFree(m_pszPath);
+ }
+
+ HRESULT Init(_In_opt_ LPCITEMIDLIST pidl, _In_opt_ LPCWSTR pszPath, _In_ DWORD
dwVspbFlags);
+ BOOL IsSameBag(LPCITEMIDLIST pidl, LPCWSTR pszPath, DWORD dwVspbFlags) const;
+
+ STDMETHODIMP Read(
+ _In_z_ LPCWSTR pszPropName,
+ _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;
+ }
+};
+
+// CViewStatePropertyBag is cached
+CComPtr<CViewStatePropertyBag> g_pCachedBag;
+extern "C"
+{
+ CRITICAL_SECTION g_csBagCacheLock;
+}
+
+HRESULT
+CViewStatePropertyBag::Init(
+ _In_opt_ LPCITEMIDLIST pidl,
+ _In_opt_ LPCWSTR pszPath,
+ _In_ DWORD dwVspbFlags)
+{
+ if (pidl)
+ {
+ m_pidl = ILClone(pidl);
+ if (!m_pidl)
+ return E_OUTOFMEMORY;
+ }
+
+ if (pszPath)
+ {
+ m_pszPath = StrDupW(pszPath);
+ if (!m_pszPath)
+ return E_OUTOFMEMORY;
+
+ m_dwVspbFlags = dwVspbFlags;
+ }
+
+ return S_OK;
+}
+
+BOOL CViewStatePropertyBag::_IsSamePidl(LPCITEMIDLIST pidlOther) const
+{
+ if (!pidlOther && !m_pidl)
+ return TRUE;
+
+ return (pidlOther && m_pidl && ILIsEqual(pidlOther, m_pidl));
+}
+
+BOOL CViewStatePropertyBag::IsSameBag(LPCITEMIDLIST pidl, LPCWSTR pszPath, DWORD
dwVspbFlags) const
+{
+ return (dwVspbFlags == m_dwVspbFlags && StrCmpW(pszPath, m_pszPath) == 0
&& _IsSamePidl(pidl));
+}
+
+BOOL CViewStatePropertyBag::_IsSystemFolder() const
+{
+ LPCITEMIDLIST ppidlLast;
+ CComPtr<IShellFolder> psf;
+
+ HRESULT hr = SHBindToParent(m_pidl, IID_IShellFolder, (void **)&psf,
&ppidlLast);
+ if (FAILED(hr))
+ return FALSE;
+
+ WIN32_FIND_DATAW FindData;
+ hr = SHGetDataFromIDListW(psf, ppidlLast, SHGDFIL_FINDDATA, &FindData,
sizeof(FindData));
+ if (FAILED(hr))
+ return FALSE;
+
+ return PathIsSystemFolderW(NULL, FindData.dwFileAttributes);
+}
+
+BOOL CViewStatePropertyBag::_CanAccessPidlBag() const
+{
+ return ((m_dwVspbFlags & SHGVSPB_FOLDER) == SHGVSPB_FOLDER);
+}
+
+BOOL CViewStatePropertyBag::_CanAccessUserDefaultsBag() const
+{
+ if (_CanAccessPidlBag())
+ return TRUE;
+
+ return ((m_dwVspbFlags & SHGVSPB_USERDEFAULTS) == SHGVSPB_USERDEFAULTS);
+}
+
+BOOL CViewStatePropertyBag::_CanAccessFolderDefaultsBag() const
+{
+ if (_CanAccessUserDefaultsBag())
+ return TRUE;
+
+ return ((m_dwVspbFlags & SHGVSPB_ALLUSERS) && (m_dwVspbFlags &
SHGVSPB_PERFOLDER));
+}
+
+BOOL CViewStatePropertyBag::_CanAccessGlobalDefaultsBag() const
+{
+ if (_CanAccessFolderDefaultsBag())
+ return TRUE;
+
+ return ((m_dwVspbFlags & SHGVSPB_GLOBALDEAFAULTS) == SHGVSPB_GLOBALDEAFAULTS);
+}
+
+BOOL CViewStatePropertyBag::_CanAccessInheritBag() const
+{
+ return (_CanAccessPidlBag() || (m_dwVspbFlags & SHGVSPB_INHERIT));
+}
+
+BOOL CViewStatePropertyBag::_CanAccessUpgradeBag() const
+{
+ return StrCmpW(m_pszPath, L"Desktop") == 0;
+}
+
+void CViewStatePropertyBag::_ResetTryAgainFlag()
+{
+ if (m_dwVspbFlags & SHGVSPB_NOAUTODEFAULTS)
+ m_bReadBag = FALSE;
+ else if ((m_dwVspbFlags & SHGVSPB_FOLDER) == SHGVSPB_FOLDER)
+ m_bPidlBag = FALSE;
+ else if (m_dwVspbFlags & SHGVSPB_INHERIT)
+ m_bInheritBag = FALSE;
+ else if ((m_dwVspbFlags & SHGVSPB_USERDEFAULTS) == SHGVSPB_USERDEFAULTS)
+ m_bUserDefaultsBag = FALSE;
+ else if ((m_dwVspbFlags & SHGVSPB_ALLUSERS) && (m_dwVspbFlags &
SHGVSPB_PERFOLDER))
+ m_bFolderDefaultsBag = FALSE;
+ else if ((m_dwVspbFlags & SHGVSPB_GLOBALDEAFAULTS) == SHGVSPB_GLOBALDEAFAULTS)
+ m_bGlobalDefaultsBag = FALSE;
+}
+
+HKEY CViewStatePropertyBag::_GetHKey(DWORD dwVspbFlags)
+{
+ if (!(dwVspbFlags & (SHGVSPB_INHERIT | SHGVSPB_PERUSER)))
+ return SHGetShellKey((SHKEY_Key_Shell | SHKEY_Root_HKLM), NULL, TRUE);
+
+ if ((m_dwVspbFlags & SHGVSPB_ROAM) && (dwVspbFlags &
SHGVSPB_PERFOLDER))
+ return SHGetShellKey((SHKEY_Key_Shell | SHKEY_Root_HKCU), NULL, TRUE);
+
+ return SHGetShellKey(SHKEY_Key_ShellNoRoam | SHKEY_Root_HKCU, NULL, TRUE);
+}
+
+HRESULT CViewStatePropertyBag::_GetRegKey(
+ LPCITEMIDLIST pidl,
+ LPCWSTR pszBagName,
+ DWORD dwFlags,
+ char unknown,
+ HKEY hKey,
+ LPWSTR pszDest,
+ INT cchDest)
+{
+ FIXME("Stub\n");
+ return E_NOTIMPL;
+}
+
+HRESULT
+CViewStatePropertyBag::_CreateBag(
+ LPITEMIDLIST pidl,
+ LPCWSTR pszPath,
+ DWORD dwVspbFlags,
+ DWORD dwMode,
+ REFIID riid,
+ void **ppvObj)
+{
+ FIXME("Stub\n");
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP
+CViewStatePropertyBag::Read(
+ _In_z_ LPCWSTR pszPropName,
+ _Inout_ VARIANT *pvari,
+ _Inout_opt_ IErrorLog *pErrorLog)
+{
+ FIXME("Stub\n");
+ return E_NOTIMPL;
+}
+
+static BOOL SHIsRemovableDrive(LPCITEMIDLIST pidl)
+{
+ STRRET strret;
+ CComPtr<IShellFolder> psf;
+ WCHAR szBuff[MAX_PATH];
+ LPCITEMIDLIST ppidlLast;
+ INT iDrive, nType;
+ HRESULT hr;
+
+ hr = SHBindToParent(pidl, IID_IShellFolder, (void **)&psf, &ppidlLast);
+ if (FAILED(hr))
+ return FALSE;
+
+ hr = psf->GetDisplayNameOf(ppidlLast, SHGDN_FORPARSING, &strret);
+ if (FAILED(hr))
+ return FALSE;
+
+ hr = StrRetToBufW(&strret, ppidlLast, szBuff, _countof(szBuff));
+ if (FAILED(hr))
+ return FALSE;
+
+ iDrive = PathGetDriveNumberW(szBuff);
+ if (iDrive < 0)
+ return FALSE;
+
+ nType = RealDriveType(iDrive, FALSE);
+ return (nType == DRIVE_REMOVABLE || nType == DRIVE_CDROM);
+}
+
+/**************************************************************************
+ * SHGetViewStatePropertyBag (SHLWAPI.515)
+ *
+ * Retrieves a property bag in which the view state information of a folder
+ * can be stored.
+ *
+ * @param pidl PIDL of the folder requested
+ * @param bag_name Name of the property bag requested
+ * @param flags Optional SHGVSPB_... flags
+ * @param riid IID of requested property bag interface
+ * @param ppv Address to receive pointer to the new interface
+ * @return An HRESULT value. S_OK on success, non-zero on failure.
+ * @see
https://learn.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-shge…
+ */
+EXTERN_C HRESULT WINAPI
+SHGetViewStatePropertyBag(
+ _In_opt_ PCIDLIST_ABSOLUTE pidl,
+ _In_opt_ LPCWSTR bag_name,
+ _In_ DWORD flags,
+ _In_ REFIID riid,
+ _Outptr_ void **ppv)
+{
+ HRESULT hr;
+
+ TRACE("%p %s 0x%X %p %p\n", pidl, debugstr_w(bag_name), flags, &riid,
ppv);
+
+ *ppv = NULL;
+
+ ::EnterCriticalSection(&g_csBagCacheLock);
+
+ if (g_pCachedBag && g_pCachedBag->IsSameBag(pidl, bag_name, flags))
+ {
+ hr = g_pCachedBag->QueryInterface(riid, ppv);
+ ::LeaveCriticalSection(&g_csBagCacheLock);
+ return hr;
+ }
+
+ if (SHIsRemovableDrive(pidl))
+ {
+ TRACE("pidl %p is removable\n", pidl);
+ ::LeaveCriticalSection(&g_csBagCacheLock);
+ return E_FAIL;
+ }
+
+ CComPtr<CViewStatePropertyBag> pBag(new CViewStatePropertyBag());
+
+ hr = pBag->Init(pidl, bag_name, flags);
+ if (SUCCEEDED(hr))
+ {
+ g_pCachedBag.Attach(pBag);
+
+ hr = g_pCachedBag->QueryInterface(riid, ppv);
+ }
+ else
+ {
+ ERR("0x%08X\n", hr);
+ }
+
+ ::LeaveCriticalSection(&g_csBagCacheLock);
+ return hr;
+}
+
+EXTERN_C VOID FreeViewStatePropertyBagCache(VOID)
+{
+ ::EnterCriticalSection(&g_csBagCacheLock);
+ g_pCachedBag.Release();
+ ::LeaveCriticalSection(&g_csBagCacheLock);
+}
diff --git a/dll/win32/shlwapi/shlwapi_main.c b/dll/win32/shlwapi/shlwapi_main.c
index f466bb485aa..56f9b8c97c2 100644
--- a/dll/win32/shlwapi/shlwapi_main.c
+++ b/dll/win32/shlwapi/shlwapi_main.c
@@ -33,6 +33,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(shell);
DECLSPEC_HIDDEN HINSTANCE shlwapi_hInstance = 0;
DECLSPEC_HIDDEN DWORD SHLWAPI_ThreadRef_index = TLS_OUT_OF_INDEXES;
+#ifdef __REACTOS__
+extern CRITICAL_SECTION g_csBagCacheLock;
+VOID FreeViewStatePropertyBagCache(VOID);
+#endif
+
/*************************************************************************
* SHLWAPI {SHLWAPI}
*
@@ -62,9 +67,16 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID
fImpLoad)
DisableThreadLibraryCalls(hinstDLL);
shlwapi_hInstance = hinstDLL;
SHLWAPI_ThreadRef_index = TlsAlloc();
+#ifdef __REACTOS__
+ InitializeCriticalSection(&g_csBagCacheLock);
+#endif
break;
case DLL_PROCESS_DETACH:
if (fImpLoad) break;
+#ifdef __REACTOS__
+ FreeViewStatePropertyBagCache();
+ DeleteCriticalSection(&g_csBagCacheLock);
+#endif
if (SHLWAPI_ThreadRef_index != TLS_OUT_OF_INDEXES)
TlsFree(SHLWAPI_ThreadRef_index);
break;
}
diff --git a/sdk/include/psdk/shlwapi.h b/sdk/include/psdk/shlwapi.h
index 84241ba4a58..801928fff4b 100644
--- a/sdk/include/psdk/shlwapi.h
+++ b/sdk/include/psdk/shlwapi.h
@@ -2003,8 +2003,8 @@ HRESULT
WINAPI
SHGetViewStatePropertyBag(
_In_opt_ PCIDLIST_ABSOLUTE pidl,
- _In_opt_ LPWSTR bag_name,
- DWORD flags,
+ _In_opt_ LPCWSTR bag_name,
+ _In_ DWORD flags,
_In_ REFIID riid,
_Outptr_ void **ppv);