Skip to content

Commit

Permalink
[SHDOCVW][SHDOCVW_APITEST] Implement MRU List for Shell Bag, Part 3 (r…
Browse files Browse the repository at this point in the history
…eactos#5646)

Follow-up to reactos#5634.
- Implement CMruBase::_UseEmptySlot.
- Implement CMruLongList and CMruShortList.
- Add CMruClassFactory class and modify
  DllGetClassObject function by using it.
- Add shdocvw_apitest.exe.
CORE-9283
  • Loading branch information
katahiromz authored Sep 11, 2023
1 parent 2a16fc5 commit 1961d70
Show file tree
Hide file tree
Showing 8 changed files with 675 additions and 28 deletions.
386 changes: 363 additions & 23 deletions dll/win32/shdocvw/mrulist.cpp

Large diffs are not rendered by default.

13 changes: 11 additions & 2 deletions dll/win32/shdocvw/shdocvw.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
29 changes: 26 additions & 3 deletions dll/win32/shdocvw/shdocvw_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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)
{
Expand Down Expand Up @@ -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' */
Expand All @@ -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
}

/***********************************************************************
Expand All @@ -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
}

/******************************************************************
Expand Down Expand Up @@ -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:
Expand Down
4 changes: 4 additions & 0 deletions dll/win32/shdocvw/shdocvw_v1.rgs
Original file line number Diff line number Diff line change
Expand Up @@ -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'
{
Expand Down
1 change: 1 addition & 0 deletions modules/rostests/apitests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
10 changes: 10 additions & 0 deletions modules/rostests/apitests/shdocvw/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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 changes: 250 additions & 0 deletions modules/rostests/apitests/shdocvw/MRUList.cpp
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>
*/

#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 changes: 10 additions & 0 deletions modules/rostests/apitests/shdocvw/testlist.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#define STANDALONE
#include <apitest.h>

extern void func_MRUList(void);

const struct test winetest_testlist[] =
{
{ "MRUList", func_MRUList },
{ 0, 0 }
};

0 comments on commit 1961d70

Please sign in to comment.