[SHLWAPI][SHLWAPI_APITEST][SDK] Support QuerySourceCreateFromKey (#9093)

Implementing missing features...
JIRA issue: CORE-20467
- Add querysrc.cpp.
- Add CRegistryEnumValues,
  CRegistryEnumKeys, and
  CRegistrySource classes.
- Implement
  QuerySourceCreateFromKey
  function.
- Add prototype into
  <shlwapi_undoc.h>.
- Modify shlwapi.spec.
- Add QuerySourceCreateFromKey
  testcase.
This commit is contained in:
Katayama Hirofumi MZ
2026-05-31 17:33:17 +09:00
committed by GitHub
parent 93bd77f1f7
commit 3b3e1ff997
8 changed files with 783 additions and 2 deletions
+1
View File
@@ -27,6 +27,7 @@ list(APPEND PCH_SKIP_SOURCE
assoc.c
policy.cpp
propbag.cpp
querysrc.cpp
utils.cpp
wsprintf.c
zonechk.c
+511
View File
@@ -0,0 +1,511 @@
/*
* PROJECT: ReactOS Shell
* LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later)
* PURPOSE: Implement QuerySourceCreateFromKey
* COPYRIGHT: Copyright 2026 Katayama Hirofumi MZ <[email protected]>
*/
#include "precomp.h"
#include <shlwapi.h>
#include <shlwapi_undoc.h>
#include <shlobj_undoc.h>
#include <shlguid_undoc.h>
WINE_DEFAULT_DEBUG_CHANNEL(shell);
static HRESULT SHAllocBlob(ULONG cbData, const BYTE *pbData, FLAGGED_BYTE_BLOB** ppBlob)
{
FLAGGED_BYTE_BLOB* pBlob =
(FLAGGED_BYTE_BLOB*)CoTaskMemAlloc(sizeof(FLAGGED_BYTE_BLOB) + cbData);
if (!pBlob)
return E_OUTOFMEMORY;
pBlob->clSize = cbData;
if (pbData)
CopyMemory(pBlob->abData, pbData, cbData);
*ppBlob = pBlob;
return S_OK;
}
class CRegistrySource;
/******************************************************************************
* CRegistryEnumBase
*/
class CRegistryEnumBase : public IEnumString
{
protected:
LONG m_cRefs = 1;
DWORD m_dwIndex = 0;
CRegistrySource *m_pSource = NULL;
HKEY m_hKey = NULL;
PWSTR m_pszName = NULL;
WCHAR m_szBuf[64] = {};
DWORD m_cchNameMax = 0;
BOOL _Next(PWSTR *ppwsz);
virtual BOOL _RegNext(DWORD dwIndex) = 0;
virtual DWORD _MaxLen() = 0;
public:
virtual ~CRegistryEnumBase();
HRESULT Init(HKEY hKey, CRegistrySource *pSource);
// IUnknown methods
STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject) override;
STDMETHODIMP_(ULONG) AddRef() override;
STDMETHODIMP_(ULONG) Release() override;
// IEnumString methods
STDMETHODIMP Next(ULONG celt, LPWSTR* rgelt, ULONG* pceltFetched) override;
STDMETHODIMP Skip(ULONG celt) override;
STDMETHODIMP Reset() override;
STDMETHODIMP Clone(IEnumString ** ppenum) override;
};
/******************************************************************************
* CRegistryEnumValues
*/
class CRegistryEnumValues : public CRegistryEnumBase
{
public:
BOOL _RegNext(DWORD dwIndex) override;
DWORD _MaxLen() override;
};
/******************************************************************************
* CRegistryEnumKeys
*/
class CRegistryEnumKeys : public CRegistryEnumBase
{
public:
BOOL _RegNext(DWORD dwIndex) override;
DWORD _MaxLen() override;
};
/******************************************************************************
* CRegistrySource
*/
class CRegistrySource
: public IQuerySourceOld
, public IObjectWithRegistryKeyOld
{
LONG m_cRefs = 1;
HKEY m_hKey = NULL;
public:
virtual ~CRegistrySource();
HRESULT Init(HKEY hKey, PCWSTR pszSubKey, BOOL bCreate);
// IUnknown methods
STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject) override;
STDMETHODIMP_(ULONG) AddRef() override;
STDMETHODIMP_(ULONG) Release() override;
// IQuerySourceOld methods
STDMETHODIMP EnumValues(IEnumString **ppEnum) override;
STDMETHODIMP EnumSources(IEnumString **ppEnum) override;
STDMETHODIMP QueryValueString(PCWSTR keyName, PCWSTR valueName, PWSTR *ppszValue) override;
STDMETHODIMP QueryValueDword(PCWSTR keyName, PCWSTR valueName, DWORD *pdwValue) override;
STDMETHODIMP QueryValueExists(PCWSTR keyName, PCWSTR valueName) override;
STDMETHODIMP QueryValueDirect(PCWSTR keyName, PCWSTR valueName,
FLAGGED_BYTE_BLOB **ppBlob) override;
STDMETHODIMP OpenSource(PCWSTR keyName, BOOL bCreate, IQuerySourceOld **ppSource) override;
STDMETHODIMP SetValueDirect(PCWSTR keyName, PCWSTR valueName, DWORD dwType, DWORD cbData,
LPCVOID pvData) override;
// IObjectWithRegistryKeyOld methods
STDMETHODIMP SetKey(HKEY hKey) override;
STDMETHODIMP GetKey(HKEY *phKey) override;
};
/******************************************************************************/
CRegistryEnumBase::~CRegistryEnumBase()
{
if (m_pszName && m_pszName != m_szBuf)
LocalFree(m_pszName);
if (m_pSource)
m_pSource->Release();
}
HRESULT CRegistryEnumBase::Init(HKEY hKey, CRegistrySource *pSource)
{
m_hKey = hKey;
m_pSource = pSource;
m_pSource->AddRef();
m_cchNameMax = _MaxLen();
if (m_cchNameMax > _countof(m_szBuf))
{
m_pszName = (PWSTR)LocalAlloc(LPTR, m_cchNameMax * sizeof(WCHAR));
}
else
{
m_cchNameMax = _countof(m_szBuf);
m_pszName = m_szBuf;
}
return m_pszName ? S_OK : E_OUTOFMEMORY;
}
BOOL CRegistryEnumBase::_Next(PWSTR *ppwsz)
{
return _RegNext(m_dwIndex) && SUCCEEDED(SHStrDupW(m_pszName, ppwsz));
}
HRESULT CRegistryEnumBase::QueryInterface(REFIID riid, PVOID* ppv)
{
if (!ppv)
return E_POINTER;
if (riid == IID_IEnumString)
{
*ppv = static_cast<IEnumString*>(this);
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) CRegistryEnumBase::AddRef()
{
return ::InterlockedIncrement(&m_cRefs);
}
STDMETHODIMP_(ULONG) CRegistryEnumBase::Release()
{
LONG refs = ::InterlockedDecrement(&m_cRefs);
if (!refs)
delete this;
return refs;
}
STDMETHODIMP CRegistryEnumBase::Next(ULONG celt, LPWSTR* rgelt, ULONG* pceltFetched)
{
if (!rgelt || (celt > 1 && !pceltFetched))
return E_INVALIDARG;
ULONG cFetched = 0;
while (cFetched < celt)
{
if (!_Next(&rgelt[cFetched]))
break;
++m_dwIndex;
++cFetched;
}
if (pceltFetched)
*pceltFetched = cFetched;
return (cFetched == celt) ? S_OK : S_FALSE;
}
STDMETHODIMP CRegistryEnumBase::Skip(ULONG celt)
{
return E_NOTIMPL;
}
STDMETHODIMP CRegistryEnumBase::Reset()
{
m_dwIndex = 0;
return S_OK;
}
STDMETHODIMP CRegistryEnumBase::Clone(IEnumString ** ppenum)
{
return E_NOTIMPL;
}
/******************************************************************************/
BOOL CRegistryEnumKeys::_RegNext(DWORD dwIndex)
{
return RegEnumKeyW(m_hKey, dwIndex, m_pszName, m_cchNameMax) == ERROR_SUCCESS;
}
DWORD CRegistryEnumKeys::_MaxLen()
{
DWORD cchKeyNameMax = 0;
RegQueryInfoKeyW(m_hKey, NULL, NULL, NULL, NULL, &cchKeyNameMax, NULL, NULL, NULL, NULL,
NULL, NULL);
return cchKeyNameMax + 1; // Including NUL
}
/******************************************************************************/
BOOL CRegistryEnumValues::_RegNext(DWORD dwIndex)
{
DWORD cchValueNameMax = m_cchNameMax;
return RegEnumValueW(m_hKey, dwIndex, m_pszName, &cchValueNameMax, NULL,
NULL, NULL, NULL) == ERROR_SUCCESS;
}
DWORD CRegistryEnumValues::_MaxLen()
{
DWORD cchValueNameMax = 0;
RegQueryInfoKeyW(m_hKey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &cchValueNameMax,
NULL, NULL, NULL);
return cchValueNameMax + 1; // Including NUL
}
/******************************************************************************/
CRegistrySource::~CRegistrySource()
{
if (m_hKey)
RegCloseKey(m_hKey);
}
HRESULT CRegistrySource::Init(HKEY hKey, PCWSTR pszSubKey, BOOL bCreate)
{
LSTATUS error;
if (bCreate)
error = RegCreateKeyExW(hKey, pszSubKey, 0, NULL, 0, MAXIMUM_ALLOWED, NULL, &m_hKey, NULL);
else
error = RegOpenKeyExW(hKey, pszSubKey, 0, MAXIMUM_ALLOWED, &m_hKey);
return error ? HRESULT_FROM_WIN32(error) : S_OK;
}
STDMETHODIMP CRegistrySource::QueryInterface(REFIID riid, void **ppvObject)
{
if (!ppvObject)
return E_POINTER;
if (riid == IID_IQuerySourceOld)
{
*ppvObject = static_cast<IQuerySourceOld*>(this);
AddRef();
return S_OK;
}
if (riid == IID_IObjectWithRegistryKeyOld)
{
*ppvObject = static_cast<IObjectWithRegistryKeyOld*>(this);
AddRef();
return S_OK;
}
*ppvObject = NULL;
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) CRegistrySource::AddRef()
{
return ::InterlockedIncrement(&m_cRefs);
}
STDMETHODIMP_(ULONG) CRegistrySource::Release()
{
LONG refs = ::InterlockedDecrement(&m_cRefs);
if (!refs)
delete this;
return refs;
}
STDMETHODIMP CRegistrySource::EnumValues(IEnumString **ppEnum)
{
CRegistryEnumValues* pEnum = new CRegistryEnumValues();
HRESULT hr = pEnum->Init(m_hKey, this);
if (FAILED(hr))
{
pEnum->Release();
pEnum = NULL;
}
*ppEnum = pEnum;
return pEnum ? S_OK : E_OUTOFMEMORY;
}
STDMETHODIMP CRegistrySource::EnumSources(IEnumString **ppEnum)
{
CRegistryEnumKeys* pEnum = new CRegistryEnumKeys();
HRESULT hr = pEnum->Init(m_hKey, this);
if (FAILED(hr))
{
pEnum->Release();
pEnum = NULL;
}
*ppEnum = pEnum;
return pEnum ? S_OK : E_OUTOFMEMORY;
}
STDMETHODIMP CRegistrySource::QueryValueString(
PCWSTR keyName,
PCWSTR valueName,
PWSTR *ppszValue)
{
*ppszValue = NULL;
WCHAR szData[128];
DWORD dwType = REG_NONE, cbData = sizeof(szData);
LSTATUS error = SHGetValueW(m_hKey, keyName, valueName, &dwType, szData, &cbData);
if (error == ERROR_SUCCESS)
{
if (dwType != REG_SZ)
return E_DATATYPE_MISMATCH;
if (!valueName && !szData[0])
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
return SHStrDupW(szData, ppszValue);
}
if (error != ERROR_MORE_DATA)
return error ? HRESULT_FROM_WIN32(error) : S_OK;
*ppszValue = (PWSTR)CoTaskMemAlloc(cbData);
if (!*ppszValue)
return E_OUTOFMEMORY;
HRESULT hr = S_OK;
error = SHGetValueW(m_hKey, keyName, valueName, &dwType, *ppszValue, &cbData);
if (error)
{
CoTaskMemFree(*ppszValue);
*ppszValue = NULL;
hr = HRESULT_FROM_WIN32(error);
}
if (SUCCEEDED(hr) && dwType != REG_SZ)
{
CoTaskMemFree(*ppszValue);
*ppszValue = NULL;
hr = E_DATATYPE_MISMATCH;
}
return hr;
}
STDMETHODIMP CRegistrySource::QueryValueDword(PCWSTR keyName, PCWSTR valueName, DWORD *pdwValue)
{
DWORD dwType, cbValue = sizeof(*pdwValue);
LSTATUS error = SHGetValueW(m_hKey, keyName, valueName, &dwType, pdwValue, &cbValue);
if (error)
return HRESULT_FROM_WIN32(error);
if (dwType != REG_DWORD)
return E_DATATYPE_MISMATCH;
return S_OK;
}
STDMETHODIMP CRegistrySource::QueryValueExists(PCWSTR keyName, PCWSTR valueName)
{
LSTATUS error = SHGetValueW(m_hKey, keyName, valueName, NULL, NULL, NULL);
if (error)
return HRESULT_FROM_WIN32(error);
return S_OK;
}
STDMETHODIMP CRegistrySource::QueryValueDirect(
PCWSTR keyName,
PCWSTR valueName,
FLAGGED_BYTE_BLOB **ppBlob)
{
HRESULT hr = E_FAIL;
HKEY hKey = m_hKey;
DWORD dwType = REG_NONE;
DWORD cbData = 256;
BYTE abData[256];
*ppBlob = NULL;
if (keyName && *keyName &&
RegOpenKeyExW(m_hKey, keyName, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
{
return E_FAIL;
}
LSTATUS error = RegQueryValueExW(hKey, valueName, NULL, &dwType, abData, &cbData);
if (error == ERROR_SUCCESS)
{
hr = SHAllocBlob(cbData, abData, ppBlob);
}
else if (error == ERROR_MORE_DATA)
{
hr = SHAllocBlob(cbData, NULL, ppBlob);
if (SUCCEEDED(hr))
{
error = RegQueryValueExW(hKey, valueName, NULL, &dwType, (*ppBlob)->abData, &cbData);
if (error != ERROR_SUCCESS)
{
CoTaskMemFree(*ppBlob);
*ppBlob = NULL;
hr = error ? HRESULT_FROM_WIN32(error) : S_OK;
}
}
}
else
{
hr = HRESULT_FROM_WIN32(error);
}
if (hKey != m_hKey)
RegCloseKey(hKey);
if (SUCCEEDED(hr))
(*ppBlob)->fFlags = dwType;
return hr;
}
STDMETHODIMP CRegistrySource::OpenSource(PCWSTR keyName, BOOL bCreate, IQuerySourceOld **ppSource)
{
return QuerySourceCreateFromKey(m_hKey, keyName, bCreate, IID_IQuerySourceOld, (PVOID*)ppSource);
}
STDMETHODIMP CRegistrySource::SetValueDirect(
PCWSTR keyName,
PCWSTR valueName,
DWORD dwType,
DWORD cbData,
LPCVOID pvData)
{
LSTATUS error = SHSetValueW(m_hKey, keyName, valueName, dwType, pvData, cbData);
if (error)
return HRESULT_FROM_WIN32(error);
return S_OK;
}
STDMETHODIMP CRegistrySource::SetKey(HKEY hKey)
{
if (m_hKey)
return E_UNEXPECTED;
m_hKey = SHRegDuplicateHKey(hKey);
return m_hKey ? S_OK : E_UNEXPECTED;
}
STDMETHODIMP CRegistrySource::GetKey(HKEY *phKey)
{
if (!m_hKey)
return E_UNEXPECTED;
*phKey = SHRegDuplicateHKey(m_hKey);
if (!*phKey)
return E_UNEXPECTED;
return S_OK;
}
/**************************************************************************
* QuerySourceCreateFromKey (SHLWAPI.544)
*
* @see https://www.geoffchappell.com/studies/windows/shell/shlwapi/api/regsrc/createfromkey.htm
*/
EXTERN_C
HRESULT WINAPI
QuerySourceCreateFromKey(
_In_ HKEY hKey,
_In_opt_ PCWSTR lpSubKey,
_In_ BOOL bCreate,
_In_ REFIID riid,
_Outptr_ PVOID *ppv)
{
*ppv = NULL;
CRegistrySource* pRS = new CRegistrySource();
HRESULT hr = pRS->Init(hKey, lpSubKey, bCreate);
if (SUCCEEDED(hr))
hr = pRS->QueryInterface(riid, ppv);
pRS->Release();
return hr;
}
+1 -1
View File
@@ -541,7 +541,7 @@
541 stdcall -noname SHInvokeCommandsOnContextMenu(ptr ptr ptr long ptr long)
542 stdcall -noname GetUIVersion()
543 stdcall -noname CreateColorSpaceWrapW(ptr) gdi32.CreateColorSpaceW
544 stub -noname QuerySourceCreateFromKey
544 stdcall -noname QuerySourceCreateFromKey(ptr wstr long ptr ptr)
545 stdcall -noname SHForwardContextMenuMsg(ptr long long long ptr long)
546 stub -noname IUnknown_DoContextMenuPopup
547 stdcall DelayLoadFailureHook(str str) kernel32.DelayLoadFailureHook
@@ -17,6 +17,7 @@ list(APPEND SOURCE
PathIsUNCServerShare.c
PathUnExpandEnvStrings.c
PathUnExpandEnvStringsForUser.c
QuerySourceCreateFromKey.cpp
SHAreIconsEqual.c
SHGetRestriction.c
SHInvokeCommandsOnContextMenu.cpp
@@ -0,0 +1,258 @@
/*
* PROJECT: ReactOS api tests
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Tests for QuerySourceCreateFromKey
* COPYRIGHT: Copyright 2026 Katayama Hirofumi MZ <[email protected]>
*/
#include <apitest.h>
#include <shlobj.h>
#include <shlwapi.h>
#include <shlguid_undoc.h>
#include <shlobj_undoc.h>
#include <shlwapi_undoc.h>
#include <versionhelpers.h>
typedef HRESULT (WINAPI *FN_QuerySourceCreateFromKey)(HKEY, PCWSTR, BOOL, REFIID, PVOID*);
static FN_QuerySourceCreateFromKey g_pQuerySourceCreateFromKey = NULL;
static const WCHAR k_Root[] = L"Software\\QuerySrcTest";
static const WCHAR k_SubKeyA[] = L"SubKeyA";
static const WCHAR k_SubKeyB[] = L"SubKeyB";
static void SetupRegistry(void)
{
HKEY hRoot;
RegCreateKeyExW(HKEY_CURRENT_USER, k_Root, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hRoot, NULL);
static const WCHAR valA[] = L"hello";
RegSetValueExW(hRoot, L"ValueA", 0, REG_SZ, (const BYTE*)valA, (DWORD)sizeof(valA));
DWORD dwValue = 0xBEEFCAFE;
RegSetValueExW(hRoot, L"ValueB", 0, REG_DWORD, (const BYTE*)&dwValue, (DWORD)sizeof(dwValue));
HKEY hSub;
RegCreateKeyExW(hRoot, k_SubKeyA, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hSub, NULL);
RegCloseKey(hSub);
RegCreateKeyExW(hRoot, k_SubKeyB, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hSub, NULL);
RegCloseKey(hSub);
RegCloseKey(hRoot);
}
static void CleanupRegistry(void)
{
SHDeleteKeyW(HKEY_CURRENT_USER, k_Root);
}
static void Test_EnumValues(void)
{
IQuerySourceOld *pSrc = NULL;
HRESULT hr = g_pQuerySourceCreateFromKey(HKEY_CURRENT_USER, k_Root, FALSE,
IID_IQuerySourceOld, (PVOID*)&pSrc);
ok_hr(hr, S_OK);
ok(pSrc != NULL, "pSrc was NULL\n");
IEnumString *pEnum = NULL;
hr = 0xDEADFACE;
if (pSrc)
hr = pSrc->EnumValues(&pEnum);
ok(pSrc && hr == S_OK, "EnumValues failed: 0x%08X\n", hr);
LPWSTR psz = NULL;
ULONG fetched = 0;
hr = 0xDEADFACE;
if (pEnum)
hr = pEnum->Next(1, &psz, &fetched);
ok_hr(hr, S_OK);
ok(lstrcmpiW(psz, L"ValueA") == 0, "psz was %s\n", wine_dbgstr_w(psz));
ok_int(fetched, 1);
CoTaskMemFree(psz);
psz = NULL;
fetched = 0;
hr = 0xDEADFACE;
if (pEnum)
hr = pEnum->Next(1, &psz, &fetched);
ok_hr(hr, S_OK);
ok(lstrcmpiW(psz, L"ValueB") == 0, "psz was %s\n", wine_dbgstr_w(psz));
ok_int(fetched, 1);
CoTaskMemFree(psz);
psz = NULL;
fetched = 0;
hr = 0xDEADFACE;
if (pEnum)
hr = pEnum->Next(1, &psz, &fetched);
ok_hr(hr, S_FALSE);
ok(psz == NULL, "psz was %s\n", wine_dbgstr_w(psz));
ok_int(fetched, 0);
CoTaskMemFree(psz);
if (pEnum)
pEnum->Release();
if (pSrc)
pSrc->Release();
}
static void Test_EnumSources(void)
{
IQuerySourceOld *pSrc = NULL;
HRESULT hr = g_pQuerySourceCreateFromKey(HKEY_CURRENT_USER, k_Root, FALSE,
IID_IQuerySourceOld, (PVOID*)&pSrc);
ok_hr(hr, S_OK);
ok(pSrc != NULL, "pSrc was NULL\n");
IEnumString *pEnum = NULL;
hr = pSrc->EnumSources(&pEnum);
ok_hr(hr, S_OK);
ok(pEnum != NULL, "pEnum was NULL\n");
LPWSTR psz = NULL;
ULONG fetched = 0;
hr = 0xDEADFACE;
if (pEnum)
hr = pEnum->Next(1, &psz, &fetched);
ok_hr(hr, S_OK);
ok(lstrcmpiW(psz, k_SubKeyA) == 0, "psz was %s\n", wine_dbgstr_w(psz));
ok_int(fetched, 1);
CoTaskMemFree(psz);
psz = NULL;
fetched = 0;
hr = 0xDEADFACE;
if (pEnum)
hr = pEnum->Next(1, &psz, &fetched);
ok_hr(hr, S_OK);
ok(lstrcmpiW(psz, k_SubKeyB) == 0, "psz was %s\n", wine_dbgstr_w(psz));
ok_int(fetched, 1);
CoTaskMemFree(psz);
psz = NULL;
fetched = 0;
hr = 0xDEADFACE;
if (pEnum)
hr = pEnum->Next(1, &psz, &fetched);
ok_hr(hr, S_FALSE);
ok(psz == NULL, "psz was %s\n", wine_dbgstr_w(psz));
ok_int(fetched, 0);
CoTaskMemFree(psz);
if (pSrc)
pSrc->Release();
}
static void Test_CheckValues(void)
{
IQuerySourceOld *pSrc = NULL;
HRESULT hr = g_pQuerySourceCreateFromKey(HKEY_CURRENT_USER, k_Root, FALSE,
IID_IQuerySourceOld, (PVOID*)&pSrc);
ok_hr(hr, S_OK);
ok(pSrc != NULL, "pSrc was NULL\n");
PWSTR pszValue;
// QueryValueString
hr = 0xDEADFACE;
pszValue = NULL;
if (pSrc)
hr = pSrc->QueryValueString(NULL, L"ValueA", &pszValue);
ok_hr(hr, S_OK);
ok(lstrcmpiW(pszValue, L"hello") == 0, "pszValue was %s\n", wine_dbgstr_w(pszValue));
hr = 0xDEADFACE;
pszValue = NULL;
if (pSrc)
hr = pSrc->QueryValueString(NULL, L"ValueB", &pszValue);
ok_hr(hr, E_DATATYPE_MISMATCH);
ok(pszValue == NULL, "pszValue was %s\n", wine_dbgstr_w(pszValue));
// QueryValueExists
hr = 0xDEADFACE;
if (pSrc)
hr = pSrc->QueryValueExists(NULL, L"ValueA");
ok_hr(hr, S_OK);
if (pSrc)
hr = pSrc->QueryValueExists(NULL, L"ValueB");
ok_hr(hr, S_OK);
DWORD dwValue;
// QueryValueDword
dwValue = 0xDEADFACE;
hr = 0xDEADFACE;
if (pSrc)
hr = pSrc->QueryValueDword(NULL, L"ValueA", &dwValue);
ok_hr(hr, HRESULT_FROM_WIN32(ERROR_MORE_DATA));
ok_long(dwValue, 0xDEADFACE);
dwValue = 0xDEADFACE;
hr = 0xDEADFACE;
if (pSrc)
hr = pSrc->QueryValueDword(NULL, L"ValueB", &dwValue);
ok_hr(hr, S_OK);
ok_long(dwValue, 0xBEEFCAFE);
FLAGGED_BYTE_BLOB *pBlob;
// QueryValueDirect
hr = 0xDEADFACE;
pBlob = NULL;
if (pSrc)
hr = pSrc->QueryValueDirect(NULL, L"ValueA", &pBlob);
ok_hr(hr, S_OK);
ok(pBlob != NULL, "pBlob was %p\n", pBlob);
ok(pBlob && pBlob->clSize == 12, "pBlob->clSize was %ld\n", pBlob->clSize);
ok(pBlob && !memcmp(pBlob->abData, L"hello", 12), "pBlob->abData mismatch\n");
CoTaskMemFree(pBlob);
hr = 0xDEADFACE;
pBlob = NULL;
if (pSrc)
hr = pSrc->QueryValueDirect(NULL, L"ValueB", &pBlob);
ok_hr(hr, S_OK);
ok(pBlob != NULL, "pBlob was %p\n", pBlob);
ok(pBlob && pBlob->clSize == 4, "pBlob->clSize was %ld\n", pBlob->clSize);
dwValue = 0xBEEFCAFE;
ok(pBlob && !memcmp(pBlob->abData, &dwValue, sizeof(dwValue)), "pBlob->abData mismatch\n");
CoTaskMemFree(pBlob);
if (pSrc)
pSrc->Release();
}
START_TEST(QuerySourceCreateFromKey)
{
if (IsWindowsVistaOrGreater())
{
skip("Vista+ is not tested well\n");
return;
}
g_pQuerySourceCreateFromKey = (FN_QuerySourceCreateFromKey)
GetProcAddress(GetModuleHandleA("shlwapi"), MAKEINTRESOURCEA(544));
if (!g_pQuerySourceCreateFromKey)
{
skip("QuerySourceCreateFromKey not found\n");
return;
}
HRESULT hrCoInit = CoInitialize(NULL);
SetupRegistry();
Test_EnumValues();
Test_EnumSources();
Test_CheckValues();
CleanupRegistry();
if (SUCCEEDED(hrCoInit))
CoUninitialize();
}
@@ -13,6 +13,7 @@ extern void func_PathIsUNCServer(void);
extern void func_PathIsUNCServerShare(void);
extern void func_PathUnExpandEnvStrings(void);
extern void func_PathUnExpandEnvStringsForUser(void);
extern void func_QuerySourceCreateFromKey(void);
extern void func_SHAreIconsEqual(void);
extern void func_SHGetRestriction(void);
extern void func_SHInvokeCommandsOnContextMenu(void);
@@ -37,6 +38,7 @@ const struct test winetest_testlist[] =
{ "PathIsUNCServerShare", func_PathIsUNCServerShare },
{ "PathUnExpandEnvStrings", func_PathUnExpandEnvStrings },
{ "PathUnExpandEnvStringsForUser", func_PathUnExpandEnvStringsForUser },
{ "QuerySourceCreateFromKey", func_QuerySourceCreateFromKey },
{ "SHAreIconsEqual", func_SHAreIconsEqual },
{ "SHGetRestriction", func_SHGetRestriction },
{ "SHInvokeCommandsOnContextMenu", func_SHInvokeCommandsOnContextMenu },
+1 -1
View File
@@ -888,7 +888,7 @@ DECLARE_INTERFACE_(IQuerySourceOld, IUnknown) // {C7478486-7583-49E7-A6C2-FAF8F0
STDMETHOD(QueryValueExists)(THIS_ PCWSTR keyName, PCWSTR valueName) PURE;
STDMETHOD(QueryValueDirect)(THIS_ PCWSTR keyName, PCWSTR valueName, FLAGGED_BYTE_BLOB **ppBlob) PURE;
STDMETHOD(OpenSource)(THIS_ PCWSTR keyName, BOOL bCreate, IQuerySourceOld **ppSource) PURE;
STDMETHOD(SetValueDirect)(THIS_ PCWSTR keyName, PCWSTR valueName, DWORD, DWORD, PBYTE) PURE;
STDMETHOD(SetValueDirect)(THIS_ PCWSTR keyName, PCWSTR valueName, DWORD dwType, DWORD cbData, LPCVOID pbData) PURE;
};
#undef INTERFACE
+8
View File
@@ -126,6 +126,14 @@ EXTERN_C BOOL WINAPI SHBoolSystemParametersInfo(UINT uiAction, PVOID pvParam);
HRESULT WINAPI SHRegGetCLSIDKeyW(REFGUID guid, LPCWSTR lpszValue, BOOL bUseHKCU, BOOL bCreate, PHKEY phKey);
HRESULT WINAPI
QuerySourceCreateFromKey(
_In_ HKEY hKey,
_In_opt_ PCWSTR lpSubKey,
_In_ BOOL bCreate,
_In_ REFIID riid,
_Outptr_ PVOID *ppv);
BOOL WINAPI SHAddDataBlock(LPDBLIST* lppList, const DATABLOCK_HEADER *lpNewItem);
BOOL WINAPI SHRemoveDataBlock(LPDBLIST* lppList, DWORD dwSignature);
DATABLOCK_HEADER* WINAPI SHFindDataBlock(LPDBLIST lpList, DWORD dwSignature);