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);