mirror of
https://github.com/reactos/reactos.git
synced 2024-12-12 04:43:48 +08:00
[SHLWAPI][SHLWAPI_APITEST][SDK] SHCreatePropertyBagOnRegKey (#5531)
Follow-up to #5511. - Add CRegPropertyBag class. - Implement SHCreatePropertyBagOnRegKey function by using CRegPropertyBag. - Strengthen SHPropertyBag testcase in shlwapi_apitest. CORE-9283
This commit is contained in:
parent
6413024cab
commit
b4684e9809
@ -5068,6 +5068,7 @@ free_sids:
|
|||||||
return psd;
|
return psd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef __REACTOS__ /* See propbag.cpp */
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* SHCreatePropertyBagOnRegKey [SHLWAPI.471]
|
* SHCreatePropertyBagOnRegKey [SHLWAPI.471]
|
||||||
*
|
*
|
||||||
@ -5093,6 +5094,7 @@ HRESULT WINAPI SHCreatePropertyBagOnRegKey (HKEY hKey, LPCWSTR subkey,
|
|||||||
|
|
||||||
return E_NOTIMPL;
|
return E_NOTIMPL;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* SHGetViewStatePropertyBag [SHLWAPI.515]
|
* SHGetViewStatePropertyBag [SHLWAPI.515]
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
#include <wingdi.h>
|
#include <wingdi.h>
|
||||||
#include <wincon.h>
|
#include <wincon.h>
|
||||||
#include <winternl.h>
|
#include <winternl.h>
|
||||||
#define NO_SHLWAPI_STREAM
|
|
||||||
#define NO_SHLWAPI_USER
|
#define NO_SHLWAPI_USER
|
||||||
#include <shlwapi.h>
|
#include <shlwapi.h>
|
||||||
#include <shlobj.h>
|
#include <shlobj.h>
|
||||||
|
@ -51,6 +51,8 @@ public:
|
|||||||
*ppvObject = static_cast<IPropertyBag*>(this);
|
*ppvObject = static_cast<IPropertyBag*>(this);
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ERR("%p: %s: E_NOTIMPL\n", this, debugstr_guid(&riid));
|
||||||
return E_NOTIMPL;
|
return E_NOTIMPL;
|
||||||
}
|
}
|
||||||
STDMETHODIMP_(ULONG) AddRef() override
|
STDMETHODIMP_(ULONG) AddRef() override
|
||||||
@ -245,9 +247,336 @@ SHCreatePropertyBagOnMemory(_In_ DWORD dwMode, _In_ REFIID riid, _Out_ void **pp
|
|||||||
|
|
||||||
CComPtr<CMemPropertyBag> pMemBag(new CMemPropertyBag(dwMode));
|
CComPtr<CMemPropertyBag> pMemBag(new CMemPropertyBag(dwMode));
|
||||||
|
|
||||||
HRESULT hr = pMemBag->QueryInterface(riid, ppvObj);
|
return pMemBag->QueryInterface(riid, ppvObj);
|
||||||
if (FAILED(hr))
|
}
|
||||||
ERR("0x%08X %s\n", hr, debugstr_guid(&riid));
|
|
||||||
|
class CRegPropertyBag : public CBasePropertyBag
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
HKEY m_hKey;
|
||||||
|
|
||||||
|
HRESULT _ReadDword(LPCWSTR pszPropName, VARIANT *pvari);
|
||||||
|
HRESULT _ReadString(LPCWSTR pszPropName, VARIANTARG *pvarg, UINT len);
|
||||||
|
HRESULT _ReadBinary(LPCWSTR pszPropName, VARIANT *pvari, VARTYPE vt, DWORD uBytes);
|
||||||
|
HRESULT _ReadStream(VARIANT *pvari, BYTE *pInit, UINT cbInit);
|
||||||
|
HRESULT _CopyStreamIntoBuff(IStream *pStream, void *pv, ULONG cb);
|
||||||
|
HRESULT _GetStreamSize(IStream *pStream, LPDWORD pcbSize);
|
||||||
|
HRESULT _WriteStream(LPCWSTR pszPropName, IStream *pStream);
|
||||||
|
|
||||||
|
public:
|
||||||
|
CRegPropertyBag(DWORD dwMode)
|
||||||
|
: CBasePropertyBag(dwMode)
|
||||||
|
, m_hKey(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~CRegPropertyBag() override
|
||||||
|
{
|
||||||
|
if (m_hKey)
|
||||||
|
::RegCloseKey(m_hKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT Init(HKEY hKey, LPCWSTR lpSubKey);
|
||||||
|
|
||||||
|
STDMETHODIMP Read(_In_z_ LPCWSTR pszPropName, _Inout_ VARIANT *pvari,
|
||||||
|
_Inout_opt_ IErrorLog *pErrorLog) override;
|
||||||
|
STDMETHODIMP Write(_In_z_ LPCWSTR pszPropName, _In_ VARIANT *pvari) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
HRESULT CRegPropertyBag::Init(HKEY hKey, LPCWSTR lpSubKey)
|
||||||
|
{
|
||||||
|
REGSAM nAccess = 0;
|
||||||
|
if ((m_dwMode & (STGM_READ | STGM_WRITE | STGM_READWRITE)) != STGM_WRITE)
|
||||||
|
nAccess |= KEY_READ;
|
||||||
|
if ((m_dwMode & (STGM_READ | STGM_WRITE | STGM_READWRITE)) != STGM_READ)
|
||||||
|
nAccess |= KEY_WRITE;
|
||||||
|
|
||||||
|
LONG error;
|
||||||
|
if (m_dwMode & STGM_CREATE)
|
||||||
|
error = ::RegCreateKeyExW(hKey, lpSubKey, 0, NULL, 0, nAccess, NULL, &m_hKey, NULL);
|
||||||
|
else
|
||||||
|
error = ::RegOpenKeyExW(hKey, lpSubKey, 0, nAccess, &m_hKey);
|
||||||
|
|
||||||
|
if (error != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
ERR("%p %s 0x%08X\n", hKey, debugstr_w(lpSubKey), error);
|
||||||
|
return HRESULT_FROM_WIN32(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT CRegPropertyBag::_ReadDword(LPCWSTR pszPropName, VARIANT *pvari)
|
||||||
|
{
|
||||||
|
DWORD cbData = sizeof(DWORD);
|
||||||
|
LONG error = SHGetValueW(m_hKey, NULL, pszPropName, NULL, &V_UI4(pvari), &cbData);
|
||||||
|
if (error)
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
|
V_VT(pvari) = VT_UI4;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT CRegPropertyBag::_ReadString(LPCWSTR pszPropName, VARIANTARG *pvarg, UINT len)
|
||||||
|
{
|
||||||
|
BSTR bstr = ::SysAllocStringByteLen(NULL, len);
|
||||||
|
V_BSTR(pvarg) = bstr;
|
||||||
|
if (!bstr)
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
|
|
||||||
|
V_VT(pvarg) = VT_BSTR;
|
||||||
|
LONG error = SHGetValueW(m_hKey, NULL, pszPropName, NULL, bstr, (LPDWORD)&len);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
::VariantClear(pvarg);
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT CRegPropertyBag::_ReadStream(VARIANT *pvari, BYTE *pInit, UINT cbInit)
|
||||||
|
{
|
||||||
|
IStream *pStream = SHCreateMemStream(pInit, cbInit);
|
||||||
|
V_UNKNOWN(pvari) = pStream;
|
||||||
|
if (!pStream)
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
|
V_VT(pvari) = VT_UNKNOWN;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT
|
||||||
|
CRegPropertyBag::_ReadBinary(
|
||||||
|
LPCWSTR pszPropName,
|
||||||
|
VARIANT *pvari,
|
||||||
|
VARTYPE vt,
|
||||||
|
DWORD uBytes)
|
||||||
|
{
|
||||||
|
HRESULT hr = E_FAIL;
|
||||||
|
if (vt != VT_UNKNOWN || uBytes < sizeof(GUID))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
LPBYTE pbData = (LPBYTE)::LocalAlloc(LMEM_ZEROINIT, uBytes);
|
||||||
|
if (!pbData)
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
if (!SHGetValueW(m_hKey, NULL, pszPropName, NULL, pbData, &uBytes) &&
|
||||||
|
memcmp(&GUID_NULL, pbData, sizeof(GUID)) == 0)
|
||||||
|
{
|
||||||
|
hr = _ReadStream(pvari, pbData + sizeof(GUID), uBytes - sizeof(GUID));
|
||||||
|
}
|
||||||
|
|
||||||
|
::LocalFree(pbData);
|
||||||
|
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HRESULT CRegPropertyBag::_CopyStreamIntoBuff(IStream *pStream, void *pv, ULONG cb)
|
||||||
|
{
|
||||||
|
LARGE_INTEGER li;
|
||||||
|
li.QuadPart = 0;
|
||||||
|
HRESULT hr = pStream->Seek(li, 0, NULL);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
|
return pStream->Read(pv, cb, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT CRegPropertyBag::_GetStreamSize(IStream *pStream, LPDWORD pcbSize)
|
||||||
|
{
|
||||||
|
*pcbSize = 0;
|
||||||
|
|
||||||
|
ULARGE_INTEGER ui;
|
||||||
|
HRESULT hr = IStream_Size(pStream, &ui);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
if (ui.DUMMYSTRUCTNAME.HighPart)
|
||||||
|
return E_FAIL; /* 64-bit value is not supported */
|
||||||
|
|
||||||
|
*pcbSize = ui.DUMMYSTRUCTNAME.LowPart;
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
STDMETHODIMP
|
||||||
|
CRegPropertyBag::Read(
|
||||||
|
_In_z_ LPCWSTR pszPropName,
|
||||||
|
_Inout_ VARIANT *pvari,
|
||||||
|
_Inout_opt_ IErrorLog *pErrorLog)
|
||||||
|
{
|
||||||
|
UNREFERENCED_PARAMETER(pErrorLog);
|
||||||
|
|
||||||
|
TRACE("%p: %s %p %p\n", this, debugstr_w(pszPropName), pvari, pErrorLog);
|
||||||
|
|
||||||
|
if ((m_dwMode & (STGM_READ | STGM_WRITE | STGM_READWRITE)) == STGM_WRITE)
|
||||||
|
{
|
||||||
|
ERR("%p: 0x%X\n", this, m_dwMode);
|
||||||
|
::VariantInit(pvari);
|
||||||
|
return E_ACCESSDENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
VARTYPE vt = V_VT(pvari);
|
||||||
|
VariantInit(pvari);
|
||||||
|
|
||||||
|
HRESULT hr;
|
||||||
|
DWORD dwType, cbValue;
|
||||||
|
LONG error = SHGetValueW(m_hKey, NULL, pszPropName, &dwType, NULL, &cbValue);
|
||||||
|
if (error != ERROR_SUCCESS)
|
||||||
|
hr = E_FAIL;
|
||||||
|
else if (dwType == REG_SZ)
|
||||||
|
hr = _ReadString(pszPropName, pvari, cbValue);
|
||||||
|
else if (dwType == REG_BINARY)
|
||||||
|
hr = _ReadBinary(pszPropName, pvari, vt, cbValue);
|
||||||
|
else if (dwType == REG_DWORD)
|
||||||
|
hr = _ReadDword(pszPropName, pvari);
|
||||||
|
else
|
||||||
|
hr = E_FAIL;
|
||||||
|
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
ERR("%p: 0x%08X %ld: %s %p\n", this, hr, dwType, debugstr_w(pszPropName), pvari);
|
||||||
|
::VariantInit(pvari);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = ::VariantChangeTypeForRead(pvari, vt);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
ERR("%p: 0x%08X %ld: %s %p\n", this, hr, dwType, debugstr_w(pszPropName), pvari);
|
||||||
|
::VariantInit(pvari);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT
|
||||||
|
CRegPropertyBag::_WriteStream(LPCWSTR pszPropName, IStream *pStream)
|
||||||
|
{
|
||||||
|
DWORD cbData;
|
||||||
|
HRESULT hr = _GetStreamSize(pStream, &cbData);
|
||||||
|
if (FAILED(hr) || !cbData)
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
DWORD cbBinary = cbData + sizeof(GUID);
|
||||||
|
LPBYTE pbBinary = (LPBYTE)::LocalAlloc(LMEM_ZEROINIT, cbBinary);
|
||||||
|
if (!pbBinary)
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
|
|
||||||
|
hr = _CopyStreamIntoBuff(pStream, pbBinary + sizeof(GUID), cbData);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
if (SHSetValueW(m_hKey, NULL, pszPropName, REG_BINARY, pbBinary, cbBinary))
|
||||||
|
hr = E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
::LocalFree(pbBinary);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
STDMETHODIMP
|
||||||
|
CRegPropertyBag::Write(_In_z_ LPCWSTR pszPropName, _In_ VARIANT *pvari)
|
||||||
|
{
|
||||||
|
TRACE("%p: %s %p\n", this, debugstr_w(pszPropName), pvari);
|
||||||
|
|
||||||
|
if ((m_dwMode & (STGM_READ | STGM_WRITE | STGM_READWRITE)) == STGM_READ)
|
||||||
|
{
|
||||||
|
ERR("%p: 0x%X\n", this, m_dwMode);
|
||||||
|
return E_ACCESSDENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT hr;
|
||||||
|
LONG error;
|
||||||
|
VARIANTARG vargTemp = { 0 };
|
||||||
|
switch (V_VT(pvari))
|
||||||
|
{
|
||||||
|
case VT_EMPTY:
|
||||||
|
SHDeleteValueW(m_hKey, NULL, pszPropName);
|
||||||
|
hr = S_OK;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VT_BOOL:
|
||||||
|
case VT_I1:
|
||||||
|
case VT_I2:
|
||||||
|
case VT_I4:
|
||||||
|
case VT_UI1:
|
||||||
|
case VT_UI2:
|
||||||
|
case VT_UI4:
|
||||||
|
case VT_INT:
|
||||||
|
case VT_UINT:
|
||||||
|
{
|
||||||
|
hr = ::VariantChangeType(&vargTemp, pvari, 0, VT_UI4);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
error = SHSetValueW(m_hKey, NULL, pszPropName, REG_DWORD, &V_UI4(&vargTemp), sizeof(DWORD));
|
||||||
|
if (error)
|
||||||
|
hr = E_FAIL;
|
||||||
|
|
||||||
|
::VariantClear(&vargTemp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case VT_UNKNOWN:
|
||||||
|
{
|
||||||
|
CComPtr<IStream> pStream;
|
||||||
|
hr = V_UNKNOWN(pvari)->QueryInterface(IID_IStream, (void **)&pStream);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
hr = _WriteStream(pszPropName, pStream);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
hr = ::VariantChangeType(&vargTemp, pvari, 0, VT_BSTR);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
int cch = lstrlenW(V_BSTR(&vargTemp));
|
||||||
|
DWORD cb = (cch + 1) * sizeof(WCHAR);
|
||||||
|
error = SHSetValueW(m_hKey, NULL, pszPropName, REG_SZ, V_BSTR(&vargTemp), cb);
|
||||||
|
if (error)
|
||||||
|
hr = E_FAIL;
|
||||||
|
|
||||||
|
::VariantClear(&vargTemp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* SHCreatePropertyBagOnRegKey (SHLWAPI.471)
|
||||||
|
*
|
||||||
|
* Creates a property bag object on registry key.
|
||||||
|
*
|
||||||
|
* @param hKey The registry key.
|
||||||
|
* @param pszSubKey The path of the sub-key.
|
||||||
|
* @param dwMode The combination of STGM_READ, STGM_WRITE, STGM_READWRITE, and STGM_CREATE.
|
||||||
|
* @param riid Specifies either IID_IUnknown, IID_IPropertyBag or IID_IPropertyBag2.
|
||||||
|
* @param ppvObj Receives an IPropertyBag pointer.
|
||||||
|
* @return An HRESULT value. S_OK on success, non-zero on failure.
|
||||||
|
* @see https://source.winehq.org/WineAPI/SHCreatePropertyBagOnRegKey.html
|
||||||
|
*/
|
||||||
|
EXTERN_C HRESULT WINAPI
|
||||||
|
SHCreatePropertyBagOnRegKey(
|
||||||
|
_In_ HKEY hKey,
|
||||||
|
_In_z_ LPCWSTR pszSubKey,
|
||||||
|
_In_ DWORD dwMode,
|
||||||
|
_In_ REFIID riid,
|
||||||
|
_Out_ void **ppvObj)
|
||||||
|
{
|
||||||
|
TRACE("%p, %s, 0x%08X, %s, %p\n", hKey, debugstr_w(pszSubKey), dwMode,
|
||||||
|
debugstr_guid(&riid), ppvObj);
|
||||||
|
|
||||||
|
*ppvObj = NULL;
|
||||||
|
|
||||||
|
CComPtr<CRegPropertyBag> pRegBag(new CRegPropertyBag(dwMode));
|
||||||
|
|
||||||
|
HRESULT hr = pRegBag->Init(hKey, pszSubKey);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
return pRegBag->QueryInterface(riid, ppvObj);
|
||||||
|
}
|
||||||
|
@ -468,7 +468,7 @@
|
|||||||
468 stub -noname RunIndirectRegCommand
|
468 stub -noname RunIndirectRegCommand
|
||||||
469 stub -noname RunRegCommand
|
469 stub -noname RunRegCommand
|
||||||
470 stub -noname IUnknown_ProfferServiceOld
|
470 stub -noname IUnknown_ProfferServiceOld
|
||||||
471 stdcall -noname SHCreatePropertyBagOnRegKey(long wstr long ptr ptr)
|
471 stdcall -noname SHCreatePropertyBagOnRegKey(ptr wstr long ptr ptr)
|
||||||
472 stub -noname SHCreatePropertyBagOnProfileSelection
|
472 stub -noname SHCreatePropertyBagOnProfileSelection
|
||||||
473 stub -noname SHGetIniStringUTF7W
|
473 stub -noname SHGetIniStringUTF7W
|
||||||
474 stub -noname SHSetIniStringUTF7W
|
474 stub -noname SHSetIniStringUTF7W
|
||||||
|
@ -96,7 +96,7 @@ public:
|
|||||||
if (lstrcmpiW(pszPropName, L"GUID1") == 0)
|
if (lstrcmpiW(pszPropName, L"GUID1") == 0)
|
||||||
{
|
{
|
||||||
V_VT(pvari) = (VT_UI1 | VT_ARRAY);
|
V_VT(pvari) = (VT_UI1 | VT_ARRAY);
|
||||||
V_ARRAY(pvari) = CreateByteArray(&IID_IShellLink, sizeof(IID));
|
V_ARRAY(pvari) = CreateByteArray(&IID_IShellLinkW, sizeof(IID));
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,7 +225,7 @@ static void SHPropertyBag_ReadTest(void)
|
|||||||
ok_long(hr, S_OK);
|
ok_long(hr, S_OK);
|
||||||
ok_int(s_cRead, 1);
|
ok_int(s_cRead, 1);
|
||||||
ok_int(s_cWrite, 0);
|
ok_int(s_cWrite, 0);
|
||||||
ok_int(IsEqualGUID(guid, IID_IShellLink), TRUE);
|
ok_int(IsEqualGUID(guid, IID_IShellLinkW), TRUE);
|
||||||
|
|
||||||
ResetTest(VT_EMPTY, L"GUID2");
|
ResetTest(VT_EMPTY, L"GUID2");
|
||||||
hr = SHPropertyBag_ReadGUID(&dummy, L"GUID2", &guid);
|
hr = SHPropertyBag_ReadGUID(&dummy, L"GUID2", &guid);
|
||||||
@ -456,9 +456,192 @@ static void SHPropertyBag_OnMemory(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void SHPropertyBag_OnRegKey(void)
|
||||||
|
{
|
||||||
|
HKEY hKey, hSubKey;
|
||||||
|
LONG error;
|
||||||
|
VARIANT vari;
|
||||||
|
WCHAR szText[MAX_PATH];
|
||||||
|
IStream *pStream;
|
||||||
|
GUID guid;
|
||||||
|
BYTE guid_and_extra[sizeof(GUID) + sizeof(GUID)];
|
||||||
|
|
||||||
|
// Create HKCU\Software\ReactOS registry key
|
||||||
|
error = RegCreateKeyW(HKEY_CURRENT_USER, L"Software\\ReactOS", &hKey);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
skip("FAILED to create HKCU\\Software\\ReactOS\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPropertyBag *pPropBag;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
// Try to create new registry key
|
||||||
|
RegDeleteKeyW(hKey, L"PropBagTest");
|
||||||
|
hr = SHCreatePropertyBagOnRegKey(hKey, L"PropBagTest", 0,
|
||||||
|
IID_IPropertyBag, (void **)&pPropBag);
|
||||||
|
ok_long(hr, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
|
||||||
|
|
||||||
|
// Try to create new registry key
|
||||||
|
RegDeleteKeyW(hKey, L"PropBagTest");
|
||||||
|
hr = SHCreatePropertyBagOnRegKey(hKey, L"PropBagTest", STGM_READWRITE,
|
||||||
|
IID_IPropertyBag, (void **)&pPropBag);
|
||||||
|
ok_long(hr, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
|
||||||
|
|
||||||
|
// Create new registry key
|
||||||
|
RegDeleteKeyW(hKey, L"PropBagTest");
|
||||||
|
hr = SHCreatePropertyBagOnRegKey(hKey, L"PropBagTest", STGM_CREATE | STGM_READWRITE,
|
||||||
|
IID_IPropertyBag, (void **)&pPropBag);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
skip("SHCreatePropertyBagOnRegKey FAILED\n");
|
||||||
|
RegCloseKey(hKey);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write UI4
|
||||||
|
VariantInit(&vari);
|
||||||
|
V_VT(&vari) = VT_UI4;
|
||||||
|
V_UI4(&vari) = 0xDEADFACE;
|
||||||
|
hr = pPropBag->Write(L"Name1", &vari);
|
||||||
|
ok_long(hr, S_OK);
|
||||||
|
VariantClear(&vari);
|
||||||
|
|
||||||
|
// Read UI4
|
||||||
|
VariantInit(&vari);
|
||||||
|
hr = pPropBag->Read(L"Name1", &vari, NULL);
|
||||||
|
ok_long(hr, S_OK);
|
||||||
|
ok_long(V_VT(&vari), VT_UI4);
|
||||||
|
ok_long(V_UI4(&vari), 0xDEADFACE);
|
||||||
|
VariantClear(&vari);
|
||||||
|
|
||||||
|
// Write BSTR
|
||||||
|
VariantInit(&vari);
|
||||||
|
V_VT(&vari) = VT_BSTR;
|
||||||
|
V_BSTR(&vari) = SysAllocString(L"StrValue");
|
||||||
|
hr = pPropBag->Write(L"Name2", &vari);
|
||||||
|
ok_long(hr, S_OK);
|
||||||
|
VariantClear(&vari);
|
||||||
|
|
||||||
|
// Read BSTR
|
||||||
|
VariantInit(&vari);
|
||||||
|
V_VT(&vari) = VT_BSTR;
|
||||||
|
hr = pPropBag->Read(L"Name2", &vari, NULL);
|
||||||
|
ok_long(hr, S_OK);
|
||||||
|
ok_long(V_VT(&vari), VT_BSTR);
|
||||||
|
ok_wstr(V_BSTR(&vari), L"StrValue");
|
||||||
|
VariantClear(&vari);
|
||||||
|
|
||||||
|
// Write GUID
|
||||||
|
VariantInit(&vari);
|
||||||
|
V_VT(&vari) = VT_UNKNOWN;
|
||||||
|
V_UNKNOWN(&vari) = SHCreateMemStream((BYTE*)&IID_IShellLinkW, sizeof(IID_IShellLinkW));
|
||||||
|
hr = pPropBag->Write(L"Name4", &vari);
|
||||||
|
ok_long(hr, S_OK);
|
||||||
|
VariantClear(&vari);
|
||||||
|
|
||||||
|
// Read GUID
|
||||||
|
VariantInit(&vari);
|
||||||
|
V_VT(&vari) = VT_EMPTY;
|
||||||
|
hr = pPropBag->Read(L"Name4", &vari, NULL);
|
||||||
|
if (IsWindowsVistaOrGreater())
|
||||||
|
{
|
||||||
|
ok_long(hr, S_OK);
|
||||||
|
ok_long(V_VT(&vari), VT_UNKNOWN);
|
||||||
|
pStream = (IStream*)V_UNKNOWN(&vari);
|
||||||
|
FillMemory(&guid, sizeof(guid), 0xEE);
|
||||||
|
hr = pStream->Read(&guid, sizeof(guid), NULL);
|
||||||
|
ok_long(hr, S_OK);
|
||||||
|
ok_int(::IsEqualGUID(guid, IID_IShellLinkW), TRUE);
|
||||||
|
}
|
||||||
|
else // XP/2k3 Read is buggy
|
||||||
|
{
|
||||||
|
ok_long(hr, E_FAIL);
|
||||||
|
ok_long(V_VT(&vari), VT_EMPTY);
|
||||||
|
}
|
||||||
|
VariantClear(&vari);
|
||||||
|
|
||||||
|
pPropBag->Release();
|
||||||
|
|
||||||
|
// Check registry
|
||||||
|
error = RegOpenKeyExW(hKey, L"PropBagTest", 0, KEY_READ, &hSubKey);
|
||||||
|
ok_long(error, ERROR_SUCCESS);
|
||||||
|
DWORD dwType, dwValue, cbValue = sizeof(dwValue);
|
||||||
|
error = RegQueryValueExW(hSubKey, L"Name1", NULL, &dwType, (BYTE*)&dwValue, &cbValue);
|
||||||
|
ok_long(error, ERROR_SUCCESS);
|
||||||
|
ok_long(dwType, REG_DWORD);
|
||||||
|
ok_long(dwValue, 0xDEADFACE);
|
||||||
|
ok_long(cbValue, sizeof(DWORD));
|
||||||
|
cbValue = sizeof(szText);
|
||||||
|
error = RegQueryValueExW(hSubKey, L"Name2", NULL, &dwType, (BYTE*)szText, &cbValue);
|
||||||
|
ok_long(error, ERROR_SUCCESS);
|
||||||
|
ok_long(dwType, REG_SZ);
|
||||||
|
ok_wstr(szText, L"StrValue");
|
||||||
|
cbValue = sizeof(guid_and_extra);
|
||||||
|
error = RegQueryValueExW(hSubKey, L"Name4", NULL, &dwType, (BYTE*)&guid_and_extra, &cbValue);
|
||||||
|
ok_long(error, ERROR_SUCCESS);
|
||||||
|
ok_long(dwType, REG_BINARY);
|
||||||
|
ok_int(memcmp(&guid_and_extra, &GUID_NULL, sizeof(GUID)), 0);
|
||||||
|
ok_int(memcmp(&guid_and_extra[sizeof(GUID)], &IID_IShellLinkW, sizeof(GUID)), 0);
|
||||||
|
RegCloseKey(hSubKey);
|
||||||
|
|
||||||
|
// Create as read-only
|
||||||
|
hr = SHCreatePropertyBagOnRegKey(hKey, L"PropBagTest", STGM_READ,
|
||||||
|
IID_IPropertyBag, (void **)&pPropBag);
|
||||||
|
ok_long(hr, S_OK);
|
||||||
|
|
||||||
|
// Read UI4
|
||||||
|
VariantInit(&vari);
|
||||||
|
hr = pPropBag->Read(L"Name1", &vari, NULL);
|
||||||
|
ok_long(hr, S_OK);
|
||||||
|
ok_long(V_VT(&vari), VT_UI4);
|
||||||
|
ok_long(V_UI4(&vari), 0xDEADFACE);
|
||||||
|
VariantClear(&vari);
|
||||||
|
|
||||||
|
// Write UI4
|
||||||
|
VariantInit(&vari);
|
||||||
|
V_VT(&vari) = VT_UI4;
|
||||||
|
V_UI4(&vari) = 0xDEADFACE;
|
||||||
|
hr = pPropBag->Write(L"Name1", &vari);
|
||||||
|
ok_long(hr, E_ACCESSDENIED);
|
||||||
|
VariantClear(&vari);
|
||||||
|
|
||||||
|
pPropBag->Release();
|
||||||
|
|
||||||
|
// Create as write-only IPropertyBag2
|
||||||
|
hr = SHCreatePropertyBagOnRegKey(hKey, L"PropBagTest", STGM_WRITE,
|
||||||
|
IID_IPropertyBag2, (void **)&pPropBag);
|
||||||
|
ok_long(hr, S_OK);
|
||||||
|
|
||||||
|
// Write UI4
|
||||||
|
VariantInit(&vari);
|
||||||
|
V_VT(&vari) = VT_UI4;
|
||||||
|
V_UI4(&vari) = 0xDEADFACE;
|
||||||
|
hr = pPropBag->Write(L"Name3", &vari);
|
||||||
|
ok_long(hr, E_NOTIMPL);
|
||||||
|
VariantClear(&vari);
|
||||||
|
|
||||||
|
// Read UI4
|
||||||
|
VariantInit(&vari);
|
||||||
|
V_UI4(&vari) = 0xFEEDF00D;
|
||||||
|
hr = pPropBag->Read(L"Name3", &vari, NULL);
|
||||||
|
ok_long(hr, E_NOTIMPL);
|
||||||
|
ok_int(V_VT(&vari), VT_EMPTY);
|
||||||
|
ok_long(V_UI4(&vari), 0xFEEDF00D);
|
||||||
|
VariantClear(&vari);
|
||||||
|
|
||||||
|
pPropBag->Release();
|
||||||
|
|
||||||
|
// Clean up
|
||||||
|
RegDeleteKeyW(hKey, L"PropBagTest");
|
||||||
|
RegCloseKey(hKey);
|
||||||
|
}
|
||||||
|
|
||||||
START_TEST(SHPropertyBag)
|
START_TEST(SHPropertyBag)
|
||||||
{
|
{
|
||||||
SHPropertyBag_ReadTest();
|
SHPropertyBag_ReadTest();
|
||||||
SHPropertyBag_WriteTest();
|
SHPropertyBag_WriteTest();
|
||||||
SHPropertyBag_OnMemory();
|
SHPropertyBag_OnMemory();
|
||||||
|
SHPropertyBag_OnRegKey();
|
||||||
}
|
}
|
||||||
|
@ -91,6 +91,7 @@ BOOL WINAPI SHExpandEnvironmentStringsForUserW(HANDLE, LPCWSTR, LPWSTR, DWORD);
|
|||||||
|
|
||||||
|
|
||||||
BOOL WINAPI SHIsEmptyStream(IStream*);
|
BOOL WINAPI SHIsEmptyStream(IStream*);
|
||||||
|
HRESULT WINAPI IStream_Size(IStream *lpStream, ULARGE_INTEGER* lpulSize);
|
||||||
HRESULT WINAPI SHInvokeDefaultCommand(HWND,IShellFolder*,LPCITEMIDLIST);
|
HRESULT WINAPI SHInvokeDefaultCommand(HWND,IShellFolder*,LPCITEMIDLIST);
|
||||||
HRESULT WINAPI SHPropertyBag_ReadType(IPropertyBag *ppb, LPCWSTR pszPropName, VARIANTARG *pvarg, VARTYPE vt);
|
HRESULT WINAPI SHPropertyBag_ReadType(IPropertyBag *ppb, LPCWSTR pszPropName, VARIANTARG *pvarg, VARTYPE vt);
|
||||||
HRESULT WINAPI SHPropertyBag_ReadBOOL(IPropertyBag *ppb, LPCWSTR pszPropName, BOOL *pbValue);
|
HRESULT WINAPI SHPropertyBag_ReadBOOL(IPropertyBag *ppb, LPCWSTR pszPropName, BOOL *pbValue);
|
||||||
@ -126,6 +127,14 @@ HRESULT WINAPI SHPropertyBag_WriteRECTL(IPropertyBag *ppb, LPCWSTR pszPropName,
|
|||||||
|
|
||||||
HRESULT WINAPI SHCreatePropertyBagOnMemory(_In_ DWORD dwMode, _In_ REFIID riid, _Out_ void **ppvObj);
|
HRESULT WINAPI SHCreatePropertyBagOnMemory(_In_ DWORD dwMode, _In_ REFIID riid, _Out_ void **ppvObj);
|
||||||
|
|
||||||
|
HRESULT WINAPI
|
||||||
|
SHCreatePropertyBagOnRegKey(
|
||||||
|
_In_ HKEY hKey,
|
||||||
|
_In_z_ LPCWSTR pszSubKey,
|
||||||
|
_In_ DWORD dwMode,
|
||||||
|
_In_ REFIID riid,
|
||||||
|
_Out_ void **ppvObj);
|
||||||
|
|
||||||
HWND WINAPI SHCreateWorkerWindowA(WNDPROC wndProc, HWND hWndParent, DWORD dwExStyle,
|
HWND WINAPI SHCreateWorkerWindowA(WNDPROC wndProc, HWND hWndParent, DWORD dwExStyle,
|
||||||
DWORD dwStyle, HMENU hMenu, LONG_PTR wnd_extra);
|
DWORD dwStyle, HMENU hMenu, LONG_PTR wnd_extra);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user