[SHLWAPI][SDK] Support SHWindowsPolicyGetValue (#9038)

Implementing missing features...
JIRA issue: CORE-19278
- Add policy.cpp and modify CMakeLists.txt.
- Implement SHWindowsPolicyGetValue function.
- Modify shlwapi.spec.
- Add some GUIDs into <shlguid_undoc.h>.
This commit is contained in:
Katayama Hirofumi MZ
2026-05-25 19:24:20 +09:00
committed by GitHub
parent 8823853f77
commit 22ee9d727f
6 changed files with 338 additions and 1 deletions
+1
View File
@@ -25,6 +25,7 @@ list(APPEND SOURCE
list(APPEND PCH_SKIP_SOURCE
assoc.c
policy.cpp
propbag.cpp
utils.cpp
wsprintf.c
+311
View File
@@ -0,0 +1,311 @@
/*
* PROJECT: ReactOS shlwapi
* LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later)
* PURPOSE: Implement SHWindowsPolicyGetValue
* COPYRIGHT: Copyright 2026 Katayama Hirofumi MZ ([email protected])
*/
#define _ATL_NO_EXCEPTIONS
#include <windef.h>
#include <shlobj.h>
#include <shlwapi.h>
#include <shlwapi_undoc.h>
#include <shlguid_undoc.h>
#include <atlstr.h>
#include <strsafe.h>
#include <wine/debug.h>
WINE_DEFAULT_DEBUG_CHANNEL(policy);
typedef enum tagPOLICY_STATE
{
POLICY_STATE_UNCACHED = 0, // Uncached
POLICY_STATE_NOT_FOUND = 1, // Not found
POLICY_STATE_CACHED = 2, // Cached
} POLICY_STATE;
// Result
typedef struct tagSHPOLICY_RESULT
{
POLICY_STATE state;
DWORD dwValue;
} SHPOLICY_RESULT, *PSHPOLICY_RESULT;
// Constraints
typedef struct tagSHPOLICY_CONSTRAINT
{
WORD wFlags;
WORD wMinSize;
DWORD dwMin;
DWORD dwMax;
} SHPOLICY_CONSTRAINT, *PSHPOLICY_CONSTRAINT;
static const SHPOLICY_CONSTRAINT c_Bool = { SRRF_RT_DWORD, sizeof(DWORD), 0, 1 };
static const SHPOLICY_CONSTRAINT c_String = { SRRF_RT_REG_SZ, sizeof(WCHAR), 0, 0 };
static const SHPOLICY_CONSTRAINT c_TriValue = { SRRF_RT_DWORD, sizeof(DWORD), 1, 3 };
static const SHPOLICY_CONSTRAINT c_Special = { SRRF_RT_DWORD, sizeof(DWORD), 0x1806, 0x1808 };
// Items
typedef struct tagSHPOLICY_ITEM
{
REFGUID rpolid; // POLID (policy descriptor)
PCWSTR pszKeyName;
PCWSTR pszValueName;
const SHPOLICY_CONSTRAINT *pConstraint;
} SHPOLICY_ITEM, *PSHPOLICY_ITEM;
static const SHPOLICY_ITEM g_PolicyItems[] =
{
{ POLID_UsePathEnvVarForCommandTemplates, L"Explorer", L"UsePathEnvVarForCommandTemplates",
&c_Bool },
{ POLID_ScanWithAntiVirus, L"Attachments", L"ScanWithAntiVirus", &c_TriValue },
{ POLID_SaveZoneInformation, L"Attachments", L"SaveZoneInformation", &c_TriValue },
{ POLID_UseTrustedHandlers, L"Attachments", L"UseTrustedHandlers", &c_TriValue },
{ POLID_HideZoneInfoOnProperties, L"Attachments", L"HideZoneInfoOnProperties", &c_Bool },
{ POLID_DefaultFileTypeRisk, L"Associations", L"DefaultFileTypeRisk", &c_Special },
{ POLID_HighRiskFileTypes, L"Associations", L"HighRiskFileTypes", &c_String },
{ POLID_ModRiskFileTypes, L"Associations", L"ModRiskFileTypes", &c_String },
{ POLID_LowRiskFileTypes, L"Associations", L"LowRiskFileTypes", &c_String },
{ POLID_PreXPSP2ShellProtocolBehavior, L"Explorer", L"PreXPSP2ShellProtocolBehavior", &c_Bool },
{ POLID_CompareJunctionness, L"Explorer", L"CompareJunctionness", &c_Bool },
};
/**************************************************************************
* CPolicyCache
*/
class CPolicyCache
{
public:
~CPolicyCache()
{
LocalFree(m_pResults);
if (m_hGlobalCounter)
CloseHandle(m_hGlobalCounter);
}
static void* operator new(size_t size)
{
// Returns NULL on failure; caller must check before use.
// NOTE: C++ UB if constructor runs on NULL, but ReactOS convention.
return LocalAlloc(LPTR, size);
}
static void operator delete(void *ptr)
{
LocalFree(ptr);
}
BOOL Initialize(const SHPOLICY_ITEM *pItems, UINT cItems)
{
m_nCounterValue = MINLONG;
m_pszRootKey = L"Software\\Microsoft\\Windows\\CurrentVersion\\Policies";
m_pItems = pItems;
m_cItems = cItems;
m_pResults = (PSHPOLICY_RESULT)LocalAlloc(LPTR, cItems * sizeof(SHPOLICY_RESULT));
if (!m_pResults)
return FALSE;
m_hGlobalCounter = SHGlobalCounterCreate(GUID_Restrictions);
if (!m_hGlobalCounter)
{
LocalFree(m_pResults);
m_pResults = NULL;
return FALSE;
}
return TRUE;
}
HRESULT GetValue(_In_ REFGUID rpolid, _Out_opt_ PVOID pvValue, _Out_opt_ PDWORD pcbValue);
protected:
LPCWSTR m_pszRootKey;
HANDLE m_hGlobalCounter;
LONG m_nCounterValue;
DWORD m_cItems;
const SHPOLICY_ITEM *m_pItems;
PSHPOLICY_RESULT m_pResults;
void _ValidateCachedResults()
{
LONG Value = SHGlobalCounterGetValue(m_hGlobalCounter);
if (m_nCounterValue != Value)
{
m_nCounterValue = Value;
ZeroMemory(m_pResults, m_cItems * sizeof(SHPOLICY_RESULT));
}
}
HRESULT _GetValue(
_In_ LPCWSTR pszSubKey,
_In_ LPCWSTR pszValueName,
_In_ const SHPOLICY_CONSTRAINT* pConstraint,
_Out_opt_ PDWORD pdwType,
_Out_opt_ PVOID pvData,
_Inout_opt_ PDWORD pcbData);
static void _CacheResult(
const SHPOLICY_CONSTRAINT *pConstraint,
PVOID pvValue,
PDWORD pcbValue,
PSHPOLICY_RESULT pResult);
};
HRESULT
CPolicyCache::GetValue(_In_ REFGUID rpolid, _Out_opt_ PVOID pvValue, _Out_opt_ PDWORD pcbValue)
{
_ValidateCachedResults();
if (m_cItems == 0)
return E_UNEXPECTED;
UINT iItem;
for (iItem = 0; iItem < m_cItems; ++iItem)
{
if (IsEqualGUID(m_pItems[iItem].rpolid, rpolid))
break;
}
if (iItem >= m_cItems)
return E_UNEXPECTED;
const SHPOLICY_ITEM *pItem = &m_pItems[iItem];
PSHPOLICY_RESULT pResult = &m_pResults[iItem];
if (pResult->state == POLICY_STATE_NOT_FOUND)
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
// Use caching only when dealing with DWORD value
if (pvValue && pcbValue && *pcbValue == sizeof(DWORD) && pResult->state == POLICY_STATE_CACHED)
{
*(PDWORD)pvValue = pResult->dwValue;
return S_OK;
}
HRESULT hr = _GetValue(pItem->pszKeyName, pItem->pszValueName, pItem->pConstraint, NULL,
pvValue, pcbValue);
if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
pResult->state = POLICY_STATE_NOT_FOUND;
else if (SUCCEEDED(hr) && pvValue)
_CacheResult(pItem->pConstraint, pvValue, pcbValue, pResult);
return hr;
}
HRESULT CPolicyCache::_GetValue(
_In_ LPCWSTR pszSubKey,
_In_ LPCWSTR pszValueName,
_In_ const SHPOLICY_CONSTRAINT* pConstraint,
_Out_opt_ PDWORD pdwType,
_Out_opt_ PVOID pvData,
_Inout_opt_ PDWORD pcbData)
{
CStringW szFullKey = CStringW(m_pszRootKey) + L"\\" + pszSubKey;
DWORD cbDataSaved = pcbData ? *pcbData : 0;
WORD wFlags = pConstraint->wFlags;
LSTATUS error = RegGetValueW(HKEY_LOCAL_MACHINE, szFullKey, pszValueName, wFlags, pdwType,
pvData, pcbData);
if (error == ERROR_FILE_NOT_FOUND)
{
if (pcbData)
*pcbData = cbDataSaved;
error = RegGetValueW(HKEY_CURRENT_USER, szFullKey, pszValueName, wFlags, pdwType,
pvData, pcbData);
}
if (error)
return HRESULT_FROM_WIN32(error);
if (!pvData)
return S_OK;
if (pConstraint->wFlags == SRRF_RT_DWORD && pConstraint->wMinSize == sizeof(DWORD))
{
DWORD dwValue = *(PDWORD)pvData;
if (dwValue < pConstraint->dwMin || pConstraint->dwMax < dwValue)
return E_DATATYPE_MISMATCH;
}
return S_OK;
}
void
CPolicyCache::_CacheResult(
const SHPOLICY_CONSTRAINT *pConstraint,
PVOID pvValue,
PDWORD pcbValue,
PSHPOLICY_RESULT pResult)
{
UNREFERENCED_PARAMETER(pcbValue); // Reserved for future use
// Use caching only when dealing with DWORD value
if (pConstraint->wFlags == SRRF_RT_DWORD)
{
pResult->dwValue = *(PDWORD)pvValue;
pResult->state = POLICY_STATE_CACHED;
}
}
/***************************************************************************/
CPolicyCache* g_pPolicyCache = NULL;
CRITICAL_SECTION g_csPolicyLock;
// This function must be called under g_csPolicyLock
static BOOL SHPolicyCache_Create(VOID)
{
if (g_pPolicyCache)
return TRUE;
CPolicyCache *pCache = new CPolicyCache;
if (!pCache)
return FALSE;
if (!pCache->Initialize(g_PolicyItems, _countof(g_PolicyItems)))
{
delete pCache;
return FALSE;
}
g_pPolicyCache = pCache;
return TRUE;
}
EXTERN_C VOID SHPolicyCache_DllProcessAttach(VOID)
{
InitializeCriticalSection(&g_csPolicyLock);
}
EXTERN_C VOID SHPolicyCache_DllProcessDetach(VOID)
{
CPolicyCache* pCache;
EnterCriticalSection(&g_csPolicyLock);
pCache = g_pPolicyCache;
g_pPolicyCache = NULL;
LeaveCriticalSection(&g_csPolicyLock);
delete pCache;
DeleteCriticalSection(&g_csPolicyLock);
}
/**************************************************************************
* SHWindowsPolicyGetValue (SHLWAPI.560)
*
* https://www.geoffchappell.com/studies/windows/shell/shlwapi/api/winpolicy/getvalue.htm
*/
EXTERN_C
HRESULT WINAPI
SHWindowsPolicyGetValue(
_In_ REFGUID rpolid,
_Out_opt_ PVOID pvValue,
_Out_opt_ PDWORD pcbValue)
{
HRESULT hr = E_FAIL;
EnterCriticalSection(&g_csPolicyLock);
if (SHPolicyCache_Create())
hr = g_pPolicyCache->GetValue(rpolid, pvValue, pcbValue);
LeaveCriticalSection(&g_csPolicyLock);
return hr;
}
+1 -1
View File
@@ -557,7 +557,7 @@
557 stub -noname SHCoCreateExtension
558 stub -noname SHCoExtensionCollectStats
559 stub -noname SHGetSignatureInfo
560 stdcall -stub -noname SHWindowsPolicyGetValue(ptr ptr ptr)
560 stdcall -noname SHWindowsPolicyGetValue(ptr ptr ptr)
561 stub -noname AssocGetUrlAction
562 stub -noname SHGetPrivateProfileInt
563 stdcall -stub -noname SHGetPrivateProfileSection(wstr ptr long ptr)
+4
View File
@@ -38,6 +38,8 @@ extern CRITICAL_SECTION g_csZoneMgrLock;
extern CRITICAL_SECTION g_csBagCacheLock;
VOID FreeViewStatePropertyBagCache(VOID);
VOID SHLWAPI_DeleteCachedZonesManager(VOID);
VOID SHPolicyCache_DllProcessAttach(VOID);
VOID SHPolicyCache_DllProcessDetach(VOID);
#endif
/*************************************************************************
@@ -72,6 +74,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
#ifdef __REACTOS__
InitializeCriticalSection(&g_csZoneMgrLock);
InitializeCriticalSection(&g_csBagCacheLock);
SHPolicyCache_DllProcessAttach();
#endif
break;
case DLL_PROCESS_DETACH:
@@ -81,6 +84,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
SHLWAPI_DeleteCachedZonesManager();
DeleteCriticalSection(&g_csBagCacheLock);
DeleteCriticalSection(&g_csZoneMgrLock);
SHPolicyCache_DllProcessDetach();
#endif
if (SHLWAPI_ThreadRef_index != TLS_OUT_OF_INDEXES) TlsFree(SHLWAPI_ThreadRef_index);
break;
+13
View File
@@ -203,6 +203,19 @@ DEFINE_GUID(IID_IDriveFolderExt, 0x3EC36F3E, 0x5BA3, 0x4C3D, 0xBF, 0x3
DEFINE_GUID(IID_IPinnedListOld, 0xC3C6EB6D, 0xC837, 0x4EAE, 0xB1, 0x72, 0x5F, 0xEC, 0x52, 0xA2, 0xA4, 0xFD); /*version 6.0*/
DEFINE_GUID(IID_IPinnedList, 0xBBD20037, 0xBC0E, 0x42F1, 0x91, 0x3F, 0xE2, 0x93, 0x6B, 0xB0, 0xEA, 0x0C); /*version 6.1*/
DEFINE_GUID(GUID_Restrictions, 0xA48F1A32, 0xA340, 0x11D1, 0xBC, 0x6B, 0x00, 0xA0, 0xC9, 0x03, 0x12, 0xE1);
DEFINE_GUID(POLID_UsePathEnvVarForCommandTemplates, 0x1FF8F603, 0x056A, 0x4F52, 0x89, 0xCC, 0x82, 0xAD, 0x1C, 0xA1, 0xC1, 0x9A);
DEFINE_GUID(POLID_ScanWithAntiVirus, 0xECF90404, 0xF38C, 0x44FE, 0x9F, 0x1B, 0x02, 0xA7, 0x2B, 0xAF, 0x60, 0x3C);
DEFINE_GUID(POLID_SaveZoneInformation, 0xECF90405, 0xF38C, 0x44FE, 0x9F, 0x1B, 0x02, 0xA7, 0x2B, 0xAF, 0x60, 0x3C);
DEFINE_GUID(POLID_UseTrustedHandlers, 0xECF90406, 0xF38C, 0x44FE, 0x9F, 0x1B, 0x02, 0xA7, 0x2B, 0xAF, 0x60, 0x3C);
DEFINE_GUID(POLID_HideZoneInfoOnProperties, 0xECF90408, 0xF38C, 0x44FE, 0x9F, 0x1B, 0x02, 0xA7, 0x2B, 0xAF, 0x60, 0x3C);
DEFINE_GUID(POLID_DefaultFileTypeRisk, 0xECF90409, 0xF38C, 0x44FE, 0x9F, 0x1B, 0x02, 0xA7, 0x2B, 0xAF, 0x60, 0x3C);
DEFINE_GUID(POLID_HighRiskFileTypes, 0xECF9040A, 0xF38C, 0x44FE, 0x9F, 0x1B, 0x02, 0xA7, 0x2B, 0xAF, 0x60, 0x3C);
DEFINE_GUID(POLID_ModRiskFileTypes, 0xECF9040B, 0xF38C, 0x44FE, 0x9F, 0x1B, 0x02, 0xA7, 0x2B, 0xAF, 0x60, 0x3C);
DEFINE_GUID(POLID_LowRiskFileTypes, 0xECF9040C, 0xF38C, 0x44FE, 0x9F, 0x1B, 0x02, 0xA7, 0x2B, 0xAF, 0x60, 0x3C);
DEFINE_GUID(POLID_PreXPSP2ShellProtocolBehavior, 0x4FC60822, 0x47AF, 0x4BEE, 0xA7, 0xDA, 0xC9, 0x9A, 0x6E, 0x8E, 0x5D, 0x8D);
DEFINE_GUID(POLID_CompareJunctionness, 0xB3AB7D3B, 0x698F, 0x401E, 0xBF, 0x89, 0x30, 0x02, 0x33, 0x35, 0xA2, 0x67);
#define CGID_IExplorerToolbar IID_IExplorerToolbar
#define SID_IExplorerToolbar IID_IExplorerToolbar
#define SID_ITargetFrame2 IID_ITargetFrame2
+8
View File
@@ -497,6 +497,14 @@ PWSTR WINAPI CharLowerNoDBCSW(_Inout_ PWSTR lpString);
PSTR WINAPI CharUpperNoDBCSA(_Inout_ PSTR lpString);
PWSTR WINAPI CharUpperNoDBCSW(_Inout_ PWSTR lpString);
HRESULT WINAPI
SHWindowsPolicyGetValue(
_In_ REFGUID rpolid,
_Out_opt_ PVOID pvValue,
_Out_opt_ PDWORD pcbValue);
#define E_DATATYPE_MISMATCH HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH)
/*****************************************************************************
* IAssociationElementOld interface
*