mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 19:03:00 +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
8 changed files with 675 additions and 28 deletions
|
@ -17,6 +17,7 @@
|
||||||
#include <shlguid_undoc.h>
|
#include <shlguid_undoc.h>
|
||||||
#include <shlwapi.h>
|
#include <shlwapi.h>
|
||||||
#include <shlwapi_undoc.h>
|
#include <shlwapi_undoc.h>
|
||||||
|
#include <strsafe.h>
|
||||||
#include "shdocvw.h"
|
#include "shdocvw.h"
|
||||||
|
|
||||||
#include <wine/debug.h>
|
#include <wine/debug.h>
|
||||||
|
@ -40,7 +41,7 @@ BOOL IEILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2, BOOL bUnknown)
|
||||||
|
|
||||||
// The flags for SLOTITEMDATA.dwFlags
|
// The flags for SLOTITEMDATA.dwFlags
|
||||||
#define SLOT_LOADED 0x1
|
#define SLOT_LOADED 0x1
|
||||||
#define SLOT_UNKNOWN_FLAG 0x2
|
#define SLOT_SET 0x2
|
||||||
|
|
||||||
// The flags for CMruBase.m_dwFlags
|
// The flags for CMruBase.m_dwFlags
|
||||||
#define COMPARE_BY_MEMCMP 0x0
|
#define COMPARE_BY_MEMCMP 0x0
|
||||||
|
@ -55,7 +56,7 @@ class CMruBase
|
||||||
protected:
|
protected:
|
||||||
LONG m_cRefs = 1; // Reference count
|
LONG m_cRefs = 1; // Reference count
|
||||||
DWORD m_dwFlags = 0; // The COMPARE_BY_... flags
|
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
|
BOOL m_bChecked = FALSE; // The checked flag
|
||||||
HKEY m_hKey = NULL; // A registry key
|
HKEY m_hKey = NULL; // A registry key
|
||||||
DWORD m_cSlotRooms = 0; // Rooms for slots
|
DWORD m_cSlotRooms = 0; // Rooms for slots
|
||||||
|
@ -70,11 +71,10 @@ protected:
|
||||||
|
|
||||||
HRESULT _GetSlotItem(UINT iSlot, SLOTITEMDATA **ppItem);
|
HRESULT _GetSlotItem(UINT iSlot, SLOTITEMDATA **ppItem);
|
||||||
void _CheckUsedSlots();
|
void _CheckUsedSlots();
|
||||||
|
HRESULT _UseEmptySlot(UINT *piSlot);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CMruBase()
|
CMruBase();
|
||||||
{
|
|
||||||
}
|
|
||||||
virtual ~CMruBase();
|
virtual ~CMruBase();
|
||||||
|
|
||||||
// IUnknown methods
|
// IUnknown methods
|
||||||
|
@ -103,7 +103,7 @@ public:
|
||||||
virtual UINT _UpdateSlots(UINT iSlot) = 0;
|
virtual UINT _UpdateSlots(UINT iSlot) = 0;
|
||||||
virtual void _SlotString(DWORD dwSlot, LPWSTR psz, DWORD cch) = 0;
|
virtual void _SlotString(DWORD dwSlot, LPWSTR psz, DWORD cch) = 0;
|
||||||
virtual HRESULT _GetSlot(UINT iSlot, UINT *puSlot) = 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)
|
static void* operator new(size_t size)
|
||||||
{
|
{
|
||||||
|
@ -115,6 +115,11 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
CMruBase::CMruBase()
|
||||||
|
{
|
||||||
|
::InterlockedIncrement(&SHDOCVW_refCount);
|
||||||
|
}
|
||||||
|
|
||||||
CMruBase::~CMruBase()
|
CMruBase::~CMruBase()
|
||||||
{
|
{
|
||||||
if (m_hKey)
|
if (m_hKey)
|
||||||
|
@ -133,13 +138,15 @@ CMruBase::~CMruBase()
|
||||||
::LocalFree(m_pSlots);
|
::LocalFree(m_pSlots);
|
||||||
m_pSlots = NULL;
|
m_pSlots = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
::InterlockedDecrement(&SHDOCVW_refCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
STDMETHODIMP CMruBase::QueryInterface(REFIID riid, void **ppvObj)
|
STDMETHODIMP CMruBase::QueryInterface(REFIID riid, void **ppvObj)
|
||||||
{
|
{
|
||||||
if (!ppvObj)
|
if (!ppvObj)
|
||||||
return E_POINTER;
|
return E_POINTER;
|
||||||
if (IsEqualGUID(riid, IID_IMruDataList))
|
if (IsEqualGUID(riid, IID_IMruDataList) || IsEqualGUID(riid, IID_IUnknown))
|
||||||
{
|
{
|
||||||
*ppvObj = static_cast<IMruDataList*>(this);
|
*ppvObj = static_cast<IMruDataList*>(this);
|
||||||
AddRef();
|
AddRef();
|
||||||
|
@ -247,7 +254,7 @@ HRESULT CMruBase::_AddItem(UINT iSlot, const BYTE *pbData, DWORD cbData)
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
|
|
||||||
pItem->cbData = cbData;
|
pItem->cbData = cbData;
|
||||||
pItem->dwFlags = (SLOT_LOADED | SLOT_UNKNOWN_FLAG);
|
pItem->dwFlags = (SLOT_LOADED | SLOT_SET);
|
||||||
CopyMemory(pItem->pvData, pbData, cbData);
|
CopyMemory(pItem->pvData, pbData, cbData);
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
@ -397,6 +404,147 @@ HRESULT CMruBase::_DeleteValue(LPCWSTR pszValue)
|
||||||
return SHDeleteValueW(m_hKey, NULL, 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
|
class CMruLongList
|
||||||
: public CMruBase
|
: public CMruBase
|
||||||
{
|
{
|
||||||
|
@ -410,7 +558,7 @@ protected:
|
||||||
UINT _UpdateSlots(UINT iSlot) override;
|
UINT _UpdateSlots(UINT iSlot) override;
|
||||||
void _SlotString(DWORD dwSlot, LPWSTR psz, DWORD cch) override;
|
void _SlotString(DWORD dwSlot, LPWSTR psz, DWORD cch) override;
|
||||||
HRESULT _GetSlot(UINT iSlot, UINT *puSlot) override;
|
HRESULT _GetSlot(UINT iSlot, UINT *puSlot) override;
|
||||||
HRESULT _RemoveSlot(UINT iSlot, UINT *uSlot) override;
|
HRESULT _RemoveSlot(UINT iSlot, UINT *puSlot) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CMruLongList()
|
CMruLongList()
|
||||||
|
@ -429,51 +577,144 @@ public:
|
||||||
|
|
||||||
HRESULT CMruLongList::_InitSlots()
|
HRESULT CMruLongList::_InitSlots()
|
||||||
{
|
{
|
||||||
FIXME("Stub\n");
|
DWORD cbData = (m_cSlotRooms + 1) * sizeof(UINT);
|
||||||
return E_NOTIMPL;
|
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()
|
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)
|
UINT CMruLongList::_UpdateSlots(UINT iSlot)
|
||||||
{
|
{
|
||||||
FIXME("Stub\n");
|
UINT cSlotsToMove, uSlotData;
|
||||||
return E_NOTIMPL;
|
|
||||||
|
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)
|
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)
|
HRESULT CMruLongList::_GetSlot(UINT iSlot, UINT *puSlot)
|
||||||
{
|
{
|
||||||
FIXME("Stub\n");
|
if (iSlot >= m_cSlots)
|
||||||
return E_NOTIMPL;
|
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");
|
HRESULT hr = _GetSlot(iSlot, puSlot);
|
||||||
return E_NOTIMPL;
|
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()
|
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
|
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(dwUnused1);
|
||||||
UNREFERENCED_PARAMETER(dwUnused3);
|
UNREFERENCED_PARAMETER(dwUnused3);
|
||||||
|
|
||||||
|
TRACE("%p %p %p\n", dwUnused1, ppv, dwUnused3);
|
||||||
|
|
||||||
|
if (!ppv)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
CMruLongList *pMruList = new CMruLongList();
|
CMruLongList *pMruList = new CMruLongList();
|
||||||
*ppv = static_cast<IMruDataList*>(pMruList);
|
*ppv = static_cast<IMruDataList*>(pMruList);
|
||||||
|
TRACE("%p\n", *ppv);
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -626,11 +867,16 @@ STDMETHODIMP CMruPidlList::PruneKids(LPCITEMIDLIST pidl)
|
||||||
return E_NOTIMPL;
|
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(dwUnused1);
|
||||||
UNREFERENCED_PARAMETER(dwUnused3);
|
UNREFERENCED_PARAMETER(dwUnused3);
|
||||||
|
|
||||||
|
TRACE("%p %p %p\n", dwUnused1, ppv, dwUnused3);
|
||||||
|
|
||||||
|
if (!ppv)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
*ppv = NULL;
|
*ppv = NULL;
|
||||||
|
|
||||||
CMruPidlList *pMruList = new CMruPidlList();
|
CMruPidlList *pMruList = new CMruPidlList();
|
||||||
|
@ -638,5 +884,99 @@ EXTERN_C HRESULT CMruPidlList_CreateInstance(DWORD dwUnused1, void **ppv, DWORD
|
||||||
return E_OUTOFMEMORY;
|
return E_OUTOFMEMORY;
|
||||||
|
|
||||||
*ppv = static_cast<IMruPidlList*>(pMruList);
|
*ppv = static_cast<IMruPidlList*>(pMruList);
|
||||||
|
TRACE("%p\n", *ppv);
|
||||||
return S_OK;
|
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
|
* 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;
|
extern LONG SHDOCVW_refCount DECLSPEC_HIDDEN;
|
||||||
|
#endif
|
||||||
static inline void SHDOCVW_LockModule(void) { InterlockedIncrement( &SHDOCVW_refCount ); }
|
static inline void SHDOCVW_LockModule(void) { InterlockedIncrement( &SHDOCVW_refCount ); }
|
||||||
static inline void SHDOCVW_UnlockModule(void) { InterlockedDecrement( &SHDOCVW_refCount ); }
|
static inline void SHDOCVW_UnlockModule(void) { InterlockedDecrement( &SHDOCVW_refCount ); }
|
||||||
|
|
||||||
#ifdef __REACTOS__
|
#ifdef __REACTOS__
|
||||||
EXTERN_C HRESULT CMruLongList_CreateInstance(DWORD dwUnused1, void **ppv, DWORD dwUnused3);
|
EXTERN_C HRESULT CMruLongList_CreateInstance(DWORD_PTR dwUnused1, void **ppv, DWORD_PTR dwUnused3);
|
||||||
EXTERN_C HRESULT CMruPidlList_CreateInstance(DWORD dwUnused1, void **ppv, DWORD dwUnused3);
|
EXTERN_C HRESULT CMruClassFactory_CreateInstance(REFIID riid, void **ppv);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* __WINE_SHDOCVW_H */
|
#endif /* __WINE_SHDOCVW_H */
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#ifdef __REACTOS__
|
#ifdef __REACTOS__
|
||||||
#include "winnls.h"
|
#include "winnls.h"
|
||||||
#include <shlguid_undoc.h>
|
#include <shlguid_undoc.h>
|
||||||
|
#include <rpcproxy.h> /* for __wine_register_resources / __wine_unregister_resources */
|
||||||
#endif
|
#endif
|
||||||
#include "shlwapi.h"
|
#include "shlwapi.h"
|
||||||
#include "wininet.h"
|
#include "wininet.h"
|
||||||
|
@ -44,6 +45,9 @@ LONG SHDOCVW_refCount = 0;
|
||||||
|
|
||||||
static HMODULE SHDOCVW_hshell32 = 0;
|
static HMODULE SHDOCVW_hshell32 = 0;
|
||||||
static HINSTANCE ieframe_instance;
|
static HINSTANCE ieframe_instance;
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
static HINSTANCE instance;
|
||||||
|
#endif
|
||||||
|
|
||||||
static HINSTANCE get_ieframe_instance(void)
|
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);
|
return get_ieframe_object(rclsid, riid, ppv);
|
||||||
|
|
||||||
#ifdef __REACTOS__
|
#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);
|
return CMruLongList_CreateInstance(0, ppv, 0);
|
||||||
if (IsEqualGUID(&CLSID_MruPidlList, rclsid))
|
}
|
||||||
return CMruPidlList_CreateInstance(0, ppv, 0);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* As a last resort, figure if the CLSID belongs to a 'Shell Instance Object' */
|
/* 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)
|
HRESULT WINAPI DllRegisterServer(void)
|
||||||
{
|
{
|
||||||
TRACE("\n");
|
TRACE("\n");
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
return __wine_register_resources(instance);
|
||||||
|
#else
|
||||||
return S_OK;
|
return S_OK;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
|
@ -114,7 +130,11 @@ HRESULT WINAPI DllRegisterServer(void)
|
||||||
HRESULT WINAPI DllUnregisterServer(void)
|
HRESULT WINAPI DllUnregisterServer(void)
|
||||||
{
|
{
|
||||||
TRACE("\n");
|
TRACE("\n");
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
return __wine_unregister_resources(instance);
|
||||||
|
#else
|
||||||
return S_OK;
|
return S_OK;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
|
@ -155,6 +175,9 @@ BOOL WINAPI DllMain(HINSTANCE hinst, DWORD fdwReason, LPVOID fImpLoad)
|
||||||
switch (fdwReason)
|
switch (fdwReason)
|
||||||
{
|
{
|
||||||
case DLL_PROCESS_ATTACH:
|
case DLL_PROCESS_ATTACH:
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
instance = hinst;
|
||||||
|
#endif
|
||||||
DisableThreadLibraryCalls(hinst);
|
DisableThreadLibraryCalls(hinst);
|
||||||
break;
|
break;
|
||||||
case DLL_PROCESS_DETACH:
|
case DLL_PROCESS_DETACH:
|
||||||
|
|
|
@ -199,6 +199,10 @@ HKCR
|
||||||
Version = s '1.1'
|
Version = s '1.1'
|
||||||
VersionIndependentProgId = s 'SearchAssistantOC.SearchAssistantOC'
|
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'
|
'Shell.Explorer.1' = s 'Microsoft Web Browser Version 1'
|
||||||
{
|
{
|
||||||
|
|
|
@ -43,6 +43,7 @@ add_subdirectory(powrprof)
|
||||||
add_subdirectory(sdk)
|
add_subdirectory(sdk)
|
||||||
add_subdirectory(setupapi)
|
add_subdirectory(setupapi)
|
||||||
add_subdirectory(sfc)
|
add_subdirectory(sfc)
|
||||||
|
add_subdirectory(shdocvw)
|
||||||
add_subdirectory(shell32)
|
add_subdirectory(shell32)
|
||||||
add_subdirectory(shlwapi)
|
add_subdirectory(shlwapi)
|
||||||
add_subdirectory(spoolss)
|
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…
Add table
Add a link
Reference in a new issue