1 /*
2  * PROJECT:         ReactOS API tests
3  * LICENSE:         LGPLv2.1+ - See COPYING.LIB in the top level directory
4  * PURPOSE:         Tests for delayload
5  * PROGRAMMER:      Mark Jansen
6  */
7 
8 #include <apitest.h>
9 
10 #include <apitest.h>
11 #include <strsafe.h>
12 #include <delayimp.h>
13 
14 /* Some libraries to test against */
15 #include <mmsystem.h>
16 #include <winver.h>
17 #include <shlwapi.h>
18 #include <intshcut.h>
19 #include <sfc.h>
20 #include <imagehlp.h>
21 #include <mmddk.h>
22 
23 #include <pseh/pseh2.h>
24 
25 /* Compatibility with the MS defines */
26 
27 #ifndef FACILITY_VISUALCPP
28 #define FACILITY_VISUALCPP  ((LONG)0x6d)
29 #endif
30 
31 #ifndef VcppException
32 #define VcppException(sev,err)  ((sev) | (FACILITY_VISUALCPP<<16) | err)
33 #endif
34 
35 #ifdef __REACTOS__
36 #define WINMM_DLLNAME   "winmm.dll"
37 #else
38 #define WINMM_DLLNAME   "WINMM.dll"
39 #endif
40 
41 bool g_BreakFunctionName = false;
42 bool g_BrokenFunctionName = false;
43 bool g_BypassMost = false;
44 bool g_ExceptionIsModule = false;
45 bool g_ImportByName = true;
46 const char* g_ExpectedDll = NULL;
47 const char* g_ExpectedName = NULL;
48 char g_Target[100] = { 0 };
49 
50 char* target(PDelayLoadInfo pdli)
51 {
52     if (g_Target[0] == '\0' && pdli)
53     {
54         if (pdli->dlp.fImportByName)
55             sprintf(g_Target, "%s!%s", pdli->szDll, pdli->dlp.szProcName);
56         else
57             sprintf(g_Target, "%s!#%lu", pdli->szDll, pdli->dlp.dwOrdinal);
58     }
59     return g_Target;
60 }
61 
62 
63 struct UnProtect
64 {
65     UnProtect(PVOID addr)
66         :mAddr(NULL), mProt(0)
67     {
68         if (IsBadWritePtr(addr, 1))
69         {
70             mAddr = addr;
71             VirtualProtect(addr, 1, PAGE_EXECUTE_READWRITE, &mProt);
72         }
73     }
74     ~UnProtect()
75     {
76         DWORD dwOld;
77         if (mAddr)
78             VirtualProtect(mAddr, 1, mProt, &dwOld);
79     }
80 
81     PVOID mAddr;
82     DWORD mProt;
83 };
84 
85 
86 unsigned* g_DliHookExpected = NULL;
87 size_t g_DliHookIndex = 0;
88 #define LAST_DLI    333
89 
90 static void SetExpectedDli(unsigned* order)
91 {
92     g_DliHookExpected = order;
93     g_DliHookIndex = 0;
94     g_Target[0] = '\0';
95 }
96 
97 static void CheckDli_imp(unsigned dliNotify, PDelayLoadInfo pdli, BOOL ErrorHandler)
98 {
99     if (!g_DliHookExpected) return;
100 
101     winetest_ok(dliNotify == g_DliHookExpected[g_DliHookIndex], "Expected dliNotify to be %u, was: %u for %s\n",
102         g_DliHookExpected[g_DliHookIndex], dliNotify, target(pdli));
103     if (ErrorHandler)
104     {
105         winetest_ok(dliNotify == dliFailGetProc || dliNotify == dliFailLoadLib,
106             "Expected code %u to be processed by the Hook, not the ErrorHandler for %s\n", dliNotify, target(pdli));
107     }
108     else
109     {
110         winetest_ok(dliNotify == dliStartProcessing || dliNotify == dliNotePreLoadLibrary ||
111             dliNotify == dliNotePreGetProcAddress || dliNotify == dliNoteEndProcessing,
112             "Expected code %u to be processed by the ErrorHandler, not the Hook for %s\n", dliNotify, target(pdli));
113     }
114     if (g_DliHookExpected[g_DliHookIndex] != LAST_DLI)
115         g_DliHookIndex++;
116 }
117 
118 static void CheckDliDone_imp()
119 {
120     if (!g_DliHookExpected) return;
121     winetest_ok(LAST_DLI == g_DliHookExpected[g_DliHookIndex],
122         "Expected g_DliHookExpected[g_DliHookIndex] to be %u, was: %u for %s\n",
123         LAST_DLI, g_DliHookExpected[g_DliHookIndex], target(NULL));
124     g_DliHookExpected = NULL;
125     g_Target[0] = '\0';
126 }
127 
128 #define CheckDli        (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : CheckDli_imp
129 #define CheckDliDone    (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : CheckDliDone_imp
130 
131 
132 /* Replacement functions */
133 INT_PTR WINAPI MyFunction()
134 {
135     return 123;
136 }
137 
138 BOOL WINAPI MySfcIsKeyProtected(HKEY KeyHandle, LPCWSTR SubKeyName, REGSAM KeySam)
139 {
140     return 12345;
141 }
142 
143 
144 static HMODULE g_VersionDll;
145 FARPROC WINAPI DliHook(unsigned dliNotify, PDelayLoadInfo pdli)
146 {
147     ok(pdli && pdli->cb >= 36, "Expected a valid pointer with a struct that is big enough: %p, %lu\n",
148         pdli, pdli ? pdli->cb : 0u);
149     if (!pdli || pdli->cb < 36) return NULL;
150 
151     CheckDli(dliNotify, pdli, FALSE);
152 
153     if (g_BreakFunctionName && pdli->dlp.fImportByName)
154     {
155         g_BreakFunctionName = false;
156         g_BrokenFunctionName = true;
157         char* procname = (char*)pdli->dlp.szProcName;
158         UnProtect prot(procname);
159         char c = procname[0];
160         procname[0] = isupper(c) ? tolower(c) : toupper(c);
161     }
162 
163     /* Validate dll name when required */
164     if (g_ExpectedDll && g_ExpectedName && !g_BrokenFunctionName)
165     {
166         ok(!strcmp(g_ExpectedDll, pdli->szDll), "Expected szDll to be '%s', but was: '%s'\n", g_ExpectedDll, pdli->szDll);
167         ok(pdli->dlp.fImportByName, "Expected import by name (%s!%s)\n", g_ExpectedDll, g_ExpectedName);
168         if (pdli->dlp.fImportByName)
169         {
170             ok(!strcmp(g_ExpectedName, pdli->dlp.szProcName), "Expected szProcName to be '%s', but was: '%s'\n",
171                 g_ExpectedName, pdli->dlp.szProcName);
172         }
173     }
174 
175 
176     if (dliNotify == dliStartProcessing)
177     {
178         /* Test loadlib fail */
179         if (!_stricmp(pdli->szDll, "sfc_os.dll"))
180         {
181             char* dll = (char*)pdli->szDll;
182             UnProtect u(dll);
183             dll[0] = 'l'; dll[1] = '_'; dll[2] = 'm';
184         }
185         if (!_stricmp(pdli->szDll, "imagehlp.dll"))
186         {
187             char* dll = (char*)pdli->szDll;
188             UnProtect u(dll);
189             dll[0] = 'x'; dll[1] = 'x'; dll[2] = 'x'; dll[3] = 'x'; dll[4] = 'x';
190         }
191         /* Test bypass */
192         if (!_stricmp(pdli->szDll, "dbghelp.dll"))
193             return MyFunction;
194     }
195     else if (dliNotify == dliNotePreLoadLibrary)
196     {
197         /* Show that this value is actually used! */
198         if (!_stricmp(pdli->szDll, "version.dll"))
199         {
200             g_VersionDll = LoadLibraryA("version.dll");
201             return (FARPROC)1;
202         }
203 
204     }
205     else if (dliNotify == dliNotePreGetProcAddress)
206     {
207         if (pdli->dlp.fImportByName && !strcmp(pdli->dlp.szProcName, "SfcIsKeyProtected"))
208         {
209             return (FARPROC)MySfcIsKeyProtected;
210         }
211     }
212 
213     /* Parameter validation */
214     ok(pdli->ppfn != NULL, "Expected ppfn to be valid, was NULL for %s\n", target(pdli));
215     ok(pdli->szDll != NULL, "Expected szDll to be valid, was NULL for %s\n", target(pdli));
216     ok(pdli->dwLastError == ERROR_SUCCESS,
217         "Expected dwLastError to be ERROR_SUCCESS, was: %lu for %s\n", pdli->dwLastError, target(pdli));
218     ok(g_ImportByName == !!pdli->dlp.fImportByName, "Expected pdli->dlp.fImportByName to equal g_ImportByname\n");
219     if (pdli->dlp.fImportByName)
220         ok(pdli->dlp.szProcName != NULL, "Expected szProcName to be valid, was NULL for %s\n", target(pdli));
221     else
222         ok(pdli->dlp.dwOrdinal != 0, "Expected dwOrdinal to be valid, was NULL for %s\n", target(pdli));
223     switch(dliNotify)
224     {
225         case dliStartProcessing:
226             ok(pdli->hmodCur == NULL, "Expected hmodCur to be NULL, was: %p for %s\n", pdli->hmodCur, target(pdli));
227             ok(pdli->pfnCur == NULL, "Expected pfnCur to be NULL, was: %p for %s\n", pdli->pfnCur, target(pdli));
228             break;
229         case dliNotePreLoadLibrary:
230             ok(pdli->hmodCur == NULL, "Expected hmodCur to be NULL, was: %p for %s\n", pdli->hmodCur, target(pdli));
231             ok(pdli->pfnCur == NULL, "Expected pfnCur to be NULL, was: %p for %s\n", pdli->pfnCur, target(pdli));
232             break;
233         case dliNotePreGetProcAddress:
234             ok(pdli->hmodCur != NULL, "Expected hmodCur to be valid, was NULL for %s\n", target(pdli));
235             ok(pdli->pfnCur == NULL, "Expected pfnCur to be NULL, was: %p for %s\n", pdli->pfnCur, target(pdli));
236             break;
237         case dliNoteEndProcessing:
238             if (!g_BypassMost)
239                 ok(pdli->hmodCur != NULL, "Expected hmodCur to be valid, was NULL for %s\n", target(pdli));
240             ok(pdli->pfnCur != NULL, "Expected pfnCur to be a valid pointer, was NULL for %s\n", target(pdli));
241             if (g_ExpectedDll && g_ExpectedName && !g_BrokenFunctionName)
242             {
243                 FARPROC targetProc = GetProcAddress(GetModuleHandleA(g_ExpectedDll), g_ExpectedName);
244                 ok(targetProc != NULL, "This should not happen, the function i need is unavail! (%s!%s)\n",
245                     g_ExpectedDll, g_ExpectedName);
246                 ok(targetProc == pdli->pfnCur, "Expected pfnCur to be %p, was %p for %s\n", targetProc, pdli->pfnCur, target(pdli));
247                 ok(pdli->ppfn && targetProc == *pdli->ppfn,
248                     "Expected ppfn to be valid and to result in %p, was: %p(%p) for %s\n",
249                     target, pdli->ppfn, pdli->ppfn ? *pdli->ppfn : NULL, target(pdli));
250             }
251             break;
252         default:
253             break;
254     }
255     return NULL;
256 }
257 
258 FARPROC WINAPI DliFailHook(unsigned dliNotify, PDelayLoadInfo pdli)
259 {
260     ok(pdli && pdli->cb >= 36,
261         "Expected a valid pointer with a struct that is big enough: %p, %lu\n", pdli, pdli ? pdli->cb : 0u);
262     if (!pdli || pdli->cb < 36) return NULL;
263 
264     CheckDli(dliNotify, pdli, TRUE);
265 
266     /* Redirections / fixes */
267     if (dliNotify == dliFailLoadLib)
268     {
269         if (!_stricmp(pdli->szDll, "l_m_os.dll"))
270             return (FARPROC)LoadLibraryA("sfc_os.dll");
271     }
272     else if (dliNotify == dliFailGetProc)
273     {
274         if (pdli->dlp.fImportByName && pdli->hmodCur == (HMODULE)1)
275         {
276             return GetProcAddress(g_VersionDll, pdli->dlp.szProcName);
277         }
278     }
279 
280     /* Parameter validation */
281     ok(pdli->ppfn != NULL, "Expected ppfn to be valid, was NULL for %s\n", target(pdli));
282     ok(pdli->szDll != NULL, "Expected szDll to be valid, was NULL for %s\n", target(pdli));
283     if (pdli->dlp.fImportByName)
284         ok(pdli->dlp.szProcName != NULL, "Expected szProcName to be valid, was NULL for %s\n", target(pdli));
285     else
286         ok(pdli->dlp.dwOrdinal != 0, "Expected dwOrdinal to be valid, was NULL for %s\n", target(pdli));
287     switch(dliNotify)
288     {
289         case dliFailLoadLib:
290             ok(pdli->hmodCur == NULL, "Expected hmodCur to be NULL, was: %p for %s\n", pdli->hmodCur, target(pdli));
291             ok(pdli->pfnCur == NULL, "Expected pfnCur to be NULL, was: %p for %s\n", pdli->pfnCur, target(pdli));
292             ok(pdli->dwLastError == ERROR_MOD_NOT_FOUND,
293                 "Expected dwLastError to be ERROR_MOD_NOT_FOUND, was: %lu for %s\n", pdli->dwLastError, target(pdli));
294             break;
295         case dliFailGetProc:
296             ok(pdli->hmodCur != NULL, "Expected hmodCur to be valid, was NULL for %s\n", target(pdli));
297             ok(pdli->pfnCur == NULL, "Expected pfnCur to be NULL, was: %p for %s\n", pdli->pfnCur, target(pdli));
298             ok(pdli->dwLastError == ERROR_PROC_NOT_FOUND,
299                 "Expected dwLastError to be ERROR_PROC_NOT_FOUND, was: %lu for %s\n", pdli->dwLastError, target(pdli));
300             break;
301     }
302 
303     return NULL;
304 }
305 
306 
307 LONG ExceptionFilter(IN PEXCEPTION_POINTERS ExceptionInfo, ULONG ExceptionCode)
308 {
309     DWORD expected = VcppException(ERROR_SEVERITY_ERROR, (g_ExceptionIsModule ? ERROR_MOD_NOT_FOUND : ERROR_PROC_NOT_FOUND));
310     ok(ExceptionCode == expected, "Expected code to be 0x%lx, was: 0x%lx\n", expected, ExceptionCode);
311     ok(ExceptionInfo != NULL, "Expected to get exception info\n");
312     ok(ExceptionInfo->ExceptionRecord != NULL, "Expected to get a valid record info\n");
313 
314     if (ExceptionCode != expected)
315     {
316         skip("Skipping other checks, this was not the exception we expected!\n");
317         return EXCEPTION_EXECUTE_HANDLER;
318     }
319 
320     if (ExceptionInfo && ExceptionInfo->ExceptionRecord)
321     {
322         PEXCEPTION_RECORD ExceptionRecord = ExceptionInfo->ExceptionRecord;
323         ok(ExceptionRecord->ExceptionCode == expected, "Expected ExceptionCode to be 0x%lx, was 0x%lx\n",
324             expected, ExceptionRecord->ExceptionCode);
325         /* We can still continue. */
326         ok(ExceptionRecord->ExceptionFlags == 0, "Expected ExceptionFlags to be 0, was: 0x%lx\n",
327             ExceptionRecord->ExceptionFlags);
328         ok(ExceptionRecord->NumberParameters == 1, "Expected 1 parameter, got %lu\n",
329             ExceptionRecord->NumberParameters);
330         if (ExceptionRecord->NumberParameters == 1)
331         {
332             PDelayLoadInfo LoadInfo = (PDelayLoadInfo)ExceptionRecord->ExceptionInformation[0];
333             ok(LoadInfo && LoadInfo->cb >= 36, "Expected a valid pointer with a struct that is big enough: %p, %lu\n",
334                 LoadInfo, LoadInfo ? LoadInfo->cb : 0);
335 
336             if (g_ExpectedDll)
337                 ok(!strcmp(g_ExpectedDll, LoadInfo->szDll), "Expected szDll to be '%s', but was: '%s'\n",
338                 g_ExpectedDll, LoadInfo->szDll);
339             if (g_ExpectedName)
340             {
341                 ok(LoadInfo->dlp.fImportByName, "Expected import by name\n");
342                 if (LoadInfo->dlp.fImportByName)
343                 {
344                     ok(!strcmp(g_ExpectedName, LoadInfo->dlp.szProcName),
345                     "Expected szProcName to be '%s', but was: '%s'\n", g_ExpectedName, LoadInfo->dlp.szProcName);
346 
347                     if (g_ExceptionIsModule)
348                     {
349                         HMODULE mod = LoadLibraryA("imagehlp.dll");
350                         LoadInfo->pfnCur = GetProcAddress(mod, g_ExpectedName);
351                     }
352                     else
353                     {
354                         char buf[100];
355                         char first = isupper(g_ExpectedName[0]) ? tolower(g_ExpectedName[0]) : toupper(g_ExpectedName[0]);
356                         sprintf(buf, "%c%s", first, g_ExpectedName + 1);
357                         LoadInfo->pfnCur = GetProcAddress(GetModuleHandleA(g_ExpectedDll), buf);
358                     }
359                     return LoadInfo->pfnCur ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER;
360                 }
361             }
362         }
363     }
364 
365     return EXCEPTION_EXECUTE_HANDLER;
366 }
367 
368 /* We register one hook the 'default' way and one manually,
369 so that we can check that both fallback and registration work*/
370 extern "C"
371 {
372     extern PfnDliHook __pfnDliNotifyHook2;
373     //PfnDliHook __pfnDliFailureHook2 = DliFailHook;
374 }
375 
376 
377 bool g_UsePointers = false;
378 
379 template<typename PTR>
380 PTR Rva2Addr(PIMAGE_DOS_HEADER dos, RVA rva)
381 {
382     /* Old delayload type */
383     if (g_UsePointers)
384         return reinterpret_cast<PTR>(rva);
385     return reinterpret_cast<PTR>((reinterpret_cast<PBYTE>(dos) + rva));
386 }
387 
388 
389 unsigned g_winmm_get_cur_task[] = { dliStartProcessing, dliNotePreLoadLibrary, dliNotePreGetProcAddress, dliNoteEndProcessing, LAST_DLI };
390 unsigned g_winmm_midi_out_close[] = { dliStartProcessing, dliNotePreGetProcAddress, dliNoteEndProcessing, LAST_DLI };
391 unsigned g_winmm_mide_in_close[] = { dliStartProcessing, dliNotePreGetProcAddress, dliFailGetProc, dliNoteEndProcessing, LAST_DLI };
392 unsigned g_sfc_key[] = { dliStartProcessing, dliNotePreLoadLibrary, dliFailLoadLib, dliNotePreGetProcAddress, dliNoteEndProcessing, LAST_DLI };
393 unsigned g_sfc_file[] = { dliStartProcessing, dliNotePreGetProcAddress, dliNoteEndProcessing, LAST_DLI };
394 unsigned g_version_a[] = { dliStartProcessing, dliNotePreLoadLibrary, dliNotePreGetProcAddress, dliFailGetProc, dliNoteEndProcessing, LAST_DLI };
395 unsigned g_version_w[] = { dliStartProcessing, dliNotePreGetProcAddress, dliFailGetProc, dliNoteEndProcessing, LAST_DLI };
396 unsigned g_scard[] = { dliStartProcessing, dliNoteEndProcessing, LAST_DLI };
397 unsigned g_shlwapi[] = { dliStartProcessing, dliNotePreLoadLibrary, dliNotePreGetProcAddress, dliNoteEndProcessing, LAST_DLI };
398 unsigned g_imagehlp[] = { dliStartProcessing, dliNotePreLoadLibrary, dliFailLoadLib, LAST_DLI };    /* This exception does not fire EndProcessing! */
399 
400 
401 //#define DELAYLOAD_SUPPORTS_UNLOADING
402 START_TEST(delayimp)
403 {
404     __pfnDliNotifyHook2 = DliHook;
405     /* Verify that both scenario's work */
406     ok(__pfnDliNotifyHook2 == DliHook, "Expected __pfnDliNotifyHook2 to be DliHook(%p), but was: %p\n",
407         DliHook, __pfnDliNotifyHook2);
408     ok(__pfnDliFailureHook2 == NULL, "Expected __pfnDliFailureHook2 to be NULL, but was: %p\n",
409         __pfnDliFailureHook2);
410 
411     __pfnDliFailureHook2 = DliFailHook;
412 
413 
414     PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)GetModuleHandle(NULL);
415 
416     ok(dos->e_magic == IMAGE_DOS_SIGNATURE, "Expected a DOS header\n");
417     if (dos->e_magic != IMAGE_DOS_SIGNATURE)
418         return;
419 
420     PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)((PBYTE)dos + dos->e_lfanew);
421     PIMAGE_DATA_DIRECTORY delaydir = nt->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT;
422 
423     /* Test some advanced features (loading / unloading) */
424     if (delaydir->Size != 0)
425     {
426 #if defined(_DELAY_IMP_VER) && _DELAY_IMP_VER == 2 && defined(DELAYLOAD_SUPPORTS_UNLOADING)
427         /* First, before mangling the delayload stuff, let's try some v2 functions */
428         HMODULE mod = GetModuleHandleA(WINMM_DLLNAME);
429         ok(mod == NULL, "Expected mod to be NULL, was %p\n", mod);
430         /* Now, a mistyped module (case sensitive!) */
431         HRESULT hr = __HrLoadAllImportsForDll("WiNmM.DlL");
432         ok(hr == HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND), "Expected hr to be HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND), was %lu\n", hr);
433         mod = GetModuleHandleA(WINMM_DLLNAME);
434         ok(mod == NULL, "Expected mod to be NULL, was %p\n", mod);
435 
436         /* Let's load it */
437         hr = __HrLoadAllImportsForDll(WINMM_DLLNAME);
438         ok(hr == S_OK, "Expected hr to be S_OK, was %lu\n", hr);
439         mod = GetModuleHandleA(WINMM_DLLNAME);
440         ok(mod != NULL, "Expected mod to be valid, was NULL\n");
441 
442         BOOL status = __FUnloadDelayLoadedDLL2(WINMM_DLLNAME);
443         ok(status == TRUE, "Expected __FUnloadDelayLoadedDLL2 to succeed\n");
444         mod = GetModuleHandleA(WINMM_DLLNAME);
445         ok(mod == NULL, "Expected mod to be NULL, was %p\n", mod);
446 #else
447         trace("Binary compiled without support for unloading\n");
448 #endif
449     }
450     else
451     {
452         skip("No IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT found, some advanced features might not work!\n");
453     }
454 
455     /* Test the normal flow without a dll loaded */
456     SetExpectedDli(g_winmm_get_cur_task);
457     g_ExpectedDll = WINMM_DLLNAME;
458     g_ExpectedName = "mmGetCurrentTask";
459     DWORD task = mmGetCurrentTask();
460     ok(task == GetCurrentThreadId(), "Expected ret to be current thread id (0x%lx), was 0x%lx\n", GetCurrentThreadId(), task);
461     CheckDliDone();
462 
463     /* Test the normal flow with a dll loaded */
464     SetExpectedDli(g_winmm_midi_out_close);
465     g_ExpectedDll = WINMM_DLLNAME;
466     g_ExpectedName = "midiOutClose";
467     DWORD err = midiOutClose((HMIDIOUT)(ULONG_PTR)0xdeadbeef);
468     ok(err == MMSYSERR_INVALHANDLE, "Expected err to be MMSYSERR_INVALHANDLE, was 0x%lx\n", err);
469     CheckDliDone();
470 
471     /* Make sure GetProcAddress fails, also ignore the Failure hook, use the exception to set the address */
472     SetExpectedDli(g_winmm_mide_in_close);
473     g_ExpectedDll = WINMM_DLLNAME;
474     g_ExpectedName = "MixerClose";
475     g_BreakFunctionName = true;
476     _SEH2_TRY
477     {
478         err = mixerClose((HMIXER)(ULONG_PTR)0xdeadbeef);
479     }
480     _SEH2_EXCEPT(ExceptionFilter(_SEH2_GetExceptionInformation(), _SEH2_GetExceptionCode()))
481     {
482         err = _SEH2_GetExceptionCode();
483     }
484     _SEH2_END;
485     ok(err == MMSYSERR_INVALHANDLE, "Expected err to be MMSYSERR_INVALHANDLE, was 0x%lx\n", err);
486     CheckDliDone();
487     ok(g_BreakFunctionName == false, "Expected the functionname to be changed\n");
488 
489     /* Make the LoadLib fail, manually load the library in the Failure Hook,
490     Respond to the dliNotePreGetProcAddress with an alternate function address */
491     SetExpectedDli(g_sfc_key);
492     BOOL ret = SfcIsKeyProtected(NULL, NULL, NULL);
493     ok(ret == 12345, "Expected ret to be 12345, was %u\n", ret);    /* The original function returns FALSE! */
494     CheckDliDone();
495 
496     /* Show that it works with the manually returned dll */
497     SetExpectedDli(g_sfc_file);
498     ret = SfcGetNextProtectedFile(NULL, NULL);
499     ok(ret == FALSE, "Expected ret to be FALSE, was %u\n", ret);
500     CheckDliDone();
501 
502     /* Return a fake dll handle, so that we can see when it is being used, and manually return a function in the Failure Hook */
503     SetExpectedDli(g_version_a);
504     ret = GetFileVersionInfoA(NULL, NULL, NULL, NULL);
505     ok(ret == FALSE, "Expected ret to be FALSE, was %u\n", ret);
506     CheckDliDone();
507 
508     /* Manually return a function in the failure hook, when the module is the previously set bad one */
509     SetExpectedDli(g_version_w);
510     ret = GetFileVersionInfoW(NULL, NULL, NULL, NULL);
511     ok(ret == FALSE, "Expected ret to be FALSE, was %u\n", ret);
512     CheckDliDone();
513 
514     if (HIWORD(SymGetOptions) == NULL)
515     {
516         skip("SymGetOptions until CORE-6504 is fixed\n");
517     }
518     else
519     {
520         /* Completely bypass most hooks, by directly replying with a function address */
521         SetExpectedDli(g_scard);
522         g_BypassMost = true;
523         DWORD opt = SymGetOptions();
524         g_BypassMost = false;
525         ok(opt == 123, "Expected opt to be 123, was %lu\n", opt);    /* The original function returns ERROR_INVALID_HANDLE */
526         CheckDliDone();
527     }
528 
529     /* Import by ordinal */
530     g_ImportByName = false;
531     SetExpectedDli(g_shlwapi);
532     PARSEDURLA pua = { sizeof(pua), 0 };
533     HRESULT hr = ParseURLA("", &pua);
534     ok(hr == URL_E_INVALID_SYNTAX, "Expected tmp to be URL_E_INVALID_SYNTAX, was %lx\n", hr);
535     CheckDliDone();
536     g_ImportByName = true;
537 
538     /* Handle LoadLib failure with an exception handler */
539     if (HIWORD(MapAndLoad) == NULL)
540     {
541         skip("MapAndLoad until CORE-6504 is fixed\n");
542     }
543     else
544     {
545         SetExpectedDli(g_imagehlp);
546         LOADED_IMAGE img = {0};
547         ret = 123;
548         g_ExceptionIsModule = true;
549         g_ExpectedDll = "xxxxxhlp.dll";
550         g_ExpectedName = "MapAndLoad";
551         _SEH2_TRY
552         {
553             ret = MapAndLoad("some_not_existing_file.aabbcc", NULL, &img, FALSE, TRUE);
554         }
555         _SEH2_EXCEPT(ExceptionFilter(_SEH2_GetExceptionInformation(), _SEH2_GetExceptionCode()))
556         {
557             ;
558         }
559         _SEH2_END;
560         g_ExceptionIsModule = false;
561         ok(ret == FALSE, "Expected ret to be FALSE, was %u\n", ret);
562         CheckDliDone();
563     }
564 }
565