mirror of
https://github.com/reactos/reactos.git
synced 2025-05-29 22:18:13 +00:00
[SDK][SDK_APITEST] Improve delayload support CORE-10935
- Add an apitest for our delayload functions. - Improve the delayload (mainly the failure cases, throw exceptions where expected etc). - Add some tests for advanced delayload features (currently blocked on CORE-6504 and CORE-10957) svn path=/trunk/; revision=71190
This commit is contained in:
parent
8c386bbbcc
commit
91d86a9a91
7 changed files with 700 additions and 64 deletions
|
@ -6,6 +6,17 @@
|
||||||
#define __ImageBase _image_base__
|
#define __ImageBase _image_base__
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
#define ExternC extern "C"
|
||||||
|
#else
|
||||||
|
#define ExternC extern
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FACILITY_VISUALCPP
|
||||||
|
#define FACILITY_VISUALCPP ((LONG)0x6d)
|
||||||
|
#endif
|
||||||
|
#define VcppException(sev,err) ((sev) | (FACILITY_VISUALCPP<<16) | err)
|
||||||
|
|
||||||
#define DELAYLOAD_VERSION 0x200
|
#define DELAYLOAD_VERSION 0x200
|
||||||
|
|
||||||
typedef DWORD RVA;
|
typedef DWORD RVA;
|
||||||
|
@ -65,24 +76,8 @@ typedef struct DelayLoadInfo
|
||||||
|
|
||||||
typedef FARPROC (WINAPI *PfnDliHook)(unsigned, PDelayLoadInfo);
|
typedef FARPROC (WINAPI *PfnDliHook)(unsigned, PDelayLoadInfo);
|
||||||
|
|
||||||
FORCEINLINE
|
|
||||||
unsigned
|
|
||||||
IndexFromPImgThunkData(PCImgThunkData pData, PCImgThunkData pBase)
|
|
||||||
{
|
|
||||||
return pData - pBase;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern const IMAGE_DOS_HEADER __ImageBase;
|
ExternC PfnDliHook __pfnDliNotifyHook2;
|
||||||
|
ExternC PfnDliHook __pfnDliFailureHook2;
|
||||||
FORCEINLINE
|
|
||||||
PVOID
|
|
||||||
PFromRva(RVA rva)
|
|
||||||
{
|
|
||||||
return (PVOID)(((ULONG_PTR)(rva)) + ((ULONG_PTR)&__ImageBase));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
extern PfnDliHook __pfnDliNotifyHook2;
|
|
||||||
extern PfnDliHook __pfnDliFailureHook2;
|
|
||||||
|
|
||||||
#endif /* not _delayimp_h */
|
#endif /* not _delayimp_h */
|
||||||
|
|
|
@ -2,3 +2,4 @@
|
||||||
add_definitions(-DUNICODE -D_UNICODE)
|
add_definitions(-DUNICODE -D_UNICODE)
|
||||||
add_library(delayimp delayimp.c)
|
add_library(delayimp delayimp.c)
|
||||||
add_dependencies(delayimp psdk)
|
add_dependencies(delayimp psdk)
|
||||||
|
add_importlibs(delayimp kernel32)
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
* FILE: lib/sdk/delayimp/delayimp.c
|
* FILE: lib/sdk/delayimp/delayimp.c
|
||||||
* PURPOSE: Library for delay importing from dlls
|
* PURPOSE: Library for delay importing from dlls
|
||||||
* PROGRAMMERS: Timo Kreuzer <timo.kreuzer@reactos.org>
|
* PROGRAMMERS: Timo Kreuzer <timo.kreuzer@reactos.org>
|
||||||
|
* Mark Jansen
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -12,17 +13,55 @@
|
||||||
#include <winbase.h>
|
#include <winbase.h>
|
||||||
#include <delayimp.h>
|
#include <delayimp.h>
|
||||||
|
|
||||||
|
/**** Linker magic: provide a default (NULL) pointer, but allow the user to override it ****/
|
||||||
|
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
PfnDliHook __pfnDliNotifyHook2;
|
||||||
|
PfnDliHook __pfnDliFailureHook2;
|
||||||
|
#else
|
||||||
|
/* The actual items we use */
|
||||||
|
extern PfnDliHook __pfnDliNotifyHook2;
|
||||||
|
extern PfnDliHook __pfnDliFailureHook2;
|
||||||
|
|
||||||
|
/* The fallback symbols */
|
||||||
|
extern PfnDliHook __pfnDliNotifyHook2Default = NULL;
|
||||||
|
extern PfnDliHook __pfnDliFailureHook2Default = NULL;
|
||||||
|
|
||||||
|
/* Tell the linker to use the fallback symbols */
|
||||||
|
#pragma comment(linker, "/alternatename:___pfnDliNotifyHook2=___pfnDliNotifyHook2Default")
|
||||||
|
#pragma comment(linker, "/alternatename:___pfnDliFailureHook2=___pfnDliFailureHook2Default")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**** Helper functions to convert from RVA to address ****/
|
||||||
|
|
||||||
|
FORCEINLINE
|
||||||
|
unsigned
|
||||||
|
IndexFromPImgThunkData(PCImgThunkData pData, PCImgThunkData pBase)
|
||||||
|
{
|
||||||
|
return pData - pBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern const IMAGE_DOS_HEADER __ImageBase;
|
||||||
|
|
||||||
|
FORCEINLINE
|
||||||
|
PVOID
|
||||||
|
PFromRva(RVA rva)
|
||||||
|
{
|
||||||
|
return (PVOID)(((ULONG_PTR)(rva)) + ((ULONG_PTR)&__ImageBase));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**** load helper ****/
|
/**** load helper ****/
|
||||||
|
|
||||||
FARPROC WINAPI
|
FARPROC WINAPI
|
||||||
__delayLoadHelper2(PCImgDelayDescr pidd, PImgThunkData pIATEntry)
|
__delayLoadHelper2(PCImgDelayDescr pidd, PImgThunkData pIATEntry)
|
||||||
{
|
{
|
||||||
DelayLoadInfo dli;
|
DelayLoadInfo dli = {0};
|
||||||
int index;
|
int index;
|
||||||
PImgThunkData pIAT;
|
PImgThunkData pIAT;
|
||||||
PImgThunkData pINT;
|
PImgThunkData pINT;
|
||||||
HMODULE *phMod;
|
HMODULE *phMod;
|
||||||
FARPROC pProc;
|
|
||||||
|
|
||||||
pIAT = PFromRva(pidd->rvaIAT);
|
pIAT = PFromRva(pidd->rvaIAT);
|
||||||
pINT = PFromRva(pidd->rvaINT);
|
pINT = PFromRva(pidd->rvaINT);
|
||||||
|
@ -31,9 +70,9 @@ __delayLoadHelper2(PCImgDelayDescr pidd, PImgThunkData pIATEntry)
|
||||||
|
|
||||||
dli.cb = sizeof(dli);
|
dli.cb = sizeof(dli);
|
||||||
dli.pidd = pidd;
|
dli.pidd = pidd;
|
||||||
dli.ppfn = (FARPROC*)pIATEntry->u1.Function;
|
dli.ppfn = (FARPROC*)&pIAT[index].u1.Function;
|
||||||
dli.szDll = PFromRva(pidd->rvaDLLName);
|
dli.szDll = PFromRva(pidd->rvaDLLName);
|
||||||
dli.dlp.fImportByName = !(pINT[index].u1.Ordinal & IMAGE_ORDINAL_FLAG);
|
dli.dlp.fImportByName = !IMAGE_SNAP_BY_ORDINAL(pINT[index].u1.Ordinal);
|
||||||
if (dli.dlp.fImportByName)
|
if (dli.dlp.fImportByName)
|
||||||
{
|
{
|
||||||
/* u1.AdressOfData points to a IMAGE_IMPORT_BY_NAME struct */
|
/* u1.AdressOfData points to a IMAGE_IMPORT_BY_NAME struct */
|
||||||
|
@ -42,61 +81,80 @@ __delayLoadHelper2(PCImgDelayDescr pidd, PImgThunkData pIATEntry)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dli.dlp.dwOrdinal = pINT[index].u1.Ordinal & ~IMAGE_ORDINAL_FLAG;
|
dli.dlp.dwOrdinal = IMAGE_ORDINAL(pINT[index].u1.Ordinal);
|
||||||
}
|
}
|
||||||
dli.hmodCur = *phMod;
|
|
||||||
dli.pfnCur = (FARPROC)pIAT[index].u1.Function;
|
if (__pfnDliNotifyHook2)
|
||||||
dli.dwLastError = GetLastError();
|
|
||||||
pProc = __pfnDliNotifyHook2(dliStartProcessing, &dli);
|
|
||||||
if (pProc)
|
|
||||||
{
|
{
|
||||||
pIAT[index].u1.Function = (DWORD_PTR)pProc;
|
dli.pfnCur = __pfnDliNotifyHook2(dliStartProcessing, &dli);
|
||||||
return pProc;
|
if (dli.pfnCur)
|
||||||
|
{
|
||||||
|
pIAT[index].u1.Function = (DWORD_PTR)dli.pfnCur;
|
||||||
|
if (__pfnDliNotifyHook2)
|
||||||
|
__pfnDliNotifyHook2(dliNoteEndProcessing, &dli);
|
||||||
|
|
||||||
|
return dli.pfnCur;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dli.hmodCur = *phMod;
|
||||||
|
|
||||||
if (dli.hmodCur == NULL)
|
if (dli.hmodCur == NULL)
|
||||||
{
|
{
|
||||||
dli.hmodCur = LoadLibraryA(dli.szDll);
|
if (__pfnDliNotifyHook2)
|
||||||
if (!dli.hmodCur)
|
dli.hmodCur = (HMODULE)__pfnDliNotifyHook2(dliNotePreLoadLibrary, &dli);
|
||||||
|
if (dli.hmodCur == NULL)
|
||||||
{
|
{
|
||||||
dli.dwLastError = GetLastError();
|
dli.hmodCur = LoadLibraryA(dli.szDll);
|
||||||
__pfnDliFailureHook2(dliFailLoadLib, &dli);
|
if (dli.hmodCur == NULL)
|
||||||
// if (ret)
|
{
|
||||||
// {
|
dli.dwLastError = GetLastError();
|
||||||
// }
|
if (__pfnDliFailureHook2)
|
||||||
// FIXME: raise exception;
|
dli.hmodCur = (HMODULE)__pfnDliFailureHook2(dliFailLoadLib, &dli);
|
||||||
return NULL;
|
|
||||||
|
if (dli.hmodCur == NULL)
|
||||||
|
{
|
||||||
|
ULONG_PTR args[] = { (ULONG_PTR)&dli };
|
||||||
|
RaiseException(VcppException(ERROR_SEVERITY_ERROR, ERROR_MOD_NOT_FOUND), 0, 1, args);
|
||||||
|
|
||||||
|
/* If we survive the exception, we are expected to use pfnCur directly.. */
|
||||||
|
return dli.pfnCur;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*phMod = dli.hmodCur;
|
*phMod = dli.hmodCur;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* dli.dlp.szProcName might also contain the ordinal */
|
dli.dwLastError = ERROR_SUCCESS;
|
||||||
pProc = GetProcAddress(dli.hmodCur, dli.dlp.szProcName);
|
|
||||||
if (!pProc)
|
if (__pfnDliNotifyHook2)
|
||||||
|
dli.pfnCur = (FARPROC)__pfnDliNotifyHook2(dliNotePreGetProcAddress, &dli);
|
||||||
|
if (dli.pfnCur == NULL)
|
||||||
{
|
{
|
||||||
dli.dwLastError = GetLastError();
|
/* dli.dlp.szProcName might also contain the ordinal */
|
||||||
__pfnDliFailureHook2(dliFailGetProc, &dli);
|
dli.pfnCur = GetProcAddress(dli.hmodCur, dli.dlp.szProcName);
|
||||||
// FIXME: handle return value & raise exception
|
if (dli.pfnCur == NULL)
|
||||||
return NULL;
|
{
|
||||||
|
dli.dwLastError = GetLastError();
|
||||||
|
if (__pfnDliFailureHook2)
|
||||||
|
dli.pfnCur = __pfnDliFailureHook2(dliFailGetProc, &dli);
|
||||||
|
|
||||||
|
if (dli.pfnCur == NULL)
|
||||||
|
{
|
||||||
|
ULONG_PTR args[] = { (ULONG_PTR)&dli };
|
||||||
|
RaiseException(VcppException(ERROR_SEVERITY_ERROR, ERROR_PROC_NOT_FOUND), 0, 1, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
//return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pIAT[index].u1.Function = (DWORD_PTR)pProc;
|
|
||||||
|
|
||||||
return pProc;
|
pIAT[index].u1.Function = (DWORD_PTR)dli.pfnCur;
|
||||||
|
dli.dwLastError = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
if (__pfnDliNotifyHook2)
|
||||||
|
__pfnDliNotifyHook2(dliNoteEndProcessing, &dli);
|
||||||
|
|
||||||
|
return dli.pfnCur;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** The default hooks ***/
|
|
||||||
|
|
||||||
FARPROC WINAPI
|
|
||||||
DefaultDliNotifyHook2(unsigned dliNotify, PDelayLoadInfo pdli)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
FARPROC WINAPI
|
|
||||||
DefaultDliFailureHook2(unsigned dliNotify, PDelayLoadInfo pdli)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
PfnDliHook __pfnDliNotifyHook2 = DefaultDliNotifyHook2;
|
|
||||||
PfnDliHook __pfnDliFailureHook2 = DefaultDliFailureHook2;
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ add_subdirectory(ntdll)
|
||||||
add_subdirectory(ole32)
|
add_subdirectory(ole32)
|
||||||
add_subdirectory(pefile)
|
add_subdirectory(pefile)
|
||||||
add_subdirectory(powrprof)
|
add_subdirectory(powrprof)
|
||||||
|
add_subdirectory(sdk)
|
||||||
add_subdirectory(setupapi)
|
add_subdirectory(setupapi)
|
||||||
add_subdirectory(shell32)
|
add_subdirectory(shell32)
|
||||||
add_subdirectory(psapi)
|
add_subdirectory(psapi)
|
||||||
|
|
7
rostests/apitests/sdk/CMakeLists.txt
Normal file
7
rostests/apitests/sdk/CMakeLists.txt
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
add_executable(sdk_apitest delayimp.cpp testlist.c)
|
||||||
|
set_module_type(sdk_apitest win32cui)
|
||||||
|
target_link_libraries(sdk_apitest ${PSEH_LIB})
|
||||||
|
add_importlibs(sdk_apitest msvcrt kernel32 ntdll)
|
||||||
|
add_delay_importlibs(sdk_apitest winmm version dbghelp shlwapi sfc_os imagehlp)
|
||||||
|
add_cd_file(TARGET sdk_apitest DESTINATION reactos/bin FOR all)
|
562
rostests/apitests/sdk/delayimp.cpp
Normal file
562
rostests/apitests/sdk/delayimp.cpp
Normal file
|
@ -0,0 +1,562 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS API tests
|
||||||
|
* LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory
|
||||||
|
* PURPOSE: Tests for delayload
|
||||||
|
* PROGRAMMER: Mark Jansen
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <apitest.h>
|
||||||
|
|
||||||
|
#include <apitest.h>
|
||||||
|
#include <strsafe.h>
|
||||||
|
#include <delayimp.h>
|
||||||
|
|
||||||
|
/* Some libraries to test against */
|
||||||
|
#include <mmsystem.h>
|
||||||
|
#include <winver.h>
|
||||||
|
#include <shlwapi.h>
|
||||||
|
#include <intshcut.h>
|
||||||
|
#include <sfc.h>
|
||||||
|
#include <imagehlp.h>
|
||||||
|
|
||||||
|
/* Compatibility with the MS defines */
|
||||||
|
|
||||||
|
#ifndef FACILITY_VISUALCPP
|
||||||
|
#define FACILITY_VISUALCPP ((LONG)0x6d)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef VcppException
|
||||||
|
#define VcppException(sev,err) ((sev) | (FACILITY_VISUALCPP<<16) | err)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
#define WINMM_DLLNAME "winmm.dll"
|
||||||
|
#else
|
||||||
|
#define WINMM_DLLNAME "WINMM.dll"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool g_BreakFunctionName = false;
|
||||||
|
bool g_BrokenFunctionName = false;
|
||||||
|
bool g_BypassMost = false;
|
||||||
|
bool g_ExceptionIsModule = false;
|
||||||
|
bool g_ImportByName = true;
|
||||||
|
const char* g_ExpectedDll = NULL;
|
||||||
|
const char* g_ExpectedName = NULL;
|
||||||
|
char g_Target[100] = { 0 };
|
||||||
|
|
||||||
|
char* target(PDelayLoadInfo pdli)
|
||||||
|
{
|
||||||
|
if (g_Target[0] == '\0' && pdli)
|
||||||
|
{
|
||||||
|
if (pdli->dlp.fImportByName)
|
||||||
|
sprintf(g_Target, "%s!%s", pdli->szDll, pdli->dlp.szProcName);
|
||||||
|
else
|
||||||
|
sprintf(g_Target, "%s!#%lu", pdli->szDll, pdli->dlp.dwOrdinal);
|
||||||
|
}
|
||||||
|
return g_Target;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct UnProtect
|
||||||
|
{
|
||||||
|
UnProtect(PVOID addr)
|
||||||
|
:mAddr(NULL), mProt(0)
|
||||||
|
{
|
||||||
|
if (IsBadWritePtr(addr, 1))
|
||||||
|
{
|
||||||
|
mAddr = addr;
|
||||||
|
VirtualProtect(addr, 1, PAGE_EXECUTE_READWRITE, &mProt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
~UnProtect()
|
||||||
|
{
|
||||||
|
DWORD dwOld;
|
||||||
|
if (mAddr)
|
||||||
|
VirtualProtect(mAddr, 1, mProt, &dwOld);
|
||||||
|
}
|
||||||
|
|
||||||
|
PVOID mAddr;
|
||||||
|
DWORD mProt;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
unsigned* g_DliHookExpected = NULL;
|
||||||
|
size_t g_DliHookIndex = 0;
|
||||||
|
#define LAST_DLI 333
|
||||||
|
|
||||||
|
static void SetExpectedDli(unsigned* order)
|
||||||
|
{
|
||||||
|
g_DliHookExpected = order;
|
||||||
|
g_DliHookIndex = 0;
|
||||||
|
g_Target[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CheckDli_imp(unsigned dliNotify, PDelayLoadInfo pdli, BOOL ErrorHandler)
|
||||||
|
{
|
||||||
|
if (!g_DliHookExpected) return;
|
||||||
|
|
||||||
|
winetest_ok(dliNotify == g_DliHookExpected[g_DliHookIndex], "Expected dliNotify to be %u, was: %u for %s\n",
|
||||||
|
g_DliHookExpected[g_DliHookIndex], dliNotify, target(pdli));
|
||||||
|
if (ErrorHandler)
|
||||||
|
{
|
||||||
|
winetest_ok(dliNotify == dliFailGetProc || dliNotify == dliFailLoadLib,
|
||||||
|
"Expected code %u to be processed by the Hook, not the ErrorHandler for %s\n", dliNotify, target(pdli));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
winetest_ok(dliNotify == dliStartProcessing || dliNotify == dliNotePreLoadLibrary ||
|
||||||
|
dliNotify == dliNotePreGetProcAddress || dliNotify == dliNoteEndProcessing,
|
||||||
|
"Expected code %u to be processed by the ErrorHandler, not the Hook for %s\n", dliNotify, target(pdli));
|
||||||
|
}
|
||||||
|
if (g_DliHookExpected[g_DliHookIndex] != LAST_DLI)
|
||||||
|
g_DliHookIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CheckDliDone_imp()
|
||||||
|
{
|
||||||
|
if (!g_DliHookExpected) return;
|
||||||
|
winetest_ok(LAST_DLI == g_DliHookExpected[g_DliHookIndex],
|
||||||
|
"Expected g_DliHookExpected[g_DliHookIndex] to be %u, was: %u for %s\n",
|
||||||
|
LAST_DLI, g_DliHookExpected[g_DliHookIndex], target(NULL));
|
||||||
|
g_DliHookExpected = NULL;
|
||||||
|
g_Target[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CheckDli (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : CheckDli_imp
|
||||||
|
#define CheckDliDone (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : CheckDliDone_imp
|
||||||
|
|
||||||
|
|
||||||
|
/* Replacement functions */
|
||||||
|
int __stdcall MyFunction()
|
||||||
|
{
|
||||||
|
return 123;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL WINAPI MySfcIsKeyProtected(HKEY KeyHandle, LPCWSTR SubKeyName, REGSAM KeySam)
|
||||||
|
{
|
||||||
|
return 12345;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static HMODULE g_VersionDll;
|
||||||
|
FARPROC WINAPI DliHook(unsigned dliNotify, PDelayLoadInfo pdli)
|
||||||
|
{
|
||||||
|
ok(pdli && pdli->cb >= 36, "Expected a valid pointer with a struct that is big enough: %p, %lu\n",
|
||||||
|
pdli, pdli ? pdli->cb : 0u);
|
||||||
|
if (!pdli || pdli->cb < 36) return NULL;
|
||||||
|
|
||||||
|
CheckDli(dliNotify, pdli, FALSE);
|
||||||
|
|
||||||
|
if (g_BreakFunctionName && pdli->dlp.fImportByName)
|
||||||
|
{
|
||||||
|
g_BreakFunctionName = false;
|
||||||
|
g_BrokenFunctionName = true;
|
||||||
|
char* procname = (char*)pdli->dlp.szProcName;
|
||||||
|
UnProtect prot(procname);
|
||||||
|
char c = procname[0];
|
||||||
|
procname[0] = isupper(c) ? tolower(c) : toupper(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Validate dll name when required */
|
||||||
|
if (g_ExpectedDll && g_ExpectedName && !g_BrokenFunctionName)
|
||||||
|
{
|
||||||
|
ok(!strcmp(g_ExpectedDll, pdli->szDll), "Expected szDll to be '%s', but was: '%s'\n", g_ExpectedDll, pdli->szDll);
|
||||||
|
ok(pdli->dlp.fImportByName, "Expected import by name (%s!%s)\n", g_ExpectedDll, g_ExpectedName);
|
||||||
|
if (pdli->dlp.fImportByName)
|
||||||
|
{
|
||||||
|
ok(!strcmp(g_ExpectedName, pdli->dlp.szProcName), "Expected szProcName to be '%s', but was: '%s'\n",
|
||||||
|
g_ExpectedName, pdli->dlp.szProcName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (dliNotify == dliStartProcessing)
|
||||||
|
{
|
||||||
|
/* Test loadlib fail */
|
||||||
|
if (!_stricmp(pdli->szDll, "sfc_os.dll"))
|
||||||
|
{
|
||||||
|
char* dll = (char*)pdli->szDll;
|
||||||
|
UnProtect u(dll);
|
||||||
|
dll[0] = 'l'; dll[1] = '_'; dll[2] = 'm';
|
||||||
|
}
|
||||||
|
if (!_stricmp(pdli->szDll, "imagehlp.dll"))
|
||||||
|
{
|
||||||
|
char* dll = (char*)pdli->szDll;
|
||||||
|
UnProtect u(dll);
|
||||||
|
dll[0] = 'x'; dll[1] = 'x'; dll[2] = 'x'; dll[3] = 'x'; dll[4] = 'x';
|
||||||
|
}
|
||||||
|
/* Test bypass */
|
||||||
|
if (!_stricmp(pdli->szDll, "dbghelp.dll"))
|
||||||
|
return MyFunction;
|
||||||
|
}
|
||||||
|
else if (dliNotify == dliNotePreLoadLibrary)
|
||||||
|
{
|
||||||
|
/* Show that this value is actually used! */
|
||||||
|
if (!_stricmp(pdli->szDll, "version.dll"))
|
||||||
|
{
|
||||||
|
g_VersionDll = LoadLibraryA("version.dll");
|
||||||
|
return (FARPROC)1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (dliNotify == dliNotePreGetProcAddress)
|
||||||
|
{
|
||||||
|
if (pdli->dlp.fImportByName && !strcmp(pdli->dlp.szProcName, "SfcIsKeyProtected"))
|
||||||
|
{
|
||||||
|
return (FARPROC)MySfcIsKeyProtected;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parameter validation */
|
||||||
|
ok(pdli->ppfn != NULL, "Expected ppfn to be valid, was NULL for %s\n", target(pdli));
|
||||||
|
ok(pdli->szDll != NULL, "Expected szDll to be valid, was NULL for %s\n", target(pdli));
|
||||||
|
ok(pdli->dwLastError == ERROR_SUCCESS,
|
||||||
|
"Expected dwLastError to be ERROR_SUCCESS, was: %lu for %s\n", pdli->dwLastError, target(pdli));
|
||||||
|
ok(g_ImportByName == !!pdli->dlp.fImportByName, "Expected pdli->dlp.fImportByName to equal g_ImportByname\n");
|
||||||
|
if (pdli->dlp.fImportByName)
|
||||||
|
ok(pdli->dlp.szProcName != NULL, "Expected szProcName to be valid, was NULL for %s\n", target(pdli));
|
||||||
|
else
|
||||||
|
ok(pdli->dlp.dwOrdinal != 0, "Expected dwOrdinal to be valid, was NULL for %s\n", target(pdli));
|
||||||
|
switch(dliNotify)
|
||||||
|
{
|
||||||
|
case dliStartProcessing:
|
||||||
|
ok(pdli->hmodCur == NULL, "Expected hmodCur to be NULL, was: %p for %s\n", pdli->hmodCur, target(pdli));
|
||||||
|
ok(pdli->pfnCur == NULL, "Expected pfnCur to be NULL, was: %p for %s\n", pdli->pfnCur, target(pdli));
|
||||||
|
break;
|
||||||
|
case dliNotePreLoadLibrary:
|
||||||
|
ok(pdli->hmodCur == NULL, "Expected hmodCur to be NULL, was: %p for %s\n", pdli->hmodCur, target(pdli));
|
||||||
|
ok(pdli->pfnCur == NULL, "Expected pfnCur to be NULL, was: %p for %s\n", pdli->pfnCur, target(pdli));
|
||||||
|
break;
|
||||||
|
case dliNotePreGetProcAddress:
|
||||||
|
ok(pdli->hmodCur != NULL, "Expected hmodCur to be valid, was NULL for %s\n", target(pdli));
|
||||||
|
ok(pdli->pfnCur == NULL, "Expected pfnCur to be NULL, was: %p for %s\n", pdli->pfnCur, target(pdli));
|
||||||
|
break;
|
||||||
|
case dliNoteEndProcessing:
|
||||||
|
if (!g_BypassMost)
|
||||||
|
ok(pdli->hmodCur != NULL, "Expected hmodCur to be valid, was NULL for %s\n", target(pdli));
|
||||||
|
ok(pdli->pfnCur != NULL, "Expected pfnCur to be a valid pointer, was NULL for %s\n", target(pdli));
|
||||||
|
if (g_ExpectedDll && g_ExpectedName && !g_BrokenFunctionName)
|
||||||
|
{
|
||||||
|
FARPROC targetProc = GetProcAddress(GetModuleHandleA(g_ExpectedDll), g_ExpectedName);
|
||||||
|
ok(targetProc != NULL, "This should not happen, the function i need is unavail! (%s!%s)\n",
|
||||||
|
g_ExpectedDll, g_ExpectedName);
|
||||||
|
ok(targetProc == pdli->pfnCur, "Expected pfnCur to be %p, was %p for %s\n", targetProc, pdli->pfnCur, target(pdli));
|
||||||
|
ok(pdli->ppfn && targetProc == *pdli->ppfn,
|
||||||
|
"Expected ppfn to be valid and to result in %p, was: %p(%p) for %s\n",
|
||||||
|
target, pdli->ppfn, pdli->ppfn ? *pdli->ppfn : NULL, target(pdli));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
FARPROC WINAPI DliFailHook(unsigned dliNotify, PDelayLoadInfo pdli)
|
||||||
|
{
|
||||||
|
ok(pdli && pdli->cb >= 36,
|
||||||
|
"Expected a valid pointer with a struct that is big enough: %p, %lu\n", pdli, pdli ? pdli->cb : 0u);
|
||||||
|
if (!pdli || pdli->cb < 36) return NULL;
|
||||||
|
|
||||||
|
CheckDli(dliNotify, pdli, TRUE);
|
||||||
|
|
||||||
|
/* Redirections / fixes */
|
||||||
|
if (dliNotify == dliFailLoadLib)
|
||||||
|
{
|
||||||
|
if (!_stricmp(pdli->szDll, "l_m_os.dll"))
|
||||||
|
return (FARPROC)LoadLibraryA("sfc_os.dll");
|
||||||
|
}
|
||||||
|
else if (dliNotify == dliFailGetProc)
|
||||||
|
{
|
||||||
|
if (pdli->dlp.fImportByName && pdli->hmodCur == (HMODULE)1)
|
||||||
|
{
|
||||||
|
return GetProcAddress(g_VersionDll, pdli->dlp.szProcName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parameter validation */
|
||||||
|
ok(pdli->ppfn != NULL, "Expected ppfn to be valid, was NULL for %s\n", target(pdli));
|
||||||
|
ok(pdli->szDll != NULL, "Expected szDll to be valid, was NULL for %s\n", target(pdli));
|
||||||
|
if (pdli->dlp.fImportByName)
|
||||||
|
ok(pdli->dlp.szProcName != NULL, "Expected szProcName to be valid, was NULL for %s\n", target(pdli));
|
||||||
|
else
|
||||||
|
ok(pdli->dlp.dwOrdinal != 0, "Expected dwOrdinal to be valid, was NULL for %s\n", target(pdli));
|
||||||
|
switch(dliNotify)
|
||||||
|
{
|
||||||
|
case dliFailLoadLib:
|
||||||
|
ok(pdli->hmodCur == NULL, "Expected hmodCur to be NULL, was: %p for %s\n", pdli->hmodCur, target(pdli));
|
||||||
|
ok(pdli->pfnCur == NULL, "Expected pfnCur to be NULL, was: %p for %s\n", pdli->pfnCur, target(pdli));
|
||||||
|
ok(pdli->dwLastError == ERROR_MOD_NOT_FOUND,
|
||||||
|
"Expected dwLastError to be ERROR_MOD_NOT_FOUND, was: %lu for %s\n", pdli->dwLastError, target(pdli));
|
||||||
|
break;
|
||||||
|
case dliFailGetProc:
|
||||||
|
ok(pdli->hmodCur != NULL, "Expected hmodCur to be valid, was NULL for %s\n", target(pdli));
|
||||||
|
ok(pdli->pfnCur == NULL, "Expected pfnCur to be NULL, was: %p for %s\n", pdli->pfnCur, target(pdli));
|
||||||
|
ok(pdli->dwLastError == ERROR_PROC_NOT_FOUND,
|
||||||
|
"Expected dwLastError to be ERROR_PROC_NOT_FOUND, was: %lu for %s\n", pdli->dwLastError, target(pdli));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LONG ExceptionFilter(IN PEXCEPTION_POINTERS ExceptionInfo, ULONG ExceptionCode)
|
||||||
|
{
|
||||||
|
DWORD expected = VcppException(ERROR_SEVERITY_ERROR, (g_ExceptionIsModule ? ERROR_MOD_NOT_FOUND : ERROR_PROC_NOT_FOUND));
|
||||||
|
ok(ExceptionCode == expected, "Expected code to be 0x%lx, was: 0x%lx\n", expected, ExceptionCode);
|
||||||
|
ok(ExceptionInfo != NULL, "Expected to get exception info\n");
|
||||||
|
ok(ExceptionInfo->ExceptionRecord != NULL, "Expected to get a valid record info\n");
|
||||||
|
|
||||||
|
if (ExceptionCode != expected)
|
||||||
|
{
|
||||||
|
skip("Skipping other checks, this was not the exception we expected!\n");
|
||||||
|
return EXCEPTION_EXECUTE_HANDLER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ExceptionInfo && ExceptionInfo->ExceptionRecord)
|
||||||
|
{
|
||||||
|
PEXCEPTION_RECORD ExceptionRecord = ExceptionInfo->ExceptionRecord;
|
||||||
|
ok(ExceptionRecord->ExceptionCode == expected, "Expected ExceptionCode to be 0x%lx, was 0x%lx\n",
|
||||||
|
expected, ExceptionRecord->ExceptionCode);
|
||||||
|
/* We can still continue. */
|
||||||
|
ok(ExceptionRecord->ExceptionFlags == 0, "Expected ExceptionFlags to be 0, was: 0x%lx\n",
|
||||||
|
ExceptionRecord->ExceptionFlags);
|
||||||
|
ok(ExceptionRecord->NumberParameters == 1, "Expected 1 parameter, got %lu\n",
|
||||||
|
ExceptionRecord->NumberParameters);
|
||||||
|
if (ExceptionRecord->NumberParameters == 1)
|
||||||
|
{
|
||||||
|
PDelayLoadInfo LoadInfo = (PDelayLoadInfo)ExceptionRecord->ExceptionInformation[0];
|
||||||
|
ok(LoadInfo && LoadInfo->cb >= 36, "Expected a valid pointer with a struct that is big enough: %p, %lu\n",
|
||||||
|
LoadInfo, LoadInfo ? LoadInfo->cb : 0);
|
||||||
|
|
||||||
|
if (g_ExpectedDll)
|
||||||
|
ok(!strcmp(g_ExpectedDll, LoadInfo->szDll), "Expected szDll to be '%s', but was: '%s'\n",
|
||||||
|
g_ExpectedDll, LoadInfo->szDll);
|
||||||
|
if (g_ExpectedName)
|
||||||
|
{
|
||||||
|
ok(LoadInfo->dlp.fImportByName, "Expected import by name\n");
|
||||||
|
if (LoadInfo->dlp.fImportByName)
|
||||||
|
{
|
||||||
|
ok(!strcmp(g_ExpectedName, LoadInfo->dlp.szProcName),
|
||||||
|
"Expected szProcName to be '%s', but was: '%s'\n", g_ExpectedName, LoadInfo->dlp.szProcName);
|
||||||
|
|
||||||
|
if (g_ExceptionIsModule)
|
||||||
|
{
|
||||||
|
HMODULE mod = LoadLibraryA("imagehlp.dll");
|
||||||
|
LoadInfo->pfnCur = GetProcAddress(mod, g_ExpectedName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char buf[100];
|
||||||
|
char first = isupper(g_ExpectedName[0]) ? tolower(g_ExpectedName[0]) : toupper(g_ExpectedName[0]);
|
||||||
|
sprintf(buf, "%c%s", first, g_ExpectedName + 1);
|
||||||
|
LoadInfo->pfnCur = GetProcAddress(GetModuleHandleA(g_ExpectedDll), buf);
|
||||||
|
}
|
||||||
|
return LoadInfo->pfnCur ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXCEPTION_EXECUTE_HANDLER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We register one hook the 'default' way and one manually,
|
||||||
|
so that we can check that both fallback and registration work*/
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
PfnDliHook __pfnDliNotifyHook2 = DliHook;
|
||||||
|
//PfnDliHook __pfnDliFailureHook2 = DliFailHook;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool g_UsePointers = false;
|
||||||
|
|
||||||
|
template<typename PTR>
|
||||||
|
PTR Rva2Addr(PIMAGE_DOS_HEADER dos, RVA rva)
|
||||||
|
{
|
||||||
|
/* Old delayload type */
|
||||||
|
if (g_UsePointers)
|
||||||
|
return reinterpret_cast<PTR>(rva);
|
||||||
|
return reinterpret_cast<PTR>((reinterpret_cast<PBYTE>(dos) + rva));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned g_winmm_snd_play_a[] = { dliStartProcessing, dliNotePreLoadLibrary, dliNotePreGetProcAddress, dliNoteEndProcessing, LAST_DLI };
|
||||||
|
unsigned g_winmm_snd_play_w[] = { dliStartProcessing, dliNotePreGetProcAddress, dliNoteEndProcessing, LAST_DLI };
|
||||||
|
unsigned g_winmm_play_w[] = { dliStartProcessing, dliNotePreGetProcAddress, dliFailGetProc, dliNoteEndProcessing, LAST_DLI };
|
||||||
|
unsigned g_sfc_key[] = { dliStartProcessing, dliNotePreLoadLibrary, dliFailLoadLib, dliNotePreGetProcAddress, dliNoteEndProcessing, LAST_DLI };
|
||||||
|
unsigned g_sfc_file[] = { dliStartProcessing, dliNotePreGetProcAddress, dliNoteEndProcessing, LAST_DLI };
|
||||||
|
unsigned g_version_a[] = { dliStartProcessing, dliNotePreLoadLibrary, dliNotePreGetProcAddress, dliFailGetProc, dliNoteEndProcessing, LAST_DLI };
|
||||||
|
unsigned g_version_w[] = { dliStartProcessing, dliNotePreGetProcAddress, dliFailGetProc, dliNoteEndProcessing, LAST_DLI };
|
||||||
|
unsigned g_scard[] = { dliStartProcessing, dliNoteEndProcessing, LAST_DLI };
|
||||||
|
unsigned g_shlwapi[] = { dliStartProcessing, dliNotePreLoadLibrary, dliNotePreGetProcAddress, dliNoteEndProcessing, LAST_DLI };
|
||||||
|
unsigned g_imagehlp[] = { dliStartProcessing, dliNotePreLoadLibrary, dliFailLoadLib, LAST_DLI }; /* This exception does not fire EndProcessing! */
|
||||||
|
|
||||||
|
|
||||||
|
//#define DELAYLOAD_SUPPORTS_UNLOADING
|
||||||
|
START_TEST(delayimp)
|
||||||
|
{
|
||||||
|
/* Verify that both scenario's work */
|
||||||
|
ok(__pfnDliNotifyHook2 == DliHook, "Expected __pfnDliNotifyHook2 to be DliHook(%p), but was: %p\n",
|
||||||
|
DliHook, __pfnDliNotifyHook2);
|
||||||
|
ok(__pfnDliFailureHook2 == NULL, "Expected __pfnDliFailureHook2 to be NULL, but was: %p\n",
|
||||||
|
__pfnDliFailureHook2);
|
||||||
|
|
||||||
|
__pfnDliFailureHook2 = DliFailHook;
|
||||||
|
|
||||||
|
|
||||||
|
PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)GetModuleHandle(NULL);
|
||||||
|
|
||||||
|
ok(dos->e_magic == IMAGE_DOS_SIGNATURE, "Expected a DOS header\n");
|
||||||
|
if (dos->e_magic != IMAGE_DOS_SIGNATURE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)((PBYTE)dos + dos->e_lfanew);
|
||||||
|
PIMAGE_DATA_DIRECTORY delaydir = nt->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT;
|
||||||
|
|
||||||
|
/* Test some advanced features (loading / unloading) */
|
||||||
|
if (delaydir->Size != 0)
|
||||||
|
{
|
||||||
|
#if defined(_DELAY_IMP_VER) && _DELAY_IMP_VER == 2 && defined(DELAYLOAD_SUPPORTS_UNLOADING)
|
||||||
|
/* First, before mangling the delayload stuff, let's try some v2 functions */
|
||||||
|
HMODULE mod = GetModuleHandleA(WINMM_DLLNAME);
|
||||||
|
ok(mod == NULL, "Expected mod to be NULL, was %p\n", mod);
|
||||||
|
/* Now, a mistyped module (case sensitive!) */
|
||||||
|
HRESULT hr = __HrLoadAllImportsForDll("WiNmM.DlL");
|
||||||
|
ok(hr == HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND), "Expected hr to be HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND), was %lu\n", hr);
|
||||||
|
mod = GetModuleHandleA(WINMM_DLLNAME);
|
||||||
|
ok(mod == NULL, "Expected mod to be NULL, was %p\n", mod);
|
||||||
|
|
||||||
|
/* Let's load it */
|
||||||
|
hr = __HrLoadAllImportsForDll(WINMM_DLLNAME);
|
||||||
|
ok(hr == S_OK, "Expected hr to be S_OK, was %lu\n", hr);
|
||||||
|
mod = GetModuleHandleA(WINMM_DLLNAME);
|
||||||
|
ok(mod != NULL, "Expected mod to be valid, was NULL\n");
|
||||||
|
|
||||||
|
BOOL status = __FUnloadDelayLoadedDLL2(WINMM_DLLNAME);
|
||||||
|
ok(status == TRUE, "Expected __FUnloadDelayLoadedDLL2 to succeed\n");
|
||||||
|
mod = GetModuleHandleA(WINMM_DLLNAME);
|
||||||
|
ok(mod == NULL, "Expected mod to be NULL, was %p\n", mod);
|
||||||
|
#else
|
||||||
|
trace("Binary compiled without support for unloading\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
skip("No IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT found, some advanced features might not work!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test the normal flow without a dll loaded */
|
||||||
|
BOOL ret = 123;
|
||||||
|
SetExpectedDli(g_winmm_snd_play_a);
|
||||||
|
g_ExpectedDll = WINMM_DLLNAME;
|
||||||
|
g_ExpectedName = "sndPlaySoundA";
|
||||||
|
ret = sndPlaySoundA(NULL, SND_NOWAIT | SND_NOSTOP);
|
||||||
|
ok(ret == TRUE, "Expected ret to be TRUE, was %u\n", ret);
|
||||||
|
CheckDliDone();
|
||||||
|
|
||||||
|
/* Test the normal flow with a dll loaded */
|
||||||
|
SetExpectedDli(g_winmm_snd_play_w);
|
||||||
|
g_ExpectedDll = WINMM_DLLNAME;
|
||||||
|
g_ExpectedName = "sndPlaySoundW";
|
||||||
|
ret = sndPlaySoundW(NULL, SND_NOWAIT | SND_NOSTOP);
|
||||||
|
ok(ret == TRUE, "Expected ret to be TRUE, was %u\n", ret);
|
||||||
|
CheckDliDone();
|
||||||
|
|
||||||
|
/* Make sure GetProcAddress fails, also ignore the Failure hook, use the exception to set the address */
|
||||||
|
SetExpectedDli(g_winmm_play_w);
|
||||||
|
g_ExpectedDll = WINMM_DLLNAME;
|
||||||
|
g_ExpectedName = "playSoundW";
|
||||||
|
g_BreakFunctionName = true;
|
||||||
|
ret = 123;
|
||||||
|
_SEH2_TRY
|
||||||
|
{
|
||||||
|
ret = PlaySoundW(NULL, NULL, SND_NOWAIT | SND_NOSTOP);
|
||||||
|
}
|
||||||
|
_SEH2_EXCEPT(ExceptionFilter(_SEH2_GetExceptionInformation(), _SEH2_GetExceptionCode()))
|
||||||
|
{
|
||||||
|
;
|
||||||
|
}
|
||||||
|
_SEH2_END;
|
||||||
|
ok(ret == TRUE, "Expected ret to be TRUE, was %u\n", ret);
|
||||||
|
CheckDliDone();
|
||||||
|
ok(g_BreakFunctionName == false, "Expected the functionname to be changed\n");
|
||||||
|
|
||||||
|
/* Make the LoadLib fail, manually load the library in the Failure Hook,
|
||||||
|
Respond to the dliNotePreGetProcAddress with an alternate function address */
|
||||||
|
SetExpectedDli(g_sfc_key);
|
||||||
|
ret = SfcIsKeyProtected(NULL, NULL, NULL);
|
||||||
|
ok(ret == 12345, "Expected ret to be 12345, was %u\n", ret); /* The original function returns FALSE! */
|
||||||
|
CheckDliDone();
|
||||||
|
|
||||||
|
/* Show that it works with the manually returned dll */
|
||||||
|
SetExpectedDli(g_sfc_file);
|
||||||
|
ret = SfcGetNextProtectedFile(NULL, NULL);
|
||||||
|
ok(ret == FALSE, "Expected ret to be FALSE, was %u\n", ret);
|
||||||
|
CheckDliDone();
|
||||||
|
|
||||||
|
/* Return a fake dll handle, so that we can see when it is being used, and manually return a function in the Failure Hook */
|
||||||
|
SetExpectedDli(g_version_a);
|
||||||
|
ret = GetFileVersionInfoA(NULL, NULL, NULL, NULL);
|
||||||
|
ok(ret == FALSE, "Expected ret to be FALSE, was %u\n", ret);
|
||||||
|
CheckDliDone();
|
||||||
|
|
||||||
|
/* Manually return a function in the failure hook, when the module is the previously set bad one */
|
||||||
|
SetExpectedDli(g_version_w);
|
||||||
|
ret = GetFileVersionInfoW(NULL, NULL, NULL, NULL);
|
||||||
|
ok(ret == FALSE, "Expected ret to be FALSE, was %u\n", ret);
|
||||||
|
CheckDliDone();
|
||||||
|
|
||||||
|
if (HIWORD(SymGetOptions) == NULL)
|
||||||
|
{
|
||||||
|
skip("SymGetOptions until CORE-6504 is fixed\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Completely bypass most hooks, by directly replying with a function address */
|
||||||
|
SetExpectedDli(g_scard);
|
||||||
|
g_BypassMost = true;
|
||||||
|
DWORD opt = SymGetOptions();
|
||||||
|
g_BypassMost = false;
|
||||||
|
ok(opt == 123, "Expected opt to be 123, was %lu\n", opt); /* The original function returns ERROR_INVALID_HANDLE */
|
||||||
|
CheckDliDone();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Import by ordinal */
|
||||||
|
g_ImportByName = false;
|
||||||
|
SetExpectedDli(g_shlwapi);
|
||||||
|
PARSEDURLA pua = { sizeof(pua), 0 };
|
||||||
|
HRESULT hr = ParseURLA("", &pua);
|
||||||
|
ok(hr == URL_E_INVALID_SYNTAX, "Expected tmp to be URL_E_INVALID_SYNTAX, was %lx\n", hr);
|
||||||
|
CheckDliDone();
|
||||||
|
g_ImportByName = true;
|
||||||
|
|
||||||
|
/* Handle LoadLib failure with an exception handler */
|
||||||
|
if (HIWORD(MapAndLoad) == NULL)
|
||||||
|
{
|
||||||
|
skip("MapAndLoad until CORE-6504 is fixed\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetExpectedDli(g_imagehlp);
|
||||||
|
LOADED_IMAGE img = {0};
|
||||||
|
ret = 123;
|
||||||
|
g_ExceptionIsModule = true;
|
||||||
|
g_ExpectedDll = "xxxxxhlp.dll";
|
||||||
|
g_ExpectedName = "MapAndLoad";
|
||||||
|
_SEH2_TRY
|
||||||
|
{
|
||||||
|
ret = MapAndLoad("some_not_existing_file.aabbcc", NULL, &img, FALSE, TRUE);
|
||||||
|
}
|
||||||
|
_SEH2_EXCEPT(ExceptionFilter(_SEH2_GetExceptionInformation(), _SEH2_GetExceptionCode()))
|
||||||
|
{
|
||||||
|
;
|
||||||
|
}
|
||||||
|
_SEH2_END;
|
||||||
|
g_ExceptionIsModule = false;
|
||||||
|
ok(ret == FALSE, "Expected ret to be FALSE, was %u\n", ret);
|
||||||
|
CheckDliDone();
|
||||||
|
}
|
||||||
|
}
|
12
rostests/apitests/sdk/testlist.c
Normal file
12
rostests/apitests/sdk/testlist.c
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#define __ROS_LONG64__
|
||||||
|
|
||||||
|
#define STANDALONE
|
||||||
|
#include <apitest.h>
|
||||||
|
|
||||||
|
extern void func_delayimp(void);
|
||||||
|
|
||||||
|
const struct test winetest_testlist[] =
|
||||||
|
{
|
||||||
|
{ "delayimp", func_delayimp },
|
||||||
|
{ 0, 0 }
|
||||||
|
};
|
Loading…
Reference in a new issue