/* * PROJECT: ReactOS shdocvw * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later) * PURPOSE: Implement MRU List of shdocvw.dll * COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ */ #define COBJMACROS #include #include #include #include #include #include #include #include #include #include "shdocvw.h" #include WINE_DEFAULT_DEBUG_CHANNEL(shdocvw); extern "C" void __cxa_pure_virtual(void) { ::DebugBreak(); } class CMruBase : public IMruDataList { protected: LONG m_cRefs = 1; // Reference count DWORD m_dwFlags = 0; // The flags BOOL m_bFlag1 = FALSE; // ??? BOOL m_bChecked = FALSE; // ??? 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 public: CMruBase() { } virtual ~CMruBase(); // IUnknown methods STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj) override; STDMETHODIMP_(ULONG) AddRef() override { return ::InterlockedIncrement(&m_cRefs); } STDMETHODIMP_(ULONG) Release() override { if (::InterlockedDecrement(&m_cRefs) == 0) { delete this; return 0; } return m_cRefs; } // IMruDataList methods STDMETHODIMP InitData(UINT cCapacity, UINT flags, HKEY hKey, LPCWSTR pszSubKey, SLOTCOMPARE fnCompare) 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; STDMETHODIMP QueryInfo(UINT iSlot, UINT *puSlot, DWORD *pcbData) override; STDMETHODIMP Delete(UINT iSlot) override; // Non-standard methods virtual HRESULT _IsEqual(const SLOTITEMDATA *pSlot, LPCITEMIDLIST pidl, UINT cbPidl) const; virtual HRESULT _DeleteValue(LPCWSTR pszValue); virtual HRESULT _InitSlots() = 0; virtual void _SaveSlots() = 0; virtual UINT _UpdateSlots(UINT iSlot) = 0; virtual void _SlotString(DWORD dwSlot, LPWSTR psz, DWORD cch) = 0; virtual HRESULT _GetSlot(UINT iSlot, UINT *puSlot) = 0; virtual HRESULT _RemoveSlot(UINT iSlot, UINT *uSlot) = 0; static void* operator new(size_t size) { return ::LocalAlloc(LPTR, size); } static void operator delete(void *ptr) { ::LocalFree(ptr); } }; CMruBase::~CMruBase() { if (m_hKey) { ::RegCloseKey(m_hKey); m_hKey = NULL; } if (m_pSlots) { for (UINT iSlot = 0; iSlot < m_cSlots; ++iSlot) { if (m_pSlots[iSlot].pidl) { ::LocalFree(m_pSlots[iSlot].pidl); m_pSlots[iSlot].pidl = NULL; } } ::LocalFree(m_pSlots); m_pSlots = NULL; } } STDMETHODIMP CMruBase::QueryInterface(REFIID riid, void **ppvObj) { if (!ppvObj) return E_POINTER; if (IsEqualGUID(riid, IID_IMruDataList)) { *ppvObj = static_cast(this); AddRef(); return S_OK; } ERR("%s: E_NOINTERFACE\n", debugstr_guid(&riid)); return E_NOINTERFACE; } STDMETHODIMP CMruBase::InitData( UINT cCapacity, UINT flags, HKEY hKey, LPCWSTR pszSubKey, SLOTCOMPARE fnCompare) { FIXME("Stub\n"); return E_NOTIMPL; } STDMETHODIMP CMruBase::AddData(const BYTE *pbData, DWORD cbData, UINT *piSlot) { FIXME("Stub\n"); return E_NOTIMPL; } STDMETHODIMP CMruBase::FindData(const BYTE *pbData, DWORD cbData, UINT *piSlot) { FIXME("Stub\n"); return E_NOTIMPL; } STDMETHODIMP CMruBase::GetData(UINT iSlot, BYTE *pbData, DWORD cbData) { FIXME("Stub\n"); return E_NOTIMPL; } STDMETHODIMP CMruBase::QueryInfo(UINT iSlot, UINT *puSlot, DWORD *pcbData) { FIXME("Stub\n"); return E_NOTIMPL; } STDMETHODIMP CMruBase::Delete(UINT iSlot) { FIXME("Stub\n"); return E_NOTIMPL; } HRESULT CMruBase::_IsEqual(const SLOTITEMDATA *pSlot, LPCITEMIDLIST pidl, UINT cbPidl) const { FIXME("Stub\n"); return E_NOTIMPL; } HRESULT CMruBase::_DeleteValue(LPCWSTR pszValue) { FIXME("Stub\n"); return E_NOTIMPL; } class CMruLongList : public CMruBase { protected: UINT *m_puSlotData = NULL; // The slot data void _ImportShortList(); HRESULT _InitSlots() override; void _SaveSlots() override; UINT _UpdateSlots(UINT iSlot) override; void _SlotString(DWORD dwSlot, LPWSTR psz, DWORD cch) override; HRESULT _GetSlot(UINT iSlot, UINT *puSlot) override; HRESULT _RemoveSlot(UINT iSlot, UINT *uSlot) override; public: CMruLongList() { } ~CMruLongList() override { if (m_puSlotData) { ::LocalFree(m_puSlotData); m_puSlotData = NULL; } } }; HRESULT CMruLongList::_InitSlots() { FIXME("Stub\n"); return E_NOTIMPL; } void CMruLongList::_SaveSlots() { FIXME("Stub\n"); } UINT CMruLongList::_UpdateSlots(UINT iSlot) { FIXME("Stub\n"); return E_NOTIMPL; } void CMruLongList::_SlotString(DWORD dwSlot, LPWSTR psz, DWORD cch) { FIXME("Stub\n"); } HRESULT CMruLongList::_GetSlot(UINT iSlot, UINT *puSlot) { FIXME("Stub\n"); return E_NOTIMPL; } HRESULT CMruLongList::_RemoveSlot(UINT iSlot, UINT *uSlot) { FIXME("Stub\n"); return E_NOTIMPL; } void CMruLongList::_ImportShortList() { FIXME("Stub\n"); } EXTERN_C HRESULT CMruLongList_CreateInstance(DWORD dwUnused1, void **ppv, DWORD dwUnused3) { UNREFERENCED_PARAMETER(dwUnused1); UNREFERENCED_PARAMETER(dwUnused3); CMruLongList *pMruList = new CMruLongList(); *ppv = static_cast(pMruList); return S_OK; } class CMruNode : public CMruLongList { protected: UINT m_uSlotData = 0; // The slot data CMruNode *m_pParent = NULL; // The parent IShellFolder *m_pShellFolder = NULL; // The shell folder public: CMruNode() { } CMruNode(CMruNode *pParent, UINT uSlotData); ~CMruNode() override; CMruNode *GetParent(); }; CMruNode::CMruNode(CMruNode *pParent, UINT uSlotData) { m_uSlotData = uSlotData; m_pParent = pParent; pParent->AddRef(); } CMruNode::~CMruNode() { if (m_pParent) { m_pParent->Release(); m_pParent = NULL; } if (m_pShellFolder) { m_pShellFolder->Release(); m_pShellFolder = NULL; } } CMruNode *CMruNode::GetParent() { if (m_pParent) m_pParent->AddRef(); return m_pParent; } class CMruPidlList : public IMruPidlList , public CMruNode { protected: LPBYTE m_pbSlots = NULL; // The data DWORD m_cbSlots = 0; // The data size HANDLE m_hMutex = NULL; // The mutex (for sync) BOOL _LoadNodeSlots() { DWORD cbSlots = m_cbSlots; if (SHGetValueW(m_hKey, NULL, L"NodeSlots", NULL, m_pbSlots, &cbSlots) != ERROR_SUCCESS) return FALSE; m_cbSlots = cbSlots; return TRUE; } void _SaveNodeSlots() { SHSetValueW(m_hKey, NULL, L"NodeSlots", REG_BINARY, m_pbSlots, m_cbSlots); } public: CMruPidlList() { } virtual ~CMruPidlList() { m_pbSlots = (LPBYTE)::LocalFree(m_pbSlots); if (m_hMutex) { ::CloseHandle(m_hMutex); m_hMutex = NULL; } } // IUnknown methods STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj) override; STDMETHODIMP_(ULONG) AddRef() override { return CMruBase::AddRef(); } STDMETHODIMP_(ULONG) Release() override { return CMruBase::Release(); } // IMruPidlList methods STDMETHODIMP InitList(UINT cMRUSize, HKEY hKey, LPCWSTR pszName) override; STDMETHODIMP UsePidl(LPCITEMIDLIST pidl, UINT *puSlots) override; STDMETHODIMP QueryPidl( LPCITEMIDLIST pidl, UINT cSlots, UINT *puSlots, UINT *pcSlots) override; STDMETHODIMP PruneKids(LPCITEMIDLIST pidl) override; }; STDMETHODIMP CMruPidlList::QueryInterface(REFIID riid, void **ppvObj) { if (!ppvObj) return E_POINTER; if (::IsEqualGUID(riid, IID_IMruPidlList) || ::IsEqualGUID(riid, IID_IUnknown)) { *ppvObj = static_cast(this); AddRef(); return S_OK; } ERR("%s: E_NOINTERFACE\n", debugstr_guid(&riid)); return E_NOINTERFACE; } STDMETHODIMP CMruPidlList::InitList(UINT cMRUSize, HKEY hKey, LPCWSTR pszName) { FIXME("Stub\n"); return E_NOTIMPL; } STDMETHODIMP CMruPidlList::UsePidl(LPCITEMIDLIST pidl, UINT *puSlots) { FIXME("Stub\n"); return E_NOTIMPL; } STDMETHODIMP CMruPidlList::QueryPidl( LPCITEMIDLIST pidl, UINT cSlots, UINT *puSlots, UINT *pcSlots) { FIXME("Stub\n"); return E_NOTIMPL; } STDMETHODIMP CMruPidlList::PruneKids(LPCITEMIDLIST pidl) { FIXME("Stub\n"); return E_NOTIMPL; } EXTERN_C HRESULT CMruPidlList_CreateInstance(DWORD dwUnused1, void **ppv, DWORD dwUnused3) { UNREFERENCED_PARAMETER(dwUnused1); UNREFERENCED_PARAMETER(dwUnused3); *ppv = NULL; CMruPidlList *pMruList = new CMruPidlList(); if (pMruList == NULL) return E_OUTOFMEMORY; *ppv = static_cast(pMruList); return S_OK; }