mirror of
https://github.com/reactos/reactos.git
synced 2024-06-01 18:21:50 +00:00
[SHDOCVW][SHDOCVW_APITEST] Implement MRU List for Shell Bag, Part 3 (#5646)
Follow-up to #5634. - Implement CMruBase::_UseEmptySlot. - Implement CMruLongList and CMruShortList. - Add CMruClassFactory class and modify DllGetClassObject function by using it. - Add shdocvw_apitest.exe. CORE-9283
This commit is contained in:
parent
2a16fc5e19
commit
1961d708e7
|
@ -17,6 +17,7 @@
|
|||
#include <shlguid_undoc.h>
|
||||
#include <shlwapi.h>
|
||||
#include <shlwapi_undoc.h>
|
||||
#include <strsafe.h>
|
||||
#include "shdocvw.h"
|
||||
|
||||
#include <wine/debug.h>
|
||||
|
@ -40,7 +41,7 @@ BOOL IEILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2, BOOL bUnknown)
|
|||
|
||||
// The flags for SLOTITEMDATA.dwFlags
|
||||
#define SLOT_LOADED 0x1
|
||||
#define SLOT_UNKNOWN_FLAG 0x2
|
||||
#define SLOT_SET 0x2
|
||||
|
||||
// The flags for CMruBase.m_dwFlags
|
||||
#define COMPARE_BY_MEMCMP 0x0
|
||||
|
@ -55,7 +56,7 @@ class CMruBase
|
|||
protected:
|
||||
LONG m_cRefs = 1; // Reference count
|
||||
DWORD m_dwFlags = 0; // The COMPARE_BY_... flags
|
||||
BOOL m_bFlag1 = FALSE; // ???
|
||||
BOOL m_bNeedSave = FALSE; // The flag that indicates whether it needs saving
|
||||
BOOL m_bChecked = FALSE; // The checked flag
|
||||
HKEY m_hKey = NULL; // A registry key
|
||||
DWORD m_cSlotRooms = 0; // Rooms for slots
|
||||
|
@ -70,11 +71,10 @@ protected:
|
|||
|
||||
HRESULT _GetSlotItem(UINT iSlot, SLOTITEMDATA **ppItem);
|
||||
void _CheckUsedSlots();
|
||||
HRESULT _UseEmptySlot(UINT *piSlot);
|
||||
|
||||
public:
|
||||
CMruBase()
|
||||
{
|
||||
}
|
||||
CMruBase();
|
||||
virtual ~CMruBase();
|
||||
|
||||
// IUnknown methods
|
||||
|
@ -103,7 +103,7 @@ public:
|
|||
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;
|
||||
virtual HRESULT _RemoveSlot(UINT iSlot, UINT *puSlot) = 0;
|
||||
|
||||
static void* operator new(size_t size)
|
||||
{
|
||||
|
@ -115,6 +115,11 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
CMruBase::CMruBase()
|
||||
{
|
||||
::InterlockedIncrement(&SHDOCVW_refCount);
|
||||
}
|
||||
|
||||
CMruBase::~CMruBase()
|
||||
{
|
||||
if (m_hKey)
|
||||
|
@ -133,13 +138,15 @@ CMruBase::~CMruBase()
|
|||
::LocalFree(m_pSlots);
|
||||
m_pSlots = NULL;
|
||||
}
|
||||
|
||||
::InterlockedDecrement(&SHDOCVW_refCount);
|
||||
}
|
||||
|
||||
STDMETHODIMP CMruBase::QueryInterface(REFIID riid, void **ppvObj)
|
||||
{
|
||||
if (!ppvObj)
|
||||
return E_POINTER;
|
||||
if (IsEqualGUID(riid, IID_IMruDataList))
|
||||
if (IsEqualGUID(riid, IID_IMruDataList) || IsEqualGUID(riid, IID_IUnknown))
|
||||
{
|
||||
*ppvObj = static_cast<IMruDataList*>(this);
|
||||
AddRef();
|
||||
|
@ -247,7 +254,7 @@ HRESULT CMruBase::_AddItem(UINT iSlot, const BYTE *pbData, DWORD cbData)
|
|||
return E_FAIL;
|
||||
|
||||
pItem->cbData = cbData;
|
||||
pItem->dwFlags = (SLOT_LOADED | SLOT_UNKNOWN_FLAG);
|
||||
pItem->dwFlags = (SLOT_LOADED | SLOT_SET);
|
||||
CopyMemory(pItem->pvData, pbData, cbData);
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -397,6 +404,147 @@ HRESULT CMruBase::_DeleteValue(LPCWSTR pszValue)
|
|||
return SHDeleteValueW(m_hKey, NULL, pszValue);
|
||||
}
|
||||
|
||||
HRESULT CMruBase::_UseEmptySlot(UINT *piSlot)
|
||||
{
|
||||
if (!m_bChecked)
|
||||
_CheckUsedSlots();
|
||||
|
||||
if (!m_cSlotRooms)
|
||||
return E_FAIL;
|
||||
|
||||
UINT iSlot = 0;
|
||||
for (SLOTITEMDATA *pItem = m_pSlots; (pItem->dwFlags & SLOT_SET); ++pItem)
|
||||
{
|
||||
if (++iSlot >= m_cSlotRooms)
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
m_pSlots[iSlot].dwFlags |= SLOT_SET;
|
||||
*piSlot = iSlot;
|
||||
++m_cSlots;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
class CMruShortList
|
||||
: public CMruBase
|
||||
{
|
||||
protected:
|
||||
LPWSTR m_pszSlotData = NULL;
|
||||
|
||||
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 *puSlot) override;
|
||||
friend class CMruLongList;
|
||||
|
||||
public:
|
||||
CMruShortList()
|
||||
{
|
||||
}
|
||||
|
||||
~CMruShortList() override
|
||||
{
|
||||
m_pszSlotData = (LPWSTR)::LocalFree(m_pszSlotData);
|
||||
}
|
||||
};
|
||||
|
||||
HRESULT CMruShortList::_InitSlots()
|
||||
{
|
||||
DWORD cbData = (m_cSlotRooms + 1) * sizeof(WCHAR);
|
||||
m_pszSlotData = (LPWSTR)LocalAlloc(LPTR, cbData);
|
||||
if (!m_pszSlotData)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
if (SHGetValueW(m_hKey, NULL, L"MRUList", NULL, m_pszSlotData, &cbData) == ERROR_SUCCESS)
|
||||
m_cSlots = (cbData / sizeof(WCHAR)) - 1;
|
||||
|
||||
m_pszSlotData[m_cSlots] = UNICODE_NULL;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void CMruShortList::_SaveSlots()
|
||||
{
|
||||
if (m_bNeedSave)
|
||||
{
|
||||
DWORD cbData = (m_cSlots + 1) * sizeof(WCHAR);
|
||||
SHSetValueW(m_hKey, NULL, L"MRUList", REG_SZ, m_pszSlotData, cbData);
|
||||
m_bNeedSave = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: MRUList uses lowercase alphabet for history of most recently used items.
|
||||
UINT CMruShortList::_UpdateSlots(UINT iSlot)
|
||||
{
|
||||
UINT iData, cDataToMove = iSlot;
|
||||
|
||||
if (iSlot == m_cSlots)
|
||||
{
|
||||
if (SUCCEEDED(_UseEmptySlot(&iData)))
|
||||
{
|
||||
++cDataToMove;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This code is getting the item index from a lowercase letter.
|
||||
iData = m_pszSlotData[m_cSlots - 1] - L'a';
|
||||
--cDataToMove;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
iData = m_pszSlotData[iSlot] - L'a';
|
||||
}
|
||||
|
||||
if (cDataToMove)
|
||||
{
|
||||
MoveMemory(m_pszSlotData + 1, m_pszSlotData, cDataToMove * sizeof(WCHAR));
|
||||
m_pszSlotData[0] = (WCHAR)(L'a' + iData);
|
||||
m_bNeedSave = TRUE;
|
||||
}
|
||||
|
||||
return iData;
|
||||
}
|
||||
|
||||
void CMruShortList::_SlotString(DWORD dwSlot, LPWSTR psz, DWORD cch)
|
||||
{
|
||||
if (cch >= 2)
|
||||
{
|
||||
psz[0] = (WCHAR)(L'a' + dwSlot);
|
||||
psz[1] = UNICODE_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT CMruShortList::_GetSlot(UINT iSlot, UINT *puSlot)
|
||||
{
|
||||
if (iSlot >= m_cSlots)
|
||||
return E_FAIL;
|
||||
|
||||
UINT iData = m_pszSlotData[iSlot] - L'a';
|
||||
if (iData >= m_cSlotRooms)
|
||||
return E_FAIL;
|
||||
|
||||
*puSlot = iData;
|
||||
m_pSlots[iData].dwFlags |= SLOT_SET;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CMruShortList::_RemoveSlot(UINT iSlot, UINT *puSlot)
|
||||
{
|
||||
HRESULT hr = _GetSlot(iSlot, puSlot);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
MoveMemory(&m_pszSlotData[iSlot], &m_pszSlotData[iSlot + 1], (m_cSlots - iSlot) * sizeof(WCHAR));
|
||||
--m_cSlots;
|
||||
m_pSlots->dwFlags &= ~SLOT_SET;
|
||||
m_bNeedSave = TRUE;
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
class CMruLongList
|
||||
: public CMruBase
|
||||
{
|
||||
|
@ -410,7 +558,7 @@ protected:
|
|||
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;
|
||||
HRESULT _RemoveSlot(UINT iSlot, UINT *puSlot) override;
|
||||
|
||||
public:
|
||||
CMruLongList()
|
||||
|
@ -429,51 +577,144 @@ public:
|
|||
|
||||
HRESULT CMruLongList::_InitSlots()
|
||||
{
|
||||
FIXME("Stub\n");
|
||||
return E_NOTIMPL;
|
||||
DWORD cbData = (m_cSlotRooms + 1) * sizeof(UINT);
|
||||
m_puSlotData = (UINT*)LocalAlloc(LPTR, cbData);
|
||||
if (!m_puSlotData)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
if (SHGetValueW(m_hKey, NULL, L"MRUListEx", NULL, m_puSlotData, &cbData) == ERROR_SUCCESS)
|
||||
m_cSlots = (cbData / sizeof(UINT)) - 1;
|
||||
else
|
||||
_ImportShortList();
|
||||
|
||||
m_puSlotData[m_cSlots] = MAXDWORD;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void CMruLongList::_SaveSlots()
|
||||
{
|
||||
FIXME("Stub\n");
|
||||
if (m_bNeedSave)
|
||||
{
|
||||
SHSetValueW(m_hKey, NULL, L"MRUListEx", REG_BINARY, m_puSlotData,
|
||||
(m_cSlots + 1) * sizeof(UINT));
|
||||
m_bNeedSave = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
UINT CMruLongList::_UpdateSlots(UINT iSlot)
|
||||
{
|
||||
FIXME("Stub\n");
|
||||
return E_NOTIMPL;
|
||||
UINT cSlotsToMove, uSlotData;
|
||||
|
||||
cSlotsToMove = iSlot;
|
||||
if (iSlot == m_cSlots)
|
||||
{
|
||||
if (SUCCEEDED(_UseEmptySlot(&uSlotData)))
|
||||
{
|
||||
++cSlotsToMove;
|
||||
}
|
||||
else
|
||||
{
|
||||
uSlotData = m_puSlotData[m_cSlots - 1];
|
||||
--cSlotsToMove;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uSlotData = m_puSlotData[iSlot];
|
||||
}
|
||||
|
||||
if (cSlotsToMove > 0)
|
||||
{
|
||||
MoveMemory(m_puSlotData + 1, m_puSlotData, cSlotsToMove * sizeof(UINT));
|
||||
m_puSlotData[0] = uSlotData;
|
||||
m_bNeedSave = TRUE;
|
||||
}
|
||||
|
||||
return uSlotData;
|
||||
}
|
||||
|
||||
void CMruLongList::_SlotString(DWORD dwSlot, LPWSTR psz, DWORD cch)
|
||||
{
|
||||
FIXME("Stub\n");
|
||||
StringCchPrintfW(psz, cch, L"%d", dwSlot);
|
||||
}
|
||||
|
||||
HRESULT CMruLongList::_GetSlot(UINT iSlot, UINT *puSlot)
|
||||
{
|
||||
FIXME("Stub\n");
|
||||
return E_NOTIMPL;
|
||||
if (iSlot >= m_cSlots)
|
||||
return E_FAIL;
|
||||
|
||||
UINT uSlotData = m_puSlotData[iSlot];
|
||||
if (uSlotData >= m_cSlotRooms)
|
||||
return E_FAIL;
|
||||
|
||||
*puSlot = uSlotData;
|
||||
m_pSlots[uSlotData].dwFlags |= SLOT_SET;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CMruLongList::_RemoveSlot(UINT iSlot, UINT *uSlot)
|
||||
HRESULT CMruLongList::_RemoveSlot(UINT iSlot, UINT *puSlot)
|
||||
{
|
||||
FIXME("Stub\n");
|
||||
return E_NOTIMPL;
|
||||
HRESULT hr = _GetSlot(iSlot, puSlot);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
MoveMemory(&m_puSlotData[iSlot], &m_puSlotData[iSlot + 1], (m_cSlots - iSlot) * sizeof(UINT));
|
||||
--m_cSlots;
|
||||
m_pSlots[0].dwFlags &= ~SLOT_SET;
|
||||
m_bNeedSave = TRUE;
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
void CMruLongList::_ImportShortList()
|
||||
{
|
||||
FIXME("Stub\n");
|
||||
CMruShortList *pShortList = new CMruShortList();
|
||||
if (!pShortList)
|
||||
return;
|
||||
|
||||
HRESULT hr = pShortList->InitData(m_cSlotRooms, 0, m_hKey, NULL, NULL);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
UINT uSlot;
|
||||
hr = pShortList->_GetSlot(m_cSlots, &uSlot);
|
||||
if (FAILED(hr))
|
||||
break;
|
||||
|
||||
SLOTITEMDATA *pItem;
|
||||
hr = pShortList->_GetSlotItem(uSlot, &pItem);
|
||||
if (FAILED(hr))
|
||||
break;
|
||||
|
||||
_AddItem(uSlot, (const BYTE*)pItem->pvData, pItem->cbData);
|
||||
pShortList->_DeleteItem(uSlot);
|
||||
|
||||
m_puSlotData[m_cSlots++] = uSlot;
|
||||
}
|
||||
|
||||
m_bNeedSave = TRUE;
|
||||
}
|
||||
|
||||
SHDeleteValueW(m_hKey, NULL, L"MRUList");
|
||||
pShortList->Release();
|
||||
}
|
||||
|
||||
EXTERN_C HRESULT
|
||||
CMruLongList_CreateInstance(DWORD dwUnused1, void **ppv, DWORD dwUnused3)
|
||||
CMruLongList_CreateInstance(DWORD_PTR dwUnused1, void **ppv, DWORD_PTR dwUnused3)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(dwUnused1);
|
||||
UNREFERENCED_PARAMETER(dwUnused3);
|
||||
|
||||
TRACE("%p %p %p\n", dwUnused1, ppv, dwUnused3);
|
||||
|
||||
if (!ppv)
|
||||
return E_POINTER;
|
||||
|
||||
CMruLongList *pMruList = new CMruLongList();
|
||||
*ppv = static_cast<IMruDataList*>(pMruList);
|
||||
TRACE("%p\n", *ppv);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -626,11 +867,16 @@ STDMETHODIMP CMruPidlList::PruneKids(LPCITEMIDLIST pidl)
|
|||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
EXTERN_C HRESULT CMruPidlList_CreateInstance(DWORD dwUnused1, void **ppv, DWORD dwUnused3)
|
||||
EXTERN_C HRESULT CMruPidlList_CreateInstance(DWORD_PTR dwUnused1, void **ppv, DWORD_PTR dwUnused3)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(dwUnused1);
|
||||
UNREFERENCED_PARAMETER(dwUnused3);
|
||||
|
||||
TRACE("%p %p %p\n", dwUnused1, ppv, dwUnused3);
|
||||
|
||||
if (!ppv)
|
||||
return E_POINTER;
|
||||
|
||||
*ppv = NULL;
|
||||
|
||||
CMruPidlList *pMruList = new CMruPidlList();
|
||||
|
@ -638,5 +884,99 @@ EXTERN_C HRESULT CMruPidlList_CreateInstance(DWORD dwUnused1, void **ppv, DWORD
|
|||
return E_OUTOFMEMORY;
|
||||
|
||||
*ppv = static_cast<IMruPidlList*>(pMruList);
|
||||
TRACE("%p\n", *ppv);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
class CMruClassFactory : public IClassFactory
|
||||
{
|
||||
protected:
|
||||
LONG m_cRefs = 1;
|
||||
|
||||
public:
|
||||
CMruClassFactory()
|
||||
{
|
||||
::InterlockedIncrement(&SHDOCVW_refCount);
|
||||
}
|
||||
virtual ~CMruClassFactory()
|
||||
{
|
||||
::InterlockedDecrement(&SHDOCVW_refCount);
|
||||
}
|
||||
|
||||
// IUnknown methods
|
||||
STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj) override;
|
||||
STDMETHODIMP_(ULONG) AddRef() override
|
||||
{
|
||||
return ::InterlockedIncrement(&m_cRefs);
|
||||
}
|
||||
STDMETHODIMP_(ULONG) Release()
|
||||
{
|
||||
if (::InterlockedDecrement(&m_cRefs) == 0)
|
||||
{
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return m_cRefs;
|
||||
}
|
||||
|
||||
// IClassFactory methods
|
||||
STDMETHODIMP CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject);
|
||||
STDMETHODIMP LockServer(BOOL fLock);
|
||||
|
||||
static void* operator new(size_t size)
|
||||
{
|
||||
return ::LocalAlloc(LPTR, size);
|
||||
}
|
||||
static void operator delete(void *ptr)
|
||||
{
|
||||
::LocalFree(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
STDMETHODIMP CMruClassFactory::QueryInterface(REFIID riid, void **ppvObj)
|
||||
{
|
||||
if (!ppvObj)
|
||||
return E_POINTER;
|
||||
if (IsEqualGUID(riid, IID_IClassFactory) || IsEqualGUID(riid, IID_IUnknown))
|
||||
{
|
||||
*ppvObj = static_cast<IClassFactory*>(this);
|
||||
AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
ERR("%s: E_NOINTERFACE\n", debugstr_guid(&riid));
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
STDMETHODIMP CMruClassFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject)
|
||||
{
|
||||
if (pUnkOuter)
|
||||
return CLASS_E_NOAGGREGATION;
|
||||
|
||||
if (IsEqualGUID(riid, IID_IMruDataList))
|
||||
return CMruLongList_CreateInstance(0, ppvObject, 0);
|
||||
|
||||
if (IsEqualGUID(riid, IID_IMruPidlList))
|
||||
return CMruPidlList_CreateInstance(0, ppvObject, 0);
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
STDMETHODIMP CMruClassFactory::LockServer(BOOL fLock)
|
||||
{
|
||||
if (fLock)
|
||||
::InterlockedIncrement(&SHDOCVW_refCount);
|
||||
else
|
||||
::InterlockedDecrement(&SHDOCVW_refCount);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
EXTERN_C HRESULT CMruClassFactory_CreateInstance(REFIID riid, void **ppv)
|
||||
{
|
||||
CMruClassFactory *pFactory = new CMruClassFactory();
|
||||
if (!pFactory)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
HRESULT hr = pFactory->QueryInterface(riid, ppv);
|
||||
pFactory->Release();
|
||||
return hr;
|
||||
}
|
||||
|
|
|
@ -46,13 +46,22 @@ extern HRESULT SHDOCVW_GetShellInstanceObjectClassObject(REFCLSID rclsid,
|
|||
/**********************************************************************
|
||||
* Dll lifetime tracking declaration for shdocvw.dll
|
||||
*/
|
||||
#ifdef __REACTOS__
|
||||
# ifdef __cplusplus
|
||||
EXTERN_C
|
||||
# else
|
||||
extern
|
||||
# endif
|
||||
LONG SHDOCVW_refCount;
|
||||
#else
|
||||
extern LONG SHDOCVW_refCount DECLSPEC_HIDDEN;
|
||||
#endif
|
||||
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);
|
||||
EXTERN_C HRESULT CMruLongList_CreateInstance(DWORD_PTR dwUnused1, void **ppv, DWORD_PTR dwUnused3);
|
||||
EXTERN_C HRESULT CMruClassFactory_CreateInstance(REFIID riid, void **ppv);
|
||||
#endif
|
||||
|
||||
#endif /* __WINE_SHDOCVW_H */
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#ifdef __REACTOS__
|
||||
#include "winnls.h"
|
||||
#include <shlguid_undoc.h>
|
||||
#include <rpcproxy.h> /* for __wine_register_resources / __wine_unregister_resources */
|
||||
#endif
|
||||
#include "shlwapi.h"
|
||||
#include "wininet.h"
|
||||
|
@ -44,6 +45,9 @@ LONG SHDOCVW_refCount = 0;
|
|||
|
||||
static HMODULE SHDOCVW_hshell32 = 0;
|
||||
static HINSTANCE ieframe_instance;
|
||||
#ifdef __REACTOS__
|
||||
static HINSTANCE instance;
|
||||
#endif
|
||||
|
||||
static HINSTANCE get_ieframe_instance(void)
|
||||
{
|
||||
|
@ -89,10 +93,18 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
|
|||
return get_ieframe_object(rclsid, riid, ppv);
|
||||
|
||||
#ifdef __REACTOS__
|
||||
if (IsEqualGUID(&CLSID_MruLongList, rclsid))
|
||||
if (IsEqualGUID(riid, &IID_IClassFactory) || IsEqualGUID(riid, &IID_IUnknown))
|
||||
{
|
||||
if (IsEqualGUID(rclsid, &CLSID_MruLongList) ||
|
||||
IsEqualGUID(rclsid, &CLSID_MruPidlList))
|
||||
{
|
||||
return CMruClassFactory_CreateInstance(riid, ppv);
|
||||
}
|
||||
}
|
||||
else if (IsEqualGUID(riid, &IID_IMruDataList))
|
||||
{
|
||||
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' */
|
||||
|
@ -105,7 +117,11 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
|
|||
HRESULT WINAPI DllRegisterServer(void)
|
||||
{
|
||||
TRACE("\n");
|
||||
#ifdef __REACTOS__
|
||||
return __wine_register_resources(instance);
|
||||
#else
|
||||
return S_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -114,7 +130,11 @@ HRESULT WINAPI DllRegisterServer(void)
|
|||
HRESULT WINAPI DllUnregisterServer(void)
|
||||
{
|
||||
TRACE("\n");
|
||||
#ifdef __REACTOS__
|
||||
return __wine_unregister_resources(instance);
|
||||
#else
|
||||
return S_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
|
@ -155,6 +175,9 @@ BOOL WINAPI DllMain(HINSTANCE hinst, DWORD fdwReason, LPVOID fImpLoad)
|
|||
switch (fdwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
#ifdef __REACTOS__
|
||||
instance = hinst;
|
||||
#endif
|
||||
DisableThreadLibraryCalls(hinst);
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
|
|
|
@ -199,6 +199,10 @@ HKCR
|
|||
Version = s '1.1'
|
||||
VersionIndependentProgId = s 'SearchAssistantOC.SearchAssistantOC'
|
||||
}
|
||||
'{53BD6B4E-3780-4693-AFC3-7161C2F3EE9C}' = s 'MruLongList'
|
||||
{
|
||||
InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Apartment' }
|
||||
}
|
||||
}
|
||||
'Shell.Explorer.1' = s 'Microsoft Web Browser Version 1'
|
||||
{
|
||||
|
|
|
@ -43,6 +43,7 @@ add_subdirectory(powrprof)
|
|||
add_subdirectory(sdk)
|
||||
add_subdirectory(setupapi)
|
||||
add_subdirectory(sfc)
|
||||
add_subdirectory(shdocvw)
|
||||
add_subdirectory(shell32)
|
||||
add_subdirectory(shlwapi)
|
||||
add_subdirectory(spoolss)
|
||||
|
|
10
modules/rostests/apitests/shdocvw/CMakeLists.txt
Normal file
10
modules/rostests/apitests/shdocvw/CMakeLists.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
list(APPEND SOURCE
|
||||
MRUList.cpp
|
||||
testlist.c)
|
||||
|
||||
add_executable(shdocvw_apitest ${SOURCE})
|
||||
set_module_type(shdocvw_apitest win32cui)
|
||||
target_link_libraries(shdocvw_apitest ${PSEH_LIB} uuid)
|
||||
add_importlibs(shdocvw_apitest shlwapi oleaut32 ole32 user32 advapi32 msvcrt kernel32)
|
||||
add_rostests_file(TARGET shdocvw_apitest)
|
250
modules/rostests/apitests/shdocvw/MRUList.cpp
Normal file
250
modules/rostests/apitests/shdocvw/MRUList.cpp
Normal file
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
* PROJECT: ReactOS api tests
|
||||
* LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
|
||||
* PURPOSE: Tests for MRU List
|
||||
* COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
|
||||
*/
|
||||
|
||||
#include <apitest.h>
|
||||
#include <winreg.h>
|
||||
#include <shlwapi.h>
|
||||
#include <shlobj.h>
|
||||
#include <shlobj_undoc.h>
|
||||
#include <shlguid_undoc.h>
|
||||
#include <stdio.h>
|
||||
#include <shlwapi_undoc.h>
|
||||
#include <versionhelpers.h>
|
||||
#include <strsafe.h>
|
||||
#include <wine/test.h>
|
||||
#include <pseh/pseh2.h>
|
||||
|
||||
#define SUBKEY0 L"Software\\MRUListTest"
|
||||
#define TEXT0 L"This is a test."
|
||||
#define TEXT1 L"ReactOS rocks!"
|
||||
|
||||
static void MRUList_List0(void)
|
||||
{
|
||||
HRESULT hr;
|
||||
IMruDataList *pList = NULL;
|
||||
UINT iSlot1, iSlot2, iSlot3;
|
||||
DWORD cbText;
|
||||
WCHAR szText[MAX_PATH];
|
||||
|
||||
hr = CoCreateInstance(CLSID_MruLongList, NULL, CLSCTX_INPROC_SERVER,
|
||||
IID_IMruDataList, (LPVOID*)&pList);
|
||||
ok_hex(hr, S_OK);
|
||||
if (pList == NULL)
|
||||
{
|
||||
skip("pList was NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
hr = pList->InitData(26, 0, HKEY_CURRENT_USER, SUBKEY0, NULL);
|
||||
ok_hex(hr, S_OK);
|
||||
|
||||
cbText = (wcslen(TEXT0) + 1) * sizeof(WCHAR);
|
||||
hr = pList->AddData((BYTE*)TEXT0, cbText, &iSlot1);
|
||||
ok_hex(hr, S_OK);
|
||||
ok_int(iSlot1, 0);
|
||||
|
||||
hr = pList->FindData((BYTE*)TEXT0, cbText, &iSlot2);
|
||||
ok_hex(hr, S_OK);
|
||||
ok_int(iSlot1, iSlot2);
|
||||
|
||||
cbText = sizeof(szText);
|
||||
hr = pList->GetData(iSlot1, (BYTE*)szText, cbText);
|
||||
ok_hex(hr, S_OK);
|
||||
ok_wstr(szText, TEXT0);
|
||||
|
||||
cbText = (wcslen(TEXT1) + 1) * sizeof(WCHAR);
|
||||
hr = pList->AddData((BYTE*)TEXT1, cbText, &iSlot3);
|
||||
ok_hex(hr, S_OK);
|
||||
ok_int(iSlot3, 1);
|
||||
|
||||
pList->Release();
|
||||
}
|
||||
|
||||
static void MRUList_List0_Check(void)
|
||||
{
|
||||
BYTE abData[512];
|
||||
DWORD cbData, dwType;
|
||||
|
||||
cbData = sizeof(abData);
|
||||
LONG error = SHGetValueW(HKEY_CURRENT_USER, SUBKEY0, L"MRUListEx", &dwType, abData, &cbData);
|
||||
ok_long(error, ERROR_SUCCESS);
|
||||
ok_long(dwType, REG_BINARY);
|
||||
#if 1
|
||||
ok_int(memcmp(abData, "\x01\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF", 12), 0);
|
||||
#else
|
||||
for (DWORD i = 0; i < cbData; ++i)
|
||||
{
|
||||
printf("%02X ", abData[i]);
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void MRUList_List1(void)
|
||||
{
|
||||
HRESULT hr;
|
||||
IMruDataList *pList = NULL;
|
||||
UINT iSlot;
|
||||
|
||||
hr = CoCreateInstance(CLSID_MruLongList, NULL, CLSCTX_INPROC_SERVER,
|
||||
IID_IMruDataList, (LPVOID*)&pList);
|
||||
ok_hex(hr, S_OK);
|
||||
if (pList == NULL)
|
||||
{
|
||||
skip("pList was NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
hr = pList->InitData(26, 0, HKEY_CURRENT_USER, SUBKEY0, NULL);
|
||||
ok_hex(hr, S_OK);
|
||||
|
||||
DWORD cbText = (wcslen(TEXT0) + 1) * sizeof(WCHAR);
|
||||
hr = pList->FindData((BYTE*)TEXT0, cbText, &iSlot);
|
||||
ok_hex(hr, S_OK);
|
||||
ok_int(iSlot, 1);
|
||||
|
||||
hr = pList->Delete(iSlot);
|
||||
ok_hex(hr, S_OK);
|
||||
|
||||
iSlot = 0xCAFE;
|
||||
cbText = (wcslen(TEXT0) + 1) * sizeof(WCHAR);
|
||||
hr = pList->FindData((BYTE*)TEXT0, cbText, &iSlot);
|
||||
ok_hex(hr, E_FAIL);
|
||||
ok_int(iSlot, 0xCAFE);
|
||||
|
||||
pList->Release();
|
||||
}
|
||||
|
||||
static void MRUList_List1_Check(void)
|
||||
{
|
||||
BYTE abData[512];
|
||||
DWORD cbData, dwType;
|
||||
|
||||
cbData = sizeof(abData);
|
||||
LONG error = SHGetValueW(HKEY_CURRENT_USER, SUBKEY0, L"MRUListEx", &dwType, abData, &cbData);
|
||||
ok_long(error, ERROR_SUCCESS);
|
||||
ok_long(dwType, REG_BINARY);
|
||||
#if 1
|
||||
ok_int(memcmp(abData, "\x01\x00\x00\x00\xFF\xFF\xFF\xFF", 8), 0);
|
||||
#else
|
||||
for (DWORD i = 0; i < cbData; ++i)
|
||||
{
|
||||
printf("%02X ", abData[i]);
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void MRUList_List2(void)
|
||||
{
|
||||
HRESULT hr;
|
||||
IMruDataList *pList = NULL;
|
||||
|
||||
hr = CoCreateInstance(CLSID_MruLongList, NULL, CLSCTX_INPROC_SERVER,
|
||||
IID_IMruDataList, (LPVOID*)&pList);
|
||||
ok_hex(hr, S_OK);
|
||||
if (pList == NULL)
|
||||
{
|
||||
skip("pList was NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
hr = pList->InitData(26, 0, HKEY_CURRENT_USER, SUBKEY0, NULL);
|
||||
ok_hex(hr, S_OK);
|
||||
|
||||
WCHAR szText[MAX_PATH];
|
||||
DWORD cbText = sizeof(szText);
|
||||
StringCchCopyW(szText, _countof(szText), L"====");
|
||||
hr = pList->GetData(0, (BYTE*)szText, cbText);
|
||||
ok_hex(hr, S_OK);
|
||||
ok_wstr(szText, L"ABC");
|
||||
|
||||
StringCchCopyW(szText, _countof(szText), L"====");
|
||||
cbText = sizeof(szText);
|
||||
hr = pList->GetData(1, (BYTE*)szText, cbText);
|
||||
ok_hex(hr, S_OK);
|
||||
ok_wstr(szText, L"XYZ");
|
||||
|
||||
pList->Release();
|
||||
}
|
||||
|
||||
static void MRUList_List2_Check(void)
|
||||
{
|
||||
BYTE abData[512];
|
||||
DWORD cbData, dwType;
|
||||
|
||||
cbData = sizeof(abData);
|
||||
LONG error = SHGetValueW(HKEY_CURRENT_USER, SUBKEY0, L"MRUListEx", &dwType, abData, &cbData);
|
||||
ok_long(error, ERROR_SUCCESS);
|
||||
ok_long(dwType, REG_BINARY);
|
||||
#if 1
|
||||
ok_int(memcmp(abData, "\x00\x00\x00\x00\x01\x00\x00\x00\xFF\xFF\xFF\xFF", 12), 0);
|
||||
#else
|
||||
for (DWORD i = 0; i < cbData; ++i)
|
||||
{
|
||||
printf("%02X ", abData[i]);
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void MRUList_List(void)
|
||||
{
|
||||
if (IsWindowsVistaOrGreater())
|
||||
{
|
||||
skip("Vista+ doesn't support CLSID_MruLongList\n");
|
||||
return;
|
||||
}
|
||||
|
||||
SHDeleteKeyW(HKEY_CURRENT_USER, SUBKEY0);
|
||||
|
||||
LONG error;
|
||||
error = SHSetValueW(HKEY_CURRENT_USER, SUBKEY0, NULL, REG_SZ, L"", sizeof(UNICODE_NULL));
|
||||
ok_long(error, ERROR_SUCCESS);
|
||||
|
||||
error = SHGetValueW(HKEY_CURRENT_USER, SUBKEY0, NULL, NULL, NULL, NULL);
|
||||
ok_long(error, ERROR_SUCCESS);
|
||||
|
||||
MRUList_List0();
|
||||
MRUList_List0_Check();
|
||||
|
||||
MRUList_List1();
|
||||
MRUList_List1_Check();
|
||||
|
||||
error = SHDeleteValueW(HKEY_CURRENT_USER, SUBKEY0, L"MRUList");
|
||||
ok_long(error, ERROR_FILE_NOT_FOUND);
|
||||
error = SHDeleteValueW(HKEY_CURRENT_USER, SUBKEY0, L"MRUListEx");
|
||||
ok_long(error, ERROR_SUCCESS);
|
||||
|
||||
error = SHSetValueW(HKEY_CURRENT_USER, SUBKEY0, L"MRUList", REG_SZ, L"ab", 3 * sizeof(WCHAR));
|
||||
ok_long(error, ERROR_SUCCESS);
|
||||
error = SHSetValueW(HKEY_CURRENT_USER, SUBKEY0, L"a", REG_BINARY, L"ABC", 4 * sizeof(WCHAR));
|
||||
ok_long(error, ERROR_SUCCESS);
|
||||
error = SHSetValueW(HKEY_CURRENT_USER, SUBKEY0, L"b", REG_BINARY, L"XYZ", 4 * sizeof(WCHAR));
|
||||
ok_long(error, ERROR_SUCCESS);
|
||||
|
||||
MRUList_List2();
|
||||
MRUList_List2_Check();
|
||||
|
||||
error = SHDeleteValueW(HKEY_CURRENT_USER, SUBKEY0, L"MRUList");
|
||||
ok_long(error, ERROR_FILE_NOT_FOUND);
|
||||
error = SHDeleteValueW(HKEY_CURRENT_USER, SUBKEY0, L"MRUListEx");
|
||||
ok_long(error, ERROR_SUCCESS);
|
||||
|
||||
SHDeleteKeyW(HKEY_CURRENT_USER, SUBKEY0);
|
||||
}
|
||||
|
||||
START_TEST(MRUList)
|
||||
{
|
||||
HRESULT hr = CoInitialize(NULL);
|
||||
ok_hex(hr, S_OK);
|
||||
|
||||
MRUList_List();
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
CoUninitialize();
|
||||
}
|
10
modules/rostests/apitests/shdocvw/testlist.c
Normal file
10
modules/rostests/apitests/shdocvw/testlist.c
Normal file
|
@ -0,0 +1,10 @@
|
|||
#define STANDALONE
|
||||
#include <apitest.h>
|
||||
|
||||
extern void func_MRUList(void);
|
||||
|
||||
const struct test winetest_testlist[] =
|
||||
{
|
||||
{ "MRUList", func_MRUList },
|
||||
{ 0, 0 }
|
||||
};
|
Loading…
Reference in a new issue