Author: mjansen
Date: Sat Apr 23 20:38:06 2016
New Revision: 71190
URL:
http://svn.reactos.org/svn/reactos?rev=71190&view=rev
Log:
[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)
Added:
trunk/rostests/apitests/sdk/
trunk/rostests/apitests/sdk/CMakeLists.txt (with props)
trunk/rostests/apitests/sdk/delayimp.cpp (with props)
trunk/rostests/apitests/sdk/testlist.c (with props)
Modified:
trunk/reactos/sdk/include/psdk/delayimp.h
trunk/reactos/sdk/lib/delayimp/CMakeLists.txt
trunk/reactos/sdk/lib/delayimp/delayimp.c
trunk/rostests/apitests/CMakeLists.txt
Modified: trunk/reactos/sdk/include/psdk/delayimp.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/sdk/include/psdk/delayimp.…
==============================================================================
--- trunk/reactos/sdk/include/psdk/delayimp.h [iso-8859-1] (original)
+++ trunk/reactos/sdk/include/psdk/delayimp.h [iso-8859-1] Sat Apr 23 20:38:06 2016
@@ -5,6 +5,17 @@
/* Hack, for bug in ld. Will be removed soon. */
#define __ImageBase _image_base__
#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
@@ -65,24 +76,8 @@
typedef FARPROC (WINAPI *PfnDliHook)(unsigned, PDelayLoadInfo);
-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));
-}
-
-
-extern PfnDliHook __pfnDliNotifyHook2;
-extern PfnDliHook __pfnDliFailureHook2;
+ExternC PfnDliHook __pfnDliNotifyHook2;
+ExternC PfnDliHook __pfnDliFailureHook2;
#endif /* not _delayimp_h */
Modified: trunk/reactos/sdk/lib/delayimp/CMakeLists.txt
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/sdk/lib/delayimp/CMakeList…
==============================================================================
--- trunk/reactos/sdk/lib/delayimp/CMakeLists.txt [iso-8859-1] (original)
+++ trunk/reactos/sdk/lib/delayimp/CMakeLists.txt [iso-8859-1] Sat Apr 23 20:38:06 2016
@@ -2,3 +2,4 @@
add_definitions(-DUNICODE -D_UNICODE)
add_library(delayimp delayimp.c)
add_dependencies(delayimp psdk)
+add_importlibs(delayimp kernel32)
Modified: trunk/reactos/sdk/lib/delayimp/delayimp.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/sdk/lib/delayimp/delayimp.…
==============================================================================
--- trunk/reactos/sdk/lib/delayimp/delayimp.c [iso-8859-1] (original)
+++ trunk/reactos/sdk/lib/delayimp/delayimp.c [iso-8859-1] Sat Apr 23 20:38:06 2016
@@ -4,6 +4,7 @@
* FILE: lib/sdk/delayimp/delayimp.c
* PURPOSE: Library for delay importing from dlls
* PROGRAMMERS: Timo Kreuzer <timo.kreuzer(a)reactos.org>
+ * Mark Jansen
*
*/
@@ -12,17 +13,55 @@
#include <winbase.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 ****/
FARPROC WINAPI
__delayLoadHelper2(PCImgDelayDescr pidd, PImgThunkData pIATEntry)
{
- DelayLoadInfo dli;
+ DelayLoadInfo dli = {0};
int index;
PImgThunkData pIAT;
PImgThunkData pINT;
HMODULE *phMod;
- FARPROC pProc;
pIAT = PFromRva(pidd->rvaIAT);
pINT = PFromRva(pidd->rvaINT);
@@ -31,9 +70,9 @@
dli.cb = sizeof(dli);
dli.pidd = pidd;
- dli.ppfn = (FARPROC*)pIATEntry->u1.Function;
+ dli.ppfn = (FARPROC*)&pIAT[index].u1.Function;
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)
{
/* u1.AdressOfData points to a IMAGE_IMPORT_BY_NAME struct */
@@ -42,61 +81,80 @@
}
else
{
- dli.dlp.dwOrdinal = pINT[index].u1.Ordinal & ~IMAGE_ORDINAL_FLAG;
+ dli.dlp.dwOrdinal = IMAGE_ORDINAL(pINT[index].u1.Ordinal);
}
+
+ if (__pfnDliNotifyHook2)
+ {
+ dli.pfnCur = __pfnDliNotifyHook2(dliStartProcessing, &dli);
+ if (dli.pfnCur)
+ {
+ pIAT[index].u1.Function = (DWORD_PTR)dli.pfnCur;
+ if (__pfnDliNotifyHook2)
+ __pfnDliNotifyHook2(dliNoteEndProcessing, &dli);
+
+ return dli.pfnCur;
+ }
+ }
+
dli.hmodCur = *phMod;
- dli.pfnCur = (FARPROC)pIAT[index].u1.Function;
- dli.dwLastError = GetLastError();
- pProc = __pfnDliNotifyHook2(dliStartProcessing, &dli);
- if (pProc)
- {
- pIAT[index].u1.Function = (DWORD_PTR)pProc;
- return pProc;
- }
if (dli.hmodCur == NULL)
{
- dli.hmodCur = LoadLibraryA(dli.szDll);
- if (!dli.hmodCur)
+ if (__pfnDliNotifyHook2)
+ dli.hmodCur = (HMODULE)__pfnDliNotifyHook2(dliNotePreLoadLibrary, &dli);
+ if (dli.hmodCur == NULL)
{
- dli.dwLastError = GetLastError();
- __pfnDliFailureHook2(dliFailLoadLib, &dli);
-// if (ret)
-// {
-// }
- // FIXME: raise exception;
- return NULL;
+ dli.hmodCur = LoadLibraryA(dli.szDll);
+ if (dli.hmodCur == NULL)
+ {
+ dli.dwLastError = GetLastError();
+ if (__pfnDliFailureHook2)
+ dli.hmodCur = (HMODULE)__pfnDliFailureHook2(dliFailLoadLib,
&dli);
+
+ 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;
}
- /* dli.dlp.szProcName might also contain the ordinal */
- pProc = GetProcAddress(dli.hmodCur, dli.dlp.szProcName);
- if (!pProc)
+ dli.dwLastError = ERROR_SUCCESS;
+
+ if (__pfnDliNotifyHook2)
+ dli.pfnCur = (FARPROC)__pfnDliNotifyHook2(dliNotePreGetProcAddress, &dli);
+ if (dli.pfnCur == NULL)
{
- dli.dwLastError = GetLastError();
- __pfnDliFailureHook2(dliFailGetProc, &dli);
- // FIXME: handle return value & raise exception
- return NULL;
+ /* dli.dlp.szProcName might also contain the ordinal */
+ dli.pfnCur = GetProcAddress(dli.hmodCur, dli.dlp.szProcName);
+ if (dli.pfnCur == 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;
Modified: trunk/rostests/apitests/CMakeLists.txt
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/CMakeLists.txt?r…
==============================================================================
--- trunk/rostests/apitests/CMakeLists.txt [iso-8859-1] (original)
+++ trunk/rostests/apitests/CMakeLists.txt [iso-8859-1] Sat Apr 23 20:38:06 2016
@@ -18,6 +18,7 @@
add_subdirectory(ole32)
add_subdirectory(pefile)
add_subdirectory(powrprof)
+add_subdirectory(sdk)
add_subdirectory(setupapi)
add_subdirectory(shell32)
add_subdirectory(psapi)
Added: trunk/rostests/apitests/sdk/CMakeLists.txt
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/sdk/CMakeLists.t…
==============================================================================
--- trunk/rostests/apitests/sdk/CMakeLists.txt (added)
+++ trunk/rostests/apitests/sdk/CMakeLists.txt [iso-8859-1] Sat Apr 23 20:38:06 2016
@@ -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)
Propchange: trunk/rostests/apitests/sdk/CMakeLists.txt
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/rostests/apitests/sdk/delayimp.cpp
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/sdk/delayimp.cpp…
==============================================================================
--- trunk/rostests/apitests/sdk/delayimp.cpp (added)
+++ trunk/rostests/apitests/sdk/delayimp.cpp [iso-8859-1] Sat Apr 23 20:38:06 2016
@@ -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();
+ }
+}
Propchange: trunk/rostests/apitests/sdk/delayimp.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/rostests/apitests/sdk/testlist.c
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/sdk/testlist.c?r…
==============================================================================
--- trunk/rostests/apitests/sdk/testlist.c (added)
+++ trunk/rostests/apitests/sdk/testlist.c [iso-8859-1] Sat Apr 23 20:38:06 2016
@@ -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 }
+};
Propchange: trunk/rostests/apitests/sdk/testlist.c
------------------------------------------------------------------------------
svn:eol-style = native