[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
This commit is contained in:
Katayama Hirofumi MZ 2023-08-23 15:00:07 +09:00 committed by GitHub
parent 8d35887c02
commit 21925d935c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 357 additions and 2 deletions

View file

@ -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]

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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);