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