[SHDOCVW][SDK][COM_APITEST] Implement MRU List for Shell Bag, Part 1 (#5626)

- Add mrulist.cpp source file.
- Add CMruBase, CMruLongList, CMruNode,
  and CMruPidlList classes with stub functions.
- Add CLSID_MruPidlList and CLSID_MruLongList.
- Add IMruDataList interface into <shlobj_undoc.h>.
- Add IID_IMruDataList and CLSID_MruLongList
  definitions into <shlguid_undoc.h>.
CORE-9283
This commit is contained in:
Katayama Hirofumi MZ 2023-08-31 09:35:00 +09:00 committed by GitHub
parent 28e771713f
commit 58770200e7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 489 additions and 0 deletions

View file

@ -17,6 +17,7 @@ set_source_files_properties(shdocvw.rc PROPERTIES OBJECT_DEPENDS ${CMAKE_CURRENT
add_library(shdocvw MODULE
${SOURCE}
mrulist.cpp
shdocvw.rc
${CMAKE_CURRENT_BINARY_DIR}/shdocvw.def)

View file

@ -0,0 +1,429 @@
/*
* 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 <katayama.hirofumi.mz@gmail.com>
*/
#define COBJMACROS
#include <windef.h>
#include <winbase.h>
#include <winreg.h>
#include <objbase.h>
#include <oleauto.h>
#include <shlobj.h>
#include <shlobj_undoc.h>
#include <shlguid_undoc.h>
#include <shlwapi.h>
#include "shdocvw.h"
#include <wine/debug.h>
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<IMruDataList*>(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<IMruDataList*>(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<IMruPidlList*>(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<IMruPidlList*>(pMruList);
return S_OK;
}

View file

@ -50,4 +50,9 @@ extern LONG SHDOCVW_refCount DECLSPEC_HIDDEN;
static inline void SHDOCVW_LockModule(void) { InterlockedIncrement( &SHDOCVW_refCount ); }
static inline void SHDOCVW_UnlockModule(void) { InterlockedDecrement( &SHDOCVW_refCount ); }
#ifdef __REACTOS__
EXTERN_C HRESULT CMruLongList_CreateInstance(DWORD dwUnused1, void **ppv, DWORD dwUnused3);
EXTERN_C HRESULT CMruPidlList_CreateInstance(DWORD dwUnused1, void **ppv, DWORD dwUnused3);
#endif
#endif /* __WINE_SHDOCVW_H */

View file

@ -30,6 +30,7 @@
#include "winreg.h"
#ifdef __REACTOS__
#include "winnls.h"
#include <shlguid_undoc.h>
#endif
#include "shlwapi.h"
#include "wininet.h"
@ -87,6 +88,13 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
|| IsEqualGUID(&CLSID_TaskbarList, rclsid))
return get_ieframe_object(rclsid, riid, ppv);
#ifdef __REACTOS__
if (IsEqualGUID(&CLSID_MruLongList, rclsid))
return CMruLongList_CreateInstance(0, ppv, 0);
if (IsEqualGUID(&CLSID_MruPidlList, rclsid))
return CMruPidlList_CreateInstance(0, ppv, 0);
#endif
/* As a last resort, figure if the CLSID belongs to a 'Shell Instance Object' */
return SHDOCVW_GetShellInstanceObjectClassObject(rclsid, riid, ppv);
}

View file

@ -205,6 +205,7 @@ static KNOWN_INTERFACE KnownInterfaces[] =
{ ID_NAME(IID_IMenuPopup), TRUE },
{ ID_NAME(IID_IModalWindow) },
{ ID_NAME(IID_IMoniker) },
{ ID_NAME(IID_IMruDataList) },
{ ID_NAME(IID_IMruPidlList) },
{ ID_NAME(IID_IMultiMonitorDockingSite), TRUE },
{ ID_NAME(IID_IMultiQI), TRUE },

View file

@ -144,6 +144,7 @@ DEFINE_GUID(IID_IHWEventHandler2, 0xcfcc809f, 0x295d, 0x42e8, 0x9f, 0xf
DEFINE_GUID(IID_IInitializeWithBindCtx, 0x71c0d2bc, 0x726d, 0x45cc, 0xa6, 0xc0, 0x2e, 0x31, 0xc1, 0xdb, 0x21, 0x59);
DEFINE_GUID(IID_IItemNameLimits, 0x1df0d7f1, 0xb267, 0x4d28, 0x8b, 0x10, 0x12, 0xe2, 0x32, 0x02, 0xa5, 0xc4);
DEFINE_GUID(IID_IMruPidlList, 0x47851649, 0xa2ef, 0x4e67, 0xba, 0xec, 0xc6, 0xa1, 0x53, 0xac, 0x72, 0xec);
DEFINE_GUID(IID_IMruDataList, 0xFE787BCB, 0x0EE8, 0x44FB, 0x8C, 0x89, 0x12, 0xF5, 0x08, 0x91, 0x3C, 0x40);
DEFINE_GUID(IID_IMultiMonitorDockingSite, 0x03879de0, 0xa205, 0x11d0, 0x99, 0xcb, 0x00, 0xc0, 0x4f, 0xd6, 0x55, 0xe1);
DEFINE_GUID(IID_INamespaceWalk, 0x57ced8a7, 0x3f4a, 0x432c, 0x93, 0x50, 0x30, 0xf2, 0x44, 0x83, 0xf7, 0x4f);
DEFINE_GUID(IID_INamespaceWalkCB, 0xd92995f8, 0xcf5e, 0x4a76, 0xbf, 0x59, 0xea, 0xd3, 0x9e, 0xa2, 0xb9, 0x7e);

View file

@ -85,6 +85,7 @@ static const CLASS_AND_INTERFACES ExpectedInterfaces[] =
{
ID_NAME(CLSID_MruLongList),
{
{ 0x0, &IID_IMruDataList },
{ 0x0, &IID_IUnknown },
}
},

View file

@ -144,6 +144,8 @@ DEFINE_GUID(CLSID_CopyToMenu, 0xC2FBB630, 0x2971, 0x11D1, 0xA1, 0x8
DEFINE_GUID(CLSID_MoveToMenu, 0xC2FBB631, 0x2971, 0x11D1, 0xA1, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0x5D, 0x13);
DEFINE_GUID(CLSID_MruPidlList, 0x42AEDC87, 0x2188, 0x41FD, 0xB9, 0xA3, 0x0C, 0x96, 0x6F, 0xEA, 0xBE, 0xC1);
DEFINE_GUID(IID_IMruPidlList, 0x47851649, 0xA2EF, 0x4E67, 0xBA, 0xEC, 0xC6, 0xA1, 0x53, 0xAC, 0x72, 0xEC);
DEFINE_GUID(CLSID_MruLongList, 0x53BD6B4E, 0x3780, 0x4693, 0xAF, 0xC3, 0x71, 0x61, 0xC2, 0xF3, 0xEE, 0x9C);
DEFINE_GUID(IID_IMruDataList, 0xFE787BCB, 0x0EE8, 0x44FB, 0x8C, 0x89, 0x12, 0xF5, 0x08, 0x91, 0x3C, 0x40);
/* The following list of interfaces was taken from here: http://www.geoffchappell.com/studies/windows/shell/shell32/interfaces/index.htm */
DEFINE_GUID(IID_IAggregateFilterCondition, 0x86228AA3, 0xA736, 0x4733, 0xBD, 0x8A, 0x10, 0xA8, 0x3C, 0x69, 0xBF, 0x84);

View file

@ -26,6 +26,15 @@
extern "C" {
#endif /* defined(__cplusplus) */
typedef struct tagSLOTITEMDATA
{
DWORD dwFlags;
UINT cbPidl;
LPITEMIDLIST pidl;
} SLOTITEMDATA, *PSLOTITEMDATA;
typedef INT (CALLBACK *SLOTCOMPARE)(LPCITEMIDLIST, LPCITEMIDLIST, UINT);
/*****************************************************************************
* New shellstate structure
*/
@ -678,6 +687,38 @@ DECLARE_INTERFACE_(IShellBrowserService, IUnknown)
#define IShellBrowserService_GetPropertyBag(T,a,b,c) (T)->lpVtbl->GetPropertyBag(T,a,b,c)
#endif
/*****************************************************************************
* IMruDataList interface
*/
#define INTERFACE IMruDataList
DECLARE_INTERFACE_(IMruDataList, IUnknown)
{
/*** IUnknown ***/
STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
STDMETHOD_(ULONG,AddRef)(THIS) PURE;
STDMETHOD_(ULONG,Release)(THIS) PURE;
/*** IMruDataList ***/
STDMETHOD(InitData)(THIS_ UINT, UINT, HKEY, LPCWSTR, SLOTCOMPARE) PURE;
STDMETHOD(AddData)(THIS_ const BYTE *, DWORD, UINT*) PURE;
STDMETHOD(FindData)(THIS_ const BYTE*, DWORD, UINT*) PURE;
STDMETHOD(GetData)(THIS_ UINT, BYTE*, DWORD) PURE;
STDMETHOD(QueryInfo)(THIS_ UINT, UINT*, DWORD*) PURE;
STDMETHOD(Delete)(THIS_ UINT) PURE;
};
#undef INTERFACE
#ifdef COBJMACROS
#define IMruDataList_QueryInterface(T,a,b) (T)->lpVtbl->QueryInterface(T,a,b)
#define IMruDataList_AddRef(T) (T)->lpVtbl->AddRef(T)
#define IMruDataList_Release(T) (T)->lpVtbl->Release(T)
#define IMruDataList_InitData(T,a,b,c,d,e) (T)->lpVtbl->InitData(T,a,b,c,d,e)
#define IMruDataList_AddData(T,a,b,c) (T)->lpVtbl->AddData(T,a,b,c)
#define IMruDataList_FindData(T,a,b,c) (T)->lpVtbl->FindData(T,a,b,c)
#define IMruDataList_GetData(T,a,b,c) (T)->lpVtbl->GetData(T,a,b,c)
#define IMruDataList_QueryInfo(T,a,b,c) (T)->lpVtbl->QueryInfo(T,a,b,c)
#define IMruDataList_Delete(T,a) (T)->lpVtbl->Delete(T,a)
#endif
/*****************************************************************************
* IMruPidlList interface
*/