https://git.reactos.org/?p=reactos.git;a=commitdiff;h=8dbb800358c5714e88848…
commit 8dbb800358c5714e88848b80d76910a32b90c8d7
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Sun Sep 3 09:42:10 2023 +0900
Commit: GitHub <noreply(a)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);