https://git.reactos.org/?p=reactos.git;a=commitdiff;h=58770200e75bd8f0c44485b0281fbd97fa799406
commit 58770200e75bd8f0c44485b0281fbd97fa799406 Author: Katayama Hirofumi MZ <katayama.hirofumi...@gmail.com> AuthorDate: Thu Aug 31 09:35:00 2023 +0900 Commit: GitHub <nore...@github.com> CommitDate: Thu Aug 31 09:35:00 2023 +0900 [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 --- dll/win32/shdocvw/CMakeLists.txt | 1 + dll/win32/shdocvw/mrulist.cpp | 429 ++++++++++++++++++++++++++++ dll/win32/shdocvw/shdocvw.h | 5 + dll/win32/shdocvw/shdocvw_main.c | 8 + modules/rostests/apitests/com/com_apitest.c | 1 + modules/rostests/apitests/com/com_apitest.h | 1 + modules/rostests/apitests/com/shdocvw.c | 1 + sdk/include/reactos/shlguid_undoc.h | 2 + sdk/include/reactos/shlobj_undoc.h | 41 +++ 9 files changed, 489 insertions(+) diff --git a/dll/win32/shdocvw/CMakeLists.txt b/dll/win32/shdocvw/CMakeLists.txt index ecc274f294f..307fee5ad6e 100644 --- a/dll/win32/shdocvw/CMakeLists.txt +++ b/dll/win32/shdocvw/CMakeLists.txt @@ -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) diff --git a/dll/win32/shdocvw/mrulist.cpp b/dll/win32/shdocvw/mrulist.cpp new file mode 100644 index 00000000000..564c3d9e9be --- /dev/null +++ b/dll/win32/shdocvw/mrulist.cpp @@ -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...@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; +} diff --git a/dll/win32/shdocvw/shdocvw.h b/dll/win32/shdocvw/shdocvw.h index 568fbadfbd6..1d8f807d8de 100644 --- a/dll/win32/shdocvw/shdocvw.h +++ b/dll/win32/shdocvw/shdocvw.h @@ -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 */ diff --git a/dll/win32/shdocvw/shdocvw_main.c b/dll/win32/shdocvw/shdocvw_main.c index d52961909fc..0ca9d5827a5 100644 --- a/dll/win32/shdocvw/shdocvw_main.c +++ b/dll/win32/shdocvw/shdocvw_main.c @@ -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); } diff --git a/modules/rostests/apitests/com/com_apitest.c b/modules/rostests/apitests/com/com_apitest.c index 3200c556c7c..c60ac28d451 100644 --- a/modules/rostests/apitests/com/com_apitest.c +++ b/modules/rostests/apitests/com/com_apitest.c @@ -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 }, diff --git a/modules/rostests/apitests/com/com_apitest.h b/modules/rostests/apitests/com/com_apitest.h index c8c8ad08d12..3bbe9e18475 100644 --- a/modules/rostests/apitests/com/com_apitest.h +++ b/modules/rostests/apitests/com/com_apitest.h @@ -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); diff --git a/modules/rostests/apitests/com/shdocvw.c b/modules/rostests/apitests/com/shdocvw.c index 34ea3efb43d..2839cc9331a 100644 --- a/modules/rostests/apitests/com/shdocvw.c +++ b/modules/rostests/apitests/com/shdocvw.c @@ -85,6 +85,7 @@ static const CLASS_AND_INTERFACES ExpectedInterfaces[] = { ID_NAME(CLSID_MruLongList), { + { 0x0, &IID_IMruDataList }, { 0x0, &IID_IUnknown }, } }, diff --git a/sdk/include/reactos/shlguid_undoc.h b/sdk/include/reactos/shlguid_undoc.h index e233df556bd..c6d2295cb30 100644 --- a/sdk/include/reactos/shlguid_undoc.h +++ b/sdk/include/reactos/shlguid_undoc.h @@ -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); diff --git a/sdk/include/reactos/shlobj_undoc.h b/sdk/include/reactos/shlobj_undoc.h index 3ed3b8a8962..33f911e05c7 100644 --- a/sdk/include/reactos/shlobj_undoc.h +++ b/sdk/include/reactos/shlobj_undoc.h @@ -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 */