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

commit b4bc6f0a6a1ea3d6e9aed68c28b2b4787dd21fd9
Author:     Katayama Hirofumi MZ <katayama.hirofumi...@gmail.com>
AuthorDate: Sat Aug 5 21:20:58 2023 +0900
Commit:     GitHub <nore...@github.com>
CommitDate: Sat Aug 5 21:20:58 2023 +0900

    [SHLWAPI][SHLWAPI_APITEST][SDK] SHCreatePropertyBagOnMemory (#5511)
    
    - Add propbag.cpp.
    - Add CBasePropertyBag / CMemPropertyBag classes.
    - Implement SHCreatePropertyBagOnMemory.
    - Strengthen SHPropertyBag testcase in shlwapi_apitest.
    CORE-9283
---
 dll/win32/shlwapi/CMakeLists.txt                   |   5 +-
 dll/win32/shlwapi/precomp.h                        |   4 +
 dll/win32/shlwapi/propbag.cpp                      | 253 +++++++++++++++++++++
 dll/win32/shlwapi/shlwapi.spec                     |   2 +-
 .../rostests/apitests/shlwapi/SHPropertyBag.cpp    | 132 +++++++++++
 sdk/include/reactos/shlwapi_undoc.h                |   2 +
 6 files changed, 396 insertions(+), 2 deletions(-)

diff --git a/dll/win32/shlwapi/CMakeLists.txt b/dll/win32/shlwapi/CMakeLists.txt
index fcb03a15c37..87551cd21c5 100644
--- a/dll/win32/shlwapi/CMakeLists.txt
+++ b/dll/win32/shlwapi/CMakeLists.txt
@@ -24,6 +24,7 @@ list(APPEND SOURCE
 
 list(APPEND PCH_SKIP_SOURCE
     assoc.c
+    propbag.cpp
     wsprintf.c
     ${CMAKE_CURRENT_BINARY_DIR}/shlwapi_stubs.c)
 
@@ -36,7 +37,9 @@ add_library(shlwapi MODULE
 
 # our C++ atlbase.h conflicts with the one from wine, so only use wine 
includes for C
 # Unfortunately, we can't use different includes for C & C++ in VS generator, 
so use an object library to achieve this
-target_include_directories(shlwapi BEFORE PRIVATE 
${REACTOS_SOURCE_DIR}/sdk/include/reactos/wine)
+target_include_directories(shlwapi BEFORE PRIVATE
+    ${REACTOS_SOURCE_DIR}/sdk/include/reactos/wine
+    ${REACTOS_SOURCE_DIR}/sdk/lib/atl)
 
 add_library(shlwapi_autocomp OBJECT autocomp.cpp)
 target_link_libraries(shlwapi_autocomp PRIVATE atl_classes)
diff --git a/dll/win32/shlwapi/precomp.h b/dll/win32/shlwapi/precomp.h
index eff450aa861..86f3ea401fd 100644
--- a/dll/win32/shlwapi/precomp.h
+++ b/dll/win32/shlwapi/precomp.h
@@ -28,6 +28,10 @@
 #include <wine/debug.h>
 #include <wine/unicode.h>
 
+#ifdef __REACTOS__
+EXTERN_C HRESULT VariantChangeTypeForRead(_Inout_ VARIANTARG *pvarg, _In_ 
VARTYPE vt);
+#endif
+
 #include "resource.h"
 
 #endif /* !_SHLWAPI_PCH_ */
diff --git a/dll/win32/shlwapi/propbag.cpp b/dll/win32/shlwapi/propbag.cpp
new file mode 100644
index 00000000000..27434091fc3
--- /dev/null
+++ b/dll/win32/shlwapi/propbag.cpp
@@ -0,0 +1,253 @@
+/*
+ * PROJECT:     ReactOS Shell
+ * LICENSE:     LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later)
+ * PURPOSE:     Implement shell property bags
+ * COPYRIGHT:   Copyright 2023 Katayama Hirofumi MZ 
<katayama.hirofumi...@gmail.com>
+ */
+
+#define _ATL_NO_EXCEPTIONS
+#include "precomp.h"
+#include <shlwapi.h>
+#include <shlwapi_undoc.h>
+#include <atlstr.h>         // for CStringW
+#include <atlsimpcoll.h>    // for CSimpleMap
+#include <atlcomcli.h>      // for CComVariant
+
+WINE_DEFAULT_DEBUG_CHANNEL(shell);
+
+class CBasePropertyBag
+    : public IPropertyBag
+#if (_WIN32_WINNT < _WIN32_WINNT_VISTA)
+    , public IPropertyBag2
+#endif
+{
+protected:
+    LONG m_cRefs;   // reference count
+    DWORD m_dwMode; // STGM_* flags
+
+public:
+    CBasePropertyBag(DWORD dwMode)
+        : m_cRefs(0)
+        , m_dwMode(dwMode)
+    {
+    }
+
+    virtual ~CBasePropertyBag() { }
+
+    // IUnknown interface
+    STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject) override
+    {
+#if (_WIN32_WINNT < _WIN32_WINNT_VISTA)
+        if (::IsEqualGUID(riid, IID_IPropertyBag2))
+        {
+            AddRef();
+            *ppvObject = static_cast<IPropertyBag2*>(this);
+            return S_OK;
+        }
+#endif
+        if (::IsEqualGUID(riid, IID_IUnknown) || ::IsEqualGUID(riid, 
IID_IPropertyBag))
+        {
+            AddRef();
+            *ppvObject = static_cast<IPropertyBag*>(this);
+            return S_OK;
+        }
+        return E_NOTIMPL;
+    }
+    STDMETHODIMP_(ULONG) AddRef() override
+    {
+        return ::InterlockedIncrement(&m_cRefs);
+    }
+    STDMETHODIMP_(ULONG) Release() override
+    {
+        if (::InterlockedDecrement(&m_cRefs) == 0)
+        {
+            delete this;
+            return 0;
+        }
+        return m_cRefs;
+    }
+
+#if (_WIN32_WINNT < _WIN32_WINNT_VISTA)
+    // IPropertyBag2 interface (stubs)
+    STDMETHODIMP Read(
+        _In_ ULONG cProperties,
+        _In_ PROPBAG2 *pPropBag,
+        _In_opt_ IErrorLog *pErrorLog,
+        _Out_ VARIANT *pvarValue,
+        _Out_ HRESULT *phrError) override
+    {
+        return E_NOTIMPL;
+    }
+    STDMETHODIMP Write(
+        _In_ ULONG cProperties,
+        _In_ PROPBAG2 *pPropBag,
+        _In_ VARIANT *pvarValue)
+    {
+        return E_NOTIMPL;
+    }
+    STDMETHODIMP CountProperties(_Out_ ULONG *pcProperties) override
+    {
+        return E_NOTIMPL;
+    }
+    STDMETHODIMP GetPropertyInfo(
+        _In_ ULONG iProperty,
+        _In_ ULONG cProperties,
+        _Out_ PROPBAG2 *pPropBag,
+        _Out_ ULONG *pcProperties) override
+    {
+        return E_NOTIMPL;
+    }
+    STDMETHODIMP LoadObject(
+        _In_z_ LPCWSTR pstrName,
+        _In_ DWORD dwHint,
+        _In_ IUnknown *pUnkObject,
+        _In_opt_ IErrorLog *pErrorLog) override
+    {
+        return E_NOTIMPL;
+    }
+#endif
+};
+
+struct CPropMapEqual
+{
+    static bool IsEqualKey(const ATL::CStringW& k1, const ATL::CStringW& k2)
+    {
+        return k1.CompareNoCase(k2) == 0;
+    }
+
+    static bool IsEqualValue(const ATL::CComVariant& v1, const 
ATL::CComVariant& v2)
+    {
+        return false;
+    }
+};
+
+class CMemPropertyBag : public CBasePropertyBag
+{
+protected:
+    ATL::CSimpleMap<ATL::CStringW, ATL::CComVariant, CPropMapEqual> m_PropMap;
+
+public:
+    CMemPropertyBag(DWORD dwFlags) : CBasePropertyBag(dwFlags) { }
+
+    STDMETHODIMP Read(_In_z_ LPCWSTR pszPropName, _Inout_ VARIANT *pvari,
+                      _Inout_opt_ IErrorLog *pErrorLog) override;
+    STDMETHODIMP Write(_In_z_ LPCWSTR pszPropName, _In_ VARIANT *pvari) 
override;
+};
+
+STDMETHODIMP
+CMemPropertyBag::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);
+
+    VARTYPE vt = V_VT(pvari);
+
+    ::VariantInit(pvari);
+
+#if (_WIN32_WINNT < _WIN32_WINNT_VISTA)
+    if ((m_dwMode & (STGM_READ | STGM_WRITE | STGM_READWRITE)) == STGM_WRITE)
+    {
+        ERR("%p: 0x%X\n", this, m_dwMode);
+        return E_ACCESSDENIED;
+    }
+#endif
+
+    if (!pszPropName || !pvari)
+    {
+        ERR("%p: %s %p %p\n", this, debugstr_w(pszPropName), pvari, pErrorLog);
+        return E_INVALIDARG;
+    }
+
+    INT iItem = m_PropMap.FindKey(pszPropName);
+    if (iItem == -1)
+    {
+        ERR("%p: %s %p %p\n", this, debugstr_w(pszPropName), pvari, pErrorLog);
+        return E_FAIL;
+    }
+
+    HRESULT hr = ::VariantCopy(pvari, &m_PropMap.GetValueAt(iItem));
+    if (FAILED(hr))
+    {
+        ERR("%p: 0x%08X %p\n", this, hr, pvari);
+        return hr;
+    }
+
+    hr = ::VariantChangeTypeForRead(pvari, vt);
+    if (FAILED(hr))
+    {
+        ERR("%p: 0x%08X %p\n", this, hr, pvari);
+        return hr;
+    }
+
+    return hr;
+}
+
+STDMETHODIMP
+CMemPropertyBag::Write(
+    _In_z_ LPCWSTR pszPropName,
+    _In_ VARIANT *pvari)
+{
+    TRACE("%p: %s %p\n", this, debugstr_w(pszPropName), pvari);
+
+#if (_WIN32_WINNT < _WIN32_WINNT_VISTA)
+    if ((m_dwMode & (STGM_READ | STGM_WRITE | STGM_READWRITE)) == STGM_READ)
+    {
+        ERR("%p: 0x%X\n", this, m_dwMode);
+        return E_ACCESSDENIED;
+    }
+#endif
+
+    if (!pszPropName || !pvari)
+    {
+        ERR("%p: %s %p\n", this, debugstr_w(pszPropName), pvari);
+        return E_INVALIDARG;
+    }
+
+    ATL::CComVariant vari;
+    HRESULT hr = vari.Copy(pvari);
+    if (FAILED(hr))
+    {
+        ERR("%p: %s %p: 0x%08X\n", this, debugstr_w(pszPropName), pvari, hr);
+        return hr;
+    }
+
+    if (!m_PropMap.SetAt(pszPropName, vari))
+    {
+        ERR("%p: %s %p\n", this, debugstr_w(pszPropName), pvari);
+        return E_FAIL;
+    }
+
+    return hr;
+}
+
+/**************************************************************************
+ *  SHCreatePropertyBagOnMemory (SHLWAPI.477)
+ *
+ * Creates a property bag object on memory.
+ *
+ * @param dwMode  Specifies either STGM_READ, STGM_WRITE or STGM_READWRITE. 
Ignored on Vista+.
+ * @param riid    Specifies either IID_IUnknown, IID_IPropertyBag or 
IID_IPropertyBag2.
+ *                Vista+ rejects IID_IPropertyBag2.
+ * @param ppvObj  Receives an IPropertyBag pointer.
+ * @return        An HRESULT value. S_OK on success, non-zero on failure.
+ * @see           
http://undoc.airesoft.co.uk/shlwapi.dll/SHCreatePropertyBagOnMemory.php
+ */
+EXTERN_C HRESULT WINAPI
+SHCreatePropertyBagOnMemory(_In_ DWORD dwMode, _In_ REFIID riid, _Out_ void 
**ppvObj)
+{
+    TRACE("0x%08X, %s, %p\n", dwMode, debugstr_guid(&riid), ppvObj);
+
+    *ppvObj = NULL;
+
+    CComPtr<CMemPropertyBag> pMemBag(new CMemPropertyBag(dwMode));
+
+    HRESULT hr = pMemBag->QueryInterface(riid, ppvObj);
+    if (FAILED(hr))
+        ERR("0x%08X %s\n", hr, debugstr_guid(&riid));
+
+    return hr;
+}
diff --git a/dll/win32/shlwapi/shlwapi.spec b/dll/win32/shlwapi/shlwapi.spec
index 8dc01d454dc..0844af03d5d 100644
--- a/dll/win32/shlwapi/shlwapi.spec
+++ b/dll/win32/shlwapi/shlwapi.spec
@@ -474,7 +474,7 @@
 474 stub -noname SHSetIniStringUTF7W
 475 stdcall -noname GetShellSecurityDescriptor(ptr long)
 476 stdcall -noname SHGetObjectCompatFlags(ptr ptr)
-477 stub -noname SHCreatePropertyBagOnMemory
+477 stdcall -noname SHCreatePropertyBagOnMemory(long ptr ptr)
 478 stdcall -noname IUnknown_TranslateAcceleratorIO(ptr ptr)
 479 stdcall -noname IUnknown_UIActivateIO(ptr long ptr)
 480 stdcall -noname UrlCrackW(wstr long long ptr) wininet.InternetCrackUrlW
diff --git a/modules/rostests/apitests/shlwapi/SHPropertyBag.cpp 
b/modules/rostests/apitests/shlwapi/SHPropertyBag.cpp
index 1aca2d256c0..2114ceff231 100644
--- a/modules/rostests/apitests/shlwapi/SHPropertyBag.cpp
+++ b/modules/rostests/apitests/shlwapi/SHPropertyBag.cpp
@@ -325,8 +325,140 @@ static void SHPropertyBag_WriteTest(void)
     ok_int(s_cWrite, 1);
 }
 
+static void SHPropertyBag_OnMemory(void)
+{
+    HRESULT hr;
+    VARIANT vari;
+
+    IPropertyBag *pPropBag = NULL;
+    hr = SHCreatePropertyBagOnMemory(STGM_READWRITE, IID_IPropertyBag, 
(void**)&pPropBag);
+    ok_long(hr, S_OK);
+    if (pPropBag == NULL)
+    {
+        skip("pPropBag was NULL\n");
+        return;
+    }
+
+    VariantInit(&vari);
+    hr = pPropBag->Read(L"InvalidName", &vari, NULL);
+    ok_long(hr, E_FAIL);
+    VariantClear(&vari);
+
+    VariantInit(&vari);
+    V_VT(&vari) = VT_UI4;
+    V_UI4(&vari) = 0xDEADFACE;
+    hr = pPropBag->Write(L"Name1", &vari);
+    ok_long(hr, S_OK);
+    VariantClear(&vari);
+
+    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);
+
+    pPropBag->Release();
+    pPropBag = NULL;
+
+    hr = SHCreatePropertyBagOnMemory(STGM_READ, IID_IPropertyBag, 
(void**)&pPropBag);
+    ok_long(hr, S_OK);
+
+    VariantInit(&vari);
+    V_VT(&vari) = VT_UI4;
+    V_UI4(&vari) = 0xDEADFACE;
+    hr = pPropBag->Write(L"Name1", &vari);
+    ok_long(hr, (IsWindowsVistaOrGreater() ? S_OK : E_ACCESSDENIED));
+    VariantClear(&vari);
+
+    VariantInit(&vari);
+    V_VT(&vari) = VT_UI4;
+    V_UI4(&vari) = 0xFEEDF00D;
+    hr = pPropBag->Read(L"Name1", &vari, NULL);
+    if (IsWindowsVistaOrGreater())
+    {
+        ok_long(hr, S_OK);
+        ok_int(V_VT(&vari), VT_UI4);
+        ok_long(V_UI4(&vari), 0xDEADFACE);
+    }
+    else
+    {
+        ok_long(hr, E_FAIL);
+        ok_int(V_VT(&vari), VT_EMPTY);
+        ok_long(V_UI4(&vari), 0xFEEDF00D);
+    }
+    VariantClear(&vari);
+
+    pPropBag->Release();
+    pPropBag = NULL;
+
+    hr = SHCreatePropertyBagOnMemory(STGM_WRITE, IID_IPropertyBag, 
(void**)&pPropBag);
+    ok_long(hr, S_OK);
+
+    VariantInit(&vari);
+    V_VT(&vari) = VT_UI4;
+    V_UI4(&vari) = 0xDEADFACE;
+    hr = pPropBag->Write(L"Name1", &vari);
+    ok_long(hr, S_OK);
+    VariantClear(&vari);
+
+    VariantInit(&vari);
+    V_VT(&vari) = VT_UI4;
+    V_UI4(&vari) = 0xFEEDF00D;
+    hr = pPropBag->Read(L"Name1", &vari, NULL);
+    if (IsWindowsVistaOrGreater())
+    {
+        ok_long(hr, S_OK);
+        ok_int(V_VT(&vari), VT_UI4);
+        ok_long(V_UI4(&vari), 0xDEADFACE);
+    }
+    else
+    {
+        ok_long(hr, E_ACCESSDENIED);
+        ok_int(V_VT(&vari), VT_EMPTY);
+        ok_long(V_UI4(&vari), 0xFEEDF00D);
+    }
+    VariantClear(&vari);
+
+    pPropBag->Release();
+
+    hr = SHCreatePropertyBagOnMemory(STGM_READWRITE, IID_IPropertyBag2, 
(void**)&pPropBag);
+    if (IsWindowsVistaOrGreater())
+    {
+        ok_long(hr, E_NOINTERFACE);
+    }
+    else
+    {
+        ok_long(hr, S_OK);
+        pPropBag->Release();
+    }
+
+    hr = SHCreatePropertyBagOnMemory(STGM_READ, IID_IPropertyBag2, 
(void**)&pPropBag);
+    if (IsWindowsVistaOrGreater())
+    {
+        ok_long(hr, E_NOINTERFACE);
+    }
+    else
+    {
+        ok_long(hr, S_OK);
+        pPropBag->Release();
+    }
+
+    hr = SHCreatePropertyBagOnMemory(STGM_WRITE, IID_IPropertyBag2, 
(void**)&pPropBag);
+    if (IsWindowsVistaOrGreater())
+    {
+        ok_long(hr, E_NOINTERFACE);
+    }
+    else
+    {
+        ok_long(hr, S_OK);
+        pPropBag->Release();
+    }
+}
+
 START_TEST(SHPropertyBag)
 {
     SHPropertyBag_ReadTest();
     SHPropertyBag_WriteTest();
+    SHPropertyBag_OnMemory();
 }
diff --git a/sdk/include/reactos/shlwapi_undoc.h 
b/sdk/include/reactos/shlwapi_undoc.h
index a50900a731e..9ed45b2c8d5 100644
--- a/sdk/include/reactos/shlwapi_undoc.h
+++ b/sdk/include/reactos/shlwapi_undoc.h
@@ -124,6 +124,8 @@ HRESULT WINAPI SHPropertyBag_WritePOINTL(IPropertyBag *ppb, 
LPCWSTR pszPropName,
 HRESULT WINAPI SHPropertyBag_WritePOINTS(IPropertyBag *ppb, LPCWSTR 
pszPropName, const POINTS *ppts);
 HRESULT WINAPI SHPropertyBag_WriteRECTL(IPropertyBag *ppb, LPCWSTR 
pszPropName, const RECTL *prcl);
 
+HRESULT WINAPI SHCreatePropertyBagOnMemory(_In_ DWORD dwMode, _In_ REFIID 
riid, _Out_ void **ppvObj);
+
 HWND WINAPI SHCreateWorkerWindowA(WNDPROC wndProc, HWND hWndParent, DWORD 
dwExStyle,
                                   DWORD dwStyle, HMENU hMenu, LONG_PTR 
wnd_extra);
 

Reply via email to