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

commit 8dbb800358c5714e88848b80d76910a32b90c8d7
Author:     Katayama Hirofumi MZ <katayama.hirofumi...@gmail.com>
AuthorDate: Sun Sep 3 09:42:10 2023 +0900
Commit:     GitHub <nore...@github.com>
CommitDate: Sun Sep 3 09:42:10 2023 +0900

    [SHDOCVW][SDK] Implement MRU List for Shell Bag, Part 2 (#5634)
    
    Follow-up to #5626.
    - Implement CMruBase class.
    - Add delay import of shell32.
    - Add RegCreateKeyExWrapW prototype to <shlobj_undoc.h>.
    CORE-9283
---
 dll/win32/shdocvw/CMakeLists.txt    |   2 +-
 dll/win32/shdocvw/mrulist.cpp       | 289 +++++++++++++++++++++++++++++++-----
 sdk/include/reactos/shlobj_undoc.h  |   6 +-
 sdk/include/reactos/shlwapi_undoc.h |  13 ++
 4 files changed, 268 insertions(+), 42 deletions(-)

diff --git a/dll/win32/shdocvw/CMakeLists.txt b/dll/win32/shdocvw/CMakeLists.txt
index 307fee5ad6e..5d25b402784 100644
--- a/dll/win32/shdocvw/CMakeLists.txt
+++ b/dll/win32/shdocvw/CMakeLists.txt
@@ -23,7 +23,7 @@ add_library(shdocvw MODULE
 
 set_module_type(shdocvw win32dll)
 target_link_libraries(shdocvw uuid wine)
-add_delay_importlibs(shdocvw ole32 oleaut32 ieframe)
+add_delay_importlibs(shdocvw shell32 ole32 oleaut32 ieframe)
 add_importlibs(shdocvw shlwapi advapi32 msvcrt kernel32 ntdll)
 add_dependencies(shdocvw stdole2)
 add_pch(shdocvw precomp.h SOURCE)
diff --git a/dll/win32/shdocvw/mrulist.cpp b/dll/win32/shdocvw/mrulist.cpp
index 564c3d9e9be..b140779cb9c 100644
--- a/dll/win32/shdocvw/mrulist.cpp
+++ b/dll/win32/shdocvw/mrulist.cpp
@@ -16,6 +16,7 @@
 #include <shlobj_undoc.h>
 #include <shlguid_undoc.h>
 #include <shlwapi.h>
+#include <shlwapi_undoc.h>
 #include "shdocvw.h"
 
 #include <wine/debug.h>
@@ -27,20 +28,49 @@ extern "C" void __cxa_pure_virtual(void)
     ::DebugBreak();
 }
 
+BOOL IEILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2, BOOL bUnknown)
+{
+    UINT cb1 = ILGetSize(pidl1), cb2 = ILGetSize(pidl2);
+    if (cb1 == cb2 && memcmp(pidl1, pidl2, cb1) == 0)
+        return TRUE;
+
+    FIXME("%p, %p\n", pidl1, pidl2);
+    return FALSE;
+}
+
+// The flags for SLOTITEMDATA.dwFlags
+#define SLOT_LOADED         0x1
+#define SLOT_UNKNOWN_FLAG   0x2
+
+// The flags for CMruBase.m_dwFlags
+#define COMPARE_BY_MEMCMP       0x0
+#define COMPARE_BY_STRCMPIW     0x1
+#define COMPARE_BY_STRCMPW      0x2
+#define COMPARE_BY_IEILISEQUAL  0x3
+#define COMPARE_BY_MASK         0xF
+
 class CMruBase
     : public IMruDataList
 {
 protected:
     LONG            m_cRefs         = 1;        // Reference count
-    DWORD           m_dwFlags       = 0;        // The flags
+    DWORD           m_dwFlags       = 0;        // The COMPARE_BY_... flags
     BOOL            m_bFlag1        = FALSE;    // ???
-    BOOL            m_bChecked      = FALSE;    // ???
+    BOOL            m_bChecked      = FALSE;    // The checked flag
     HKEY            m_hKey          = NULL;     // A registry key
     DWORD           m_cSlotRooms    = 0;        // Rooms for slots
     DWORD           m_cSlots        = 0;        // The # of slots
     SLOTCOMPARE     m_fnCompare     = NULL;     // The comparison function
     SLOTITEMDATA *  m_pSlots        = NULL;     // Slot data
 
+    HRESULT _LoadItem(UINT iSlot);
+    HRESULT _AddItem(UINT iSlot, const BYTE *pbData, DWORD cbData);
+    HRESULT _GetItem(UINT iSlot, SLOTITEMDATA **ppItem);
+    void _DeleteItem(UINT iSlot);
+
+    HRESULT _GetSlotItem(UINT iSlot, SLOTITEMDATA **ppItem);
+    void _CheckUsedSlots();
+
 public:
     CMruBase()
     {
@@ -53,19 +83,12 @@ public:
     {
         return ::InterlockedIncrement(&m_cRefs);
     }
-    STDMETHODIMP_(ULONG) Release() override
-    {
-        if (::InterlockedDecrement(&m_cRefs) == 0)
-        {
-            delete this;
-            return 0;
-        }
-        return m_cRefs;
-    }
+    STDMETHODIMP_(ULONG) Release() override;
 
     // IMruDataList methods
-    STDMETHODIMP InitData(UINT cCapacity, UINT flags, HKEY hKey, LPCWSTR 
pszSubKey,
-                          SLOTCOMPARE fnCompare) override;
+    STDMETHODIMP InitData(UINT cCapacity, UINT flags, HKEY hKey,
+                          LPCWSTR pszSubKey OPTIONAL,
+                          SLOTCOMPARE fnCompare OPTIONAL) override;
     STDMETHODIMP AddData(const BYTE *pbData, DWORD cbData, UINT *piSlot) 
override;
     STDMETHODIMP FindData(const BYTE *pbData, DWORD cbData, UINT *piSlot) 
override;
     STDMETHODIMP GetData(UINT iSlot, BYTE *pbData, DWORD cbData) override;
@@ -73,7 +96,7 @@ public:
     STDMETHODIMP Delete(UINT iSlot) override;
 
     // Non-standard methods
-    virtual HRESULT _IsEqual(const SLOTITEMDATA *pSlot, LPCITEMIDLIST pidl, 
UINT cbPidl) const;
+    virtual BOOL _IsEqual(const SLOTITEMDATA *pItem, LPCVOID pvData, UINT 
cbData) const;
     virtual HRESULT _DeleteValue(LPCWSTR pszValue);
     virtual HRESULT _InitSlots() = 0;
     virtual void _SaveSlots() = 0;
@@ -104,11 +127,7 @@ CMruBase::~CMruBase()
     {
         for (UINT iSlot = 0; iSlot < m_cSlots; ++iSlot)
         {
-            if (m_pSlots[iSlot].pidl)
-            {
-                ::LocalFree(m_pSlots[iSlot].pidl);
-                m_pSlots[iSlot].pidl = NULL;
-            }
+            m_pSlots[iSlot].pvData = ::LocalFree(m_pSlots[iSlot].pvData);
         }
 
         ::LocalFree(m_pSlots);
@@ -130,58 +149,252 @@ STDMETHODIMP CMruBase::QueryInterface(REFIID riid, void 
**ppvObj)
     return E_NOINTERFACE;
 }
 
+STDMETHODIMP_(ULONG) CMruBase::Release()
+{
+    if (::InterlockedDecrement(&m_cRefs) == 0)
+    {
+        _SaveSlots();
+        delete this;
+        return 0;
+    }
+    return m_cRefs;
+}
+
+HRESULT CMruBase::_LoadItem(UINT iSlot)
+{
+    DWORD cbData;
+    WCHAR szValue[12];
+
+    SLOTITEMDATA *pItem = &m_pSlots[iSlot];
+    _SlotString(iSlot, szValue, _countof(szValue));
+
+    if (SHGetValueW(m_hKey, NULL, szValue, NULL, NULL, &cbData) == 
ERROR_SUCCESS &&
+        cbData > 0)
+    {
+        pItem->pvData = ::LocalAlloc(LPTR, cbData);
+        if (pItem->pvData)
+        {
+            pItem->cbData = cbData;
+            if (SHGetValueW(m_hKey, NULL, szValue, NULL, pItem->pvData, 
&cbData) != ERROR_SUCCESS)
+                pItem->pvData = ::LocalFree(pItem->pvData);
+        }
+    }
+
+    pItem->dwFlags |= SLOT_LOADED;
+    if (!pItem->pvData)
+        return E_FAIL;
+
+    return S_OK;
+}
+
+HRESULT CMruBase::_GetSlotItem(UINT iSlot, SLOTITEMDATA **ppItem)
+{
+    if (!(m_pSlots[iSlot].dwFlags & SLOT_LOADED))
+        _LoadItem(iSlot);
+
+    SLOTITEMDATA *pItem = &m_pSlots[iSlot];
+    if (!pItem->pvData)
+        return E_OUTOFMEMORY;
+
+    *ppItem = pItem;
+    return S_OK;
+}
+
+HRESULT CMruBase::_GetItem(UINT iSlot, SLOTITEMDATA **ppItem)
+{
+    HRESULT hr = _GetSlot(iSlot, &iSlot);
+    if (FAILED(hr))
+        return hr;
+    return _GetSlotItem(iSlot, ppItem);
+}
+
+void CMruBase::_DeleteItem(UINT iSlot)
+{
+    WCHAR szBuff[12];
+
+    _SlotString(iSlot, szBuff, _countof(szBuff));
+    _DeleteValue(szBuff);
+
+    m_pSlots[iSlot].pvData = ::LocalFree(m_pSlots[iSlot].pvData);
+}
+
+void CMruBase::_CheckUsedSlots()
+{
+    UINT iGotSlot;
+    for (UINT iSlot = 0; iSlot < m_cSlots; ++iSlot)
+        _GetSlot(iSlot, &iGotSlot);
+
+    m_bChecked = TRUE;
+}
+
+HRESULT CMruBase::_AddItem(UINT iSlot, const BYTE *pbData, DWORD cbData)
+{
+    SLOTITEMDATA *pItem = &m_pSlots[iSlot];
+
+    WCHAR szBuff[12];
+    _SlotString(iSlot, szBuff, _countof(szBuff));
+
+    if (SHSetValueW(m_hKey, NULL, szBuff, REG_BINARY, pbData, cbData) != 
ERROR_SUCCESS)
+        return E_OUTOFMEMORY;
+
+    if (cbData >= pItem->cbData || !pItem->pvData)
+    {
+        ::LocalFree(pItem->pvData);
+        pItem->pvData = ::LocalAlloc(LPTR, cbData);
+    }
+
+    if (!pItem->pvData)
+        return E_FAIL;
+
+    pItem->cbData = cbData;
+    pItem->dwFlags = (SLOT_LOADED | SLOT_UNKNOWN_FLAG);
+    CopyMemory(pItem->pvData, pbData, cbData);
+    return S_OK;
+}
+
 STDMETHODIMP
 CMruBase::InitData(
     UINT cCapacity,
     UINT flags,
     HKEY hKey,
-    LPCWSTR pszSubKey,
-    SLOTCOMPARE fnCompare)
+    LPCWSTR pszSubKey OPTIONAL,
+    SLOTCOMPARE fnCompare OPTIONAL)
 {
-    FIXME("Stub\n");
-    return E_NOTIMPL;
+    m_dwFlags = flags;
+    m_fnCompare = fnCompare;
+    m_cSlotRooms = cCapacity;
+
+    if (pszSubKey)
+        ::RegCreateKeyExWrapW(hKey, pszSubKey, 0, NULL, 0, MAXIMUM_ALLOWED, 
NULL, &m_hKey, NULL);
+    else
+        m_hKey = SHRegDuplicateHKey(hKey);
+
+    if (!m_hKey)
+        return E_FAIL;
+
+    m_pSlots = (SLOTITEMDATA*)::LocalAlloc(LPTR, m_cSlotRooms * 
sizeof(SLOTITEMDATA));
+    if (!m_pSlots)
+        return E_OUTOFMEMORY;
+
+    return _InitSlots();
 }
 
 STDMETHODIMP CMruBase::AddData(const BYTE *pbData, DWORD cbData, UINT *piSlot)
 {
-    FIXME("Stub\n");
-    return E_NOTIMPL;
+    UINT iSlot;
+    HRESULT hr = FindData(pbData, cbData, &iSlot);
+    if (FAILED(hr))
+    {
+        iSlot = _UpdateSlots(m_cSlots);
+        hr = _AddItem(iSlot, pbData, cbData);
+        if (FAILED(hr))
+            return hr;
+    }
+    else
+    {
+        iSlot = _UpdateSlots(iSlot);
+        hr = S_OK;
+    }
+
+    if (piSlot)
+        *piSlot = iSlot;
+
+    return hr;
 }
 
 STDMETHODIMP CMruBase::FindData(const BYTE *pbData, DWORD cbData, UINT *piSlot)
 {
-    FIXME("Stub\n");
-    return E_NOTIMPL;
+    if (m_cSlots <= 0)
+        return E_FAIL;
+
+    UINT iSlot = 0;
+    SLOTITEMDATA *pItem;
+    while (FAILED(_GetItem(iSlot, &pItem)) || !_IsEqual(pItem, pbData, cbData))
+    {
+        if (++iSlot >= m_cSlots)
+            return E_FAIL;
+    }
+
+    *piSlot = iSlot;
+    return S_OK;
 }
 
 STDMETHODIMP CMruBase::GetData(UINT iSlot, BYTE *pbData, DWORD cbData)
 {
-    FIXME("Stub\n");
-    return E_NOTIMPL;
+    SLOTITEMDATA *pItem;
+    HRESULT hr = _GetItem(iSlot, &pItem);
+    if (FAILED(hr))
+        return hr;
+
+    if (cbData < pItem->cbData)
+        return 0x8007007A; // FIXME: Magic number
+
+    CopyMemory(pbData, pItem->pvData, pItem->cbData);
+    return hr;
 }
 
 STDMETHODIMP CMruBase::QueryInfo(UINT iSlot, UINT *puSlot, DWORD *pcbData)
 {
-    FIXME("Stub\n");
-    return E_NOTIMPL;
+    UINT iGotSlot;
+    HRESULT hr = _GetSlot(iSlot, &iGotSlot);
+    if (FAILED(hr))
+        return hr;
+
+    if (puSlot)
+        *puSlot = iGotSlot;
+
+    if (pcbData)
+    {
+        SLOTITEMDATA *pItem;
+        hr = _GetSlotItem(iGotSlot, &pItem);
+        if (SUCCEEDED(hr))
+            *pcbData = pItem->cbData;
+    }
+
+    return hr;
 }
 
 STDMETHODIMP CMruBase::Delete(UINT iSlot)
 {
-    FIXME("Stub\n");
-    return E_NOTIMPL;
+    UINT uSlot;
+    HRESULT hr = _RemoveSlot(iSlot, &uSlot);
+    if (FAILED(hr))
+        return hr;
+
+    _DeleteItem(uSlot);
+    return hr;
 }
 
-HRESULT CMruBase::_IsEqual(const SLOTITEMDATA *pSlot, LPCITEMIDLIST pidl, UINT 
cbPidl) const
+BOOL CMruBase::_IsEqual(const SLOTITEMDATA *pItem, LPCVOID pvData, UINT 
cbData) const
 {
-    FIXME("Stub\n");
-    return E_NOTIMPL;
+    if (m_fnCompare)
+        return m_fnCompare(pvData, pItem->pvData, cbData) == 0;
+
+    switch (m_dwFlags & COMPARE_BY_MASK)
+    {
+        case COMPARE_BY_MEMCMP:
+            if (pItem->cbData != cbData)
+                return FALSE;
+            return memcmp(pvData, pItem->pvData, cbData) == 0;
+
+        case COMPARE_BY_STRCMPIW:
+            return StrCmpIW((LPCWSTR)pvData, (LPCWSTR)pItem->pvData) == 0;
+
+        case COMPARE_BY_STRCMPW:
+            return StrCmpW((LPCWSTR)pvData, (LPCWSTR)pItem->pvData) == 0;
+
+        case COMPARE_BY_IEILISEQUAL:
+            return IEILIsEqual((LPCITEMIDLIST)pvData, 
(LPCITEMIDLIST)pItem->pvData, FALSE);
+
+        default:
+            ERR("0x%08X\n", m_dwFlags);
+            return FALSE;
+    }
 }
 
 HRESULT CMruBase::_DeleteValue(LPCWSTR pszValue)
 {
-    FIXME("Stub\n");
-    return E_NOTIMPL;
+    return SHDeleteValueW(m_hKey, NULL, pszValue);
 }
 
 class CMruLongList
diff --git a/sdk/include/reactos/shlobj_undoc.h 
b/sdk/include/reactos/shlobj_undoc.h
index 33f911e05c7..0601d6fbd7b 100644
--- a/sdk/include/reactos/shlobj_undoc.h
+++ b/sdk/include/reactos/shlobj_undoc.h
@@ -29,11 +29,11 @@ extern "C" {
 typedef struct tagSLOTITEMDATA
 {
     DWORD dwFlags;
-    UINT cbPidl;
-    LPITEMIDLIST pidl;
+    UINT cbData;
+    LPVOID pvData;
 } SLOTITEMDATA, *PSLOTITEMDATA;
 
-typedef INT (CALLBACK *SLOTCOMPARE)(LPCITEMIDLIST, LPCITEMIDLIST, UINT);
+typedef INT (CALLBACK *SLOTCOMPARE)(LPCVOID pvData1, LPCVOID pvData2, UINT 
cbData);
 
 /*****************************************************************************
  * New shellstate structure
diff --git a/sdk/include/reactos/shlwapi_undoc.h 
b/sdk/include/reactos/shlwapi_undoc.h
index d7f3790d897..cd427170815 100644
--- a/sdk/include/reactos/shlwapi_undoc.h
+++ b/sdk/include/reactos/shlwapi_undoc.h
@@ -69,6 +69,19 @@ HRESULT WINAPI SHWriteDataBlockList(IStream* lpStream, 
LPDBLIST lpList);
 HRESULT WINAPI SHReadDataBlockList(IStream* lpStream, LPDBLIST* lppList);
 VOID WINAPI SHFreeDataBlockList(LPDBLIST lpList);
 
+LONG
+WINAPI
+RegCreateKeyExWrapW(
+    _In_ HKEY hKey,
+    _In_ LPCWSTR lpSubKey,
+    _In_ DWORD Reserved,
+    _In_opt_ LPWSTR lpClass,
+    _In_ DWORD dwOptions,
+    _In_ REGSAM samDesired,
+    _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+    _Out_ PHKEY phkResult,
+    _Out_opt_ LPDWORD lpdwDisposition);
+
 /* Redirected to kernel32.ExpandEnvironmentStringsA/W */
 DWORD WINAPI SHExpandEnvironmentStringsA(LPCSTR,LPSTR,DWORD);
 DWORD WINAPI SHExpandEnvironmentStringsW(LPCWSTR,LPWSTR,DWORD);

Reply via email to