https://git.reactos.org/?p=reactos.git;a=commitdiff;h=21925d935cf991be7db64c593a061a13ae6d708a

commit 21925d935cf991be7db64c593a061a13ae6d708a
Author:     Katayama Hirofumi MZ <katayama.hirofumi...@gmail.com>
AuthorDate: Wed Aug 23 15:00:07 2023 +0900
Commit:     GitHub <nore...@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-shgetviewstatepropertybag
+ */
+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);
 

Reply via email to