mshtml: Correct test for another unknown dispID.
[wine] / dlls / kernel32 / tests / loader.c
1 /*
2  * Unit test suite for the PE loader.
3  *
4  * Copyright 2006 Dmitry Timoshkov
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdarg.h>
22 #include <assert.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wine/test.h"
27
28 #define ALIGN_SIZE(size, alignment) (((size) + (alignment - 1)) & ~((alignment - 1)))
29
30 static PVOID RVAToAddr(DWORD_PTR rva, HMODULE module)
31 {
32     if (rva == 0)
33         return NULL;
34     return ((char*) module) + rva;
35 }
36
37 static const struct
38 {
39     WORD e_magic;      /* 00: MZ Header signature */
40     WORD unused[29];
41     DWORD e_lfanew;    /* 3c: Offset to extended header */
42 } dos_header =
43 {
44     IMAGE_DOS_SIGNATURE, { 0 }, sizeof(dos_header)
45 };
46
47 static IMAGE_NT_HEADERS nt_header =
48 {
49     IMAGE_NT_SIGNATURE, /* Signature */
50     {
51 #if defined __i386__
52       IMAGE_FILE_MACHINE_I386, /* Machine */
53 #elif defined __x86_64__
54       IMAGE_FILE_MACHINE_AMD64, /* Machine */
55 #elif defined __powerpc__
56       IMAGE_FILE_MACHINE_POWERPC, /* Machine */
57 #elif defined __sparc__
58       IMAGE_FILE_MACHINE_SPARC, /* Machine */
59 #else
60 # error You must specify the machine type
61 #endif
62       1, /* NumberOfSections */
63       0, /* TimeDateStamp */
64       0, /* PointerToSymbolTable */
65       0, /* NumberOfSymbols */
66       sizeof(IMAGE_OPTIONAL_HEADER), /* SizeOfOptionalHeader */
67       IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL /* Characteristics */
68     },
69     { IMAGE_NT_OPTIONAL_HDR_MAGIC, /* Magic */
70       1, /* MajorLinkerVersion */
71       0, /* MinorLinkerVersion */
72       0, /* SizeOfCode */
73       0, /* SizeOfInitializedData */
74       0, /* SizeOfUninitializedData */
75       0, /* AddressOfEntryPoint */
76       0x10, /* BaseOfCode, also serves as e_lfanew in the truncated MZ header */
77 #ifndef _WIN64
78       0, /* BaseOfData */
79 #endif
80       0x10000000, /* ImageBase */
81       0, /* SectionAlignment */
82       0, /* FileAlignment */
83       4, /* MajorOperatingSystemVersion */
84       0, /* MinorOperatingSystemVersion */
85       1, /* MajorImageVersion */
86       0, /* MinorImageVersion */
87       4, /* MajorSubsystemVersion */
88       0, /* MinorSubsystemVersion */
89       0, /* Win32VersionValue */
90       sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x1000, /* SizeOfImage */
91       sizeof(dos_header) + sizeof(nt_header), /* SizeOfHeaders */
92       0, /* CheckSum */
93       IMAGE_SUBSYSTEM_WINDOWS_CUI, /* Subsystem */
94       0, /* DllCharacteristics */
95       0, /* SizeOfStackReserve */
96       0, /* SizeOfStackCommit */
97       0, /* SizeOfHeapReserve */
98       0, /* SizeOfHeapCommit */
99       0, /* LoaderFlags */
100       0, /* NumberOfRvaAndSizes */
101       { { 0 } } /* DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] */
102     }
103 };
104
105 static IMAGE_SECTION_HEADER section =
106 {
107     ".rodata", /* Name */
108     { 0x10 }, /* Misc */
109     0, /* VirtualAddress */
110     0x0a, /* SizeOfRawData */
111     0, /* PointerToRawData */
112     0, /* PointerToRelocations */
113     0, /* PointerToLinenumbers */
114     0, /* NumberOfRelocations */
115     0, /* NumberOfLinenumbers */
116     IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ, /* Characteristics */
117 };
118
119 static void test_Loader(void)
120 {
121     static const struct test_data
122     {
123         const void *dos_header;
124         DWORD size_of_dos_header;
125         WORD number_of_sections, size_of_optional_header;
126         DWORD section_alignment, file_alignment;
127         DWORD size_of_image, size_of_headers;
128         DWORD error; /* 0 means LoadLibrary should succeed */
129         DWORD alt_error; /* alternate error */
130     } td[] =
131     {
132         { &dos_header, sizeof(dos_header),
133           1, 0, 0, 0, 0, 0,
134           ERROR_BAD_EXE_FORMAT
135         },
136         { &dos_header, sizeof(dos_header),
137           1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x1000,
138           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0xe00,
139           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER),
140           ERROR_BAD_EXE_FORMAT /* XP doesn't like too small image size */
141         },
142         { &dos_header, sizeof(dos_header),
143           1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x1000,
144           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
145           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER),
146           ERROR_SUCCESS
147         },
148         { &dos_header, sizeof(dos_header),
149           1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x1000,
150           0x1f00,
151           0x1000,
152           ERROR_SUCCESS
153         },
154         { &dos_header, sizeof(dos_header),
155           1, sizeof(IMAGE_OPTIONAL_HEADER), 0x200, 0x200,
156           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x200,
157           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER),
158           ERROR_SUCCESS, ERROR_INVALID_ADDRESS /* vista is more strict */
159         },
160         { &dos_header, sizeof(dos_header),
161           1, sizeof(IMAGE_OPTIONAL_HEADER), 0x200, 0x1000,
162           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
163           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER),
164           ERROR_BAD_EXE_FORMAT /* XP doesn't like alignments */
165         },
166         { &dos_header, sizeof(dos_header),
167           1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x200,
168           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
169           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER),
170           ERROR_SUCCESS
171         },
172         { &dos_header, sizeof(dos_header),
173           1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x200,
174           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
175           0x200,
176           ERROR_SUCCESS
177         },
178         /* Mandatory are all fields up to SizeOfHeaders, everything else
179          * is really optional (at least that's true for XP).
180          */
181         { &dos_header, sizeof(dos_header),
182           1, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
183           sizeof(dos_header) + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum) + sizeof(IMAGE_SECTION_HEADER) + 0x10,
184           sizeof(dos_header) + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum) + sizeof(IMAGE_SECTION_HEADER),
185           ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT /* vista is more strict */
186         },
187         { &dos_header, sizeof(dos_header),
188           0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
189           0xd0, /* beyond of the end of file */
190           0xc0, /* beyond of the end of file */
191           ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT /* vista is more strict */
192         },
193         { &dos_header, sizeof(dos_header),
194           0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
195           0x1000,
196           0,
197           ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT /* vista is more strict */
198         },
199         { &dos_header, sizeof(dos_header),
200           0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
201           1,
202           0,
203           ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT /* vista is more strict */
204         },
205 #if 0 /* not power of 2 alignments need more test cases */
206         { &dos_header, sizeof(dos_header),
207           0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x300, 0x300,
208           1,
209           0,
210           ERROR_BAD_EXE_FORMAT /* alignment is not power of 2 */
211         },
212 #endif
213         { &dos_header, sizeof(dos_header),
214           0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 4, 4,
215           1,
216           0,
217           ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT /* vista is more strict */
218         },
219         { &dos_header, sizeof(dos_header),
220           0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 1, 1,
221           1,
222           0,
223           ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT /* vista is more strict */
224         },
225         { &dos_header, sizeof(dos_header),
226           0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
227           0,
228           0,
229           ERROR_BAD_EXE_FORMAT /* image size == 0 -> failure */
230         },
231         /* the following data mimics the PE image which upack creates */
232         { &dos_header, 0x10,
233           1, 0x148, 0x1000, 0x200,
234           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
235           0x200,
236           ERROR_SUCCESS
237         },
238         /* Minimal PE image that XP is able to load: 92 bytes */
239         { &dos_header, 0x04,
240           0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum),
241           0x04 /* also serves as e_lfanew in the truncated MZ header */, 0x04,
242           1,
243           0,
244           ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT /* vista is more strict */
245         }
246     };
247     static const char filler[0x1000];
248     static const char section_data[0x10] = "section data";
249     int i;
250     DWORD dummy, file_size, file_align;
251     HANDLE hfile;
252     HMODULE hlib, hlib_as_data_file;
253     SYSTEM_INFO si;
254     char temp_path[MAX_PATH];
255     char dll_name[MAX_PATH];
256
257     GetSystemInfo(&si);
258     trace("system page size 0x%04x\n", si.dwPageSize);
259
260     /* prevent displaying of the "Unable to load this DLL" message box */
261     SetErrorMode(SEM_FAILCRITICALERRORS);
262
263     GetTempPath(MAX_PATH, temp_path);
264
265     for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
266     {
267         GetTempFileName(temp_path, "ldr", 0, dll_name);
268
269         /*trace("creating %s\n", dll_name);*/
270         hfile = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
271         if (hfile == INVALID_HANDLE_VALUE)
272         {
273             ok(0, "could not create %s\n", dll_name);
274             break;
275         }
276
277         SetLastError(0xdeadbeef);
278         ok(WriteFile(hfile, td[i].dos_header, td[i].size_of_dos_header, &dummy, NULL),
279            "WriteFile error %d\n", GetLastError());
280
281         nt_header.FileHeader.NumberOfSections = td[i].number_of_sections;
282         nt_header.FileHeader.SizeOfOptionalHeader = td[i].size_of_optional_header;
283
284         nt_header.OptionalHeader.SectionAlignment = td[i].section_alignment;
285         nt_header.OptionalHeader.FileAlignment = td[i].file_alignment;
286         nt_header.OptionalHeader.SizeOfImage = td[i].size_of_image;
287         nt_header.OptionalHeader.SizeOfHeaders = td[i].size_of_headers;
288         SetLastError(0xdeadbeef);
289         ok(WriteFile(hfile, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL),
290            "WriteFile error %d\n", GetLastError());
291
292         if (nt_header.FileHeader.SizeOfOptionalHeader)
293         {
294             SetLastError(0xdeadbeef);
295             ok(WriteFile(hfile, &nt_header.OptionalHeader,
296                          min(nt_header.FileHeader.SizeOfOptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER)),
297                          &dummy, NULL),
298                "WriteFile error %d\n", GetLastError());
299             if (nt_header.FileHeader.SizeOfOptionalHeader > sizeof(IMAGE_OPTIONAL_HEADER))
300             {
301                 file_align = nt_header.FileHeader.SizeOfOptionalHeader - sizeof(IMAGE_OPTIONAL_HEADER);
302                 assert(file_align < sizeof(filler));
303                 SetLastError(0xdeadbeef);
304                 ok(WriteFile(hfile, filler, file_align, &dummy, NULL),
305                    "WriteFile error %d\n", GetLastError());
306             }
307         }
308
309         assert(nt_header.FileHeader.NumberOfSections <= 1);
310         if (nt_header.FileHeader.NumberOfSections)
311         {
312             if (nt_header.OptionalHeader.SectionAlignment >= si.dwPageSize)
313             {
314                 section.PointerToRawData = td[i].size_of_dos_header;
315                 section.VirtualAddress = nt_header.OptionalHeader.SectionAlignment;
316                 section.Misc.VirtualSize = section.SizeOfRawData * 10;
317             }
318             else
319             {
320                 section.PointerToRawData = nt_header.OptionalHeader.SizeOfHeaders;
321                 section.VirtualAddress = nt_header.OptionalHeader.SizeOfHeaders;
322                 section.Misc.VirtualSize = 5;
323             }
324
325             SetLastError(0xdeadbeef);
326             ok(WriteFile(hfile, &section, sizeof(section), &dummy, NULL),
327                "WriteFile error %d\n", GetLastError());
328
329             /* section data */
330             SetLastError(0xdeadbeef);
331             ok(WriteFile(hfile, section_data, sizeof(section_data), &dummy, NULL),
332                "WriteFile error %d\n", GetLastError());
333         }
334
335         file_size = GetFileSize(hfile, NULL);
336         CloseHandle(hfile);
337
338         SetLastError(0xdeadbeef);
339         hlib = LoadLibrary(dll_name);
340         if (hlib)
341         {
342             MEMORY_BASIC_INFORMATION info;
343
344             ok( td[i].error == ERROR_SUCCESS, "%d: should have failed\n", i );
345
346             SetLastError(0xdeadbeef);
347             ok(VirtualQuery(hlib, &info, sizeof(info)) == sizeof(info),
348                 "%d: VirtualQuery error %d\n", i, GetLastError());
349             ok(info.BaseAddress == hlib, "%d: %p != %p\n", i, info.BaseAddress, hlib);
350             ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
351             ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
352             ok(info.RegionSize == ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, si.dwPageSize), "%d: got %lx != expected %x\n",
353                i, info.RegionSize, ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, si.dwPageSize));
354             ok(info.State == MEM_COMMIT, "%d: %x != MEM_COMMIT\n", i, info.State);
355             if (nt_header.OptionalHeader.SectionAlignment < si.dwPageSize)
356                 ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.Protect);
357             else
358                 ok(info.Protect == PAGE_READONLY, "%d: %x != PAGE_READONLY\n", i, info.Protect);
359             ok(info.Type == SEC_IMAGE, "%d: %x != SEC_IMAGE\n", i, info.Type);
360
361             SetLastError(0xdeadbeef);
362             ok(VirtualQuery((char *)hlib + info.RegionSize, &info, sizeof(info)) == sizeof(info),
363                 "%d: VirtualQuery error %d\n", i, GetLastError());
364             if (nt_header.OptionalHeader.SectionAlignment == si.dwPageSize ||
365                 nt_header.OptionalHeader.SectionAlignment == nt_header.OptionalHeader.FileAlignment)
366             {
367                 ok(info.BaseAddress == (char *)hlib + ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, si.dwPageSize), "%d: got %p != expected %p\n",
368                    i, info.BaseAddress, (char *)hlib + ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, si.dwPageSize));
369                 ok(info.AllocationBase == 0, "%d: %p != 0\n", i, info.AllocationBase);
370                 ok(info.AllocationProtect == 0, "%d: %x != 0\n", i, info.AllocationProtect);
371                 /*ok(info.RegionSize == not_practical_value, "%d: %lx != not_practical_value\n", i, info.RegionSize);*/
372                 ok(info.State == MEM_FREE, "%d: %x != MEM_FREE\n", i, info.State);
373                 ok(info.Type == 0, "%d: %x != 0\n", i, info.Type);
374                 ok(info.Protect == PAGE_NOACCESS, "%d: %x != PAGE_NOACCESS\n", i, info.Protect);
375             }
376             else
377             {
378                 ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.Protect);
379                 ok(info.BaseAddress == hlib, "%d: got %p != expected %p\n", i, info.BaseAddress, hlib);
380                 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
381                 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
382                 ok(info.RegionSize == ALIGN_SIZE(file_size, si.dwPageSize), "%d: got %lx != expected %x\n",
383                    i, info.RegionSize, ALIGN_SIZE(file_size, si.dwPageSize));
384                 ok(info.State == MEM_COMMIT, "%d: %x != MEM_COMMIT\n", i, info.State);
385                 ok(info.Protect == PAGE_READONLY, "%d: %x != PAGE_READONLY\n", i, info.Protect);
386                 ok(info.Type == SEC_IMAGE, "%d: %x != SEC_IMAGE\n", i, info.Type);
387             }
388
389             /* header: check the zeroing of alignment */
390             if (nt_header.OptionalHeader.SectionAlignment >= si.dwPageSize)
391             {
392                 const char *start;
393                 int size;
394
395                 start = (const char *)hlib + nt_header.OptionalHeader.SizeOfHeaders;
396                 size = ALIGN_SIZE((ULONG_PTR)start, si.dwPageSize) - (ULONG_PTR)start;
397                 ok(!memcmp(start, filler, size), "%d: header alignment is not cleared\n", i);
398             }
399
400             if (nt_header.FileHeader.NumberOfSections)
401             {
402                 SetLastError(0xdeadbeef);
403                 ok(VirtualQuery((char *)hlib + section.VirtualAddress, &info, sizeof(info)) == sizeof(info),
404                     "%d: VirtualQuery error %d\n", i, GetLastError());
405                 if (nt_header.OptionalHeader.SectionAlignment < si.dwPageSize)
406                 {
407                     ok(info.BaseAddress == hlib, "%d: got %p != expected %p\n", i, info.BaseAddress, hlib);
408                     ok(info.RegionSize == ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, si.dwPageSize), "%d: got %lx != expected %x\n",
409                        i, info.RegionSize, ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, si.dwPageSize));
410                     ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.Protect);
411                 }
412                 else
413                 {
414                     ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "%d: got %p != expected %p\n", i, info.BaseAddress, (char *)hlib + section.VirtualAddress);
415                     ok(info.RegionSize == ALIGN_SIZE(section.Misc.VirtualSize, si.dwPageSize), "%d: got %lx != expected %x\n",
416                        i, info.RegionSize, ALIGN_SIZE(section.Misc.VirtualSize, si.dwPageSize));
417                     ok(info.Protect == PAGE_READONLY, "%d: %x != PAGE_READONLY\n", i, info.Protect);
418                 }
419                 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
420                 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
421                 ok(info.State == MEM_COMMIT, "%d: %x != MEM_COMMIT\n", i, info.State);
422                 ok(info.Type == SEC_IMAGE, "%d: %x != SEC_IMAGE\n", i, info.Type);
423
424                 if (nt_header.OptionalHeader.SectionAlignment >= si.dwPageSize)
425                     ok(!memcmp((const char *)hlib + section.VirtualAddress + section.PointerToRawData, &nt_header, section.SizeOfRawData), "wrong section data\n");
426                 else
427                     ok(!memcmp((const char *)hlib + section.PointerToRawData, section_data, section.SizeOfRawData), "wrong section data\n");
428
429                 /* check the zeroing of alignment */
430                 if (nt_header.OptionalHeader.SectionAlignment >= si.dwPageSize)
431                 {
432                     const char *start;
433                     int size;
434
435                     start = (const char *)hlib + section.VirtualAddress + section.PointerToRawData + section.SizeOfRawData;
436                     size = ALIGN_SIZE((ULONG_PTR)start, si.dwPageSize) - (ULONG_PTR)start;
437                     ok(memcmp(start, filler, size), "%d: alignment should not be cleared\n", i);
438                 }
439             }
440
441             SetLastError(0xdeadbeef);
442             hlib_as_data_file = LoadLibraryEx(dll_name, 0, LOAD_LIBRARY_AS_DATAFILE);
443             ok(hlib_as_data_file != 0, "LoadLibraryEx error %u\n", GetLastError());
444             ok(hlib_as_data_file == hlib, "hlib_as_file and hlib are different\n");
445
446             SetLastError(0xdeadbeef);
447             ok(FreeLibrary(hlib), "FreeLibrary error %d\n", GetLastError());
448
449             SetLastError(0xdeadbeef);
450             hlib = GetModuleHandle(dll_name);
451             ok(hlib != 0, "GetModuleHandle error %u\n", GetLastError());
452
453             SetLastError(0xdeadbeef);
454             ok(FreeLibrary(hlib_as_data_file), "FreeLibrary error %d\n", GetLastError());
455
456             hlib = GetModuleHandle(dll_name);
457             ok(!hlib, "GetModuleHandle should fail\n");
458
459             SetLastError(0xdeadbeef);
460             hlib_as_data_file = LoadLibraryEx(dll_name, 0, LOAD_LIBRARY_AS_DATAFILE);
461             ok(hlib_as_data_file != 0, "LoadLibraryEx error %u\n", GetLastError());
462             ok((ULONG_PTR)hlib_as_data_file & 1, "hlib_as_data_file is even\n");
463
464             hlib = GetModuleHandle(dll_name);
465             ok(!hlib, "GetModuleHandle should fail\n");
466
467             SetLastError(0xdeadbeef);
468             ok(FreeLibrary(hlib_as_data_file), "FreeLibrary error %d\n", GetLastError());
469         }
470         else
471         {
472             ok(td[i].error || td[i].alt_error, "%d: LoadLibrary should succeed\n", i);
473
474             if (GetLastError() == ERROR_GEN_FAILURE) /* Win9x, broken behaviour */
475             {
476                 trace("skipping the loader test on Win9x\n");
477                 DeleteFile(dll_name);
478                 return;
479             }
480
481             ok(td[i].error == GetLastError() || td[i].alt_error == GetLastError(),
482                "%d: expected error %d or %d, got %d\n",
483                i, td[i].error, td[i].alt_error, GetLastError());
484         }
485
486         SetLastError(0xdeadbeef);
487         ok(DeleteFile(dll_name), "DeleteFile error %d\n", GetLastError());
488     }
489 }
490
491 /* Verify linking style of import descriptors */
492 static void test_ImportDescriptors(void)
493 {
494     HMODULE kernel32_module = NULL;
495     PIMAGE_DOS_HEADER d_header;
496     PIMAGE_NT_HEADERS nt_headers;
497     DWORD import_dir_size;
498     DWORD_PTR dir_offset;
499     PIMAGE_IMPORT_DESCRIPTOR import_chunk;
500
501     /* Load kernel32 module */
502     kernel32_module = GetModuleHandleA("kernel32.dll");
503     assert( kernel32_module != NULL );
504
505     /* Get PE header info from module image */
506     d_header = (PIMAGE_DOS_HEADER) kernel32_module;
507     nt_headers = (PIMAGE_NT_HEADERS) (((char*) d_header) +
508             d_header->e_lfanew);
509
510     /* Get size of import entry directory */
511     import_dir_size = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
512     if (!import_dir_size)
513     {
514         skip("Unable to continue testing due to missing import directory.\n");
515         return;
516     }
517
518     /* Get address of first import chunk */
519     dir_offset = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
520     import_chunk = RVAToAddr(dir_offset, kernel32_module);
521     ok(import_chunk != 0, "Invalid import_chunk: %p\n", import_chunk);
522     if (!import_chunk) return;
523
524     /* Iterate through import descriptors and verify set name,
525      * OriginalFirstThunk, and FirstThunk.  Core Windows DLLs, such as
526      * kernel32.dll, don't use Borland-style linking, where the table of
527      * imported names is stored directly in FirstThunk and overwritten
528      * by the relocation, instead of being stored in OriginalFirstThunk.
529      * */
530     for (; import_chunk->FirstThunk; import_chunk++)
531     {
532         LPCSTR module_name = RVAToAddr(import_chunk->Name, kernel32_module);
533         PIMAGE_THUNK_DATA name_table = RVAToAddr(
534                 U(*import_chunk).OriginalFirstThunk, kernel32_module);
535         PIMAGE_THUNK_DATA iat = RVAToAddr(
536                 import_chunk->FirstThunk, kernel32_module);
537         ok(module_name != NULL, "Imported module name should not be NULL\n");
538         ok(name_table != NULL,
539                 "Name table for imported module %s should not be NULL\n",
540                 module_name);
541         ok(iat != NULL, "IAT for imported module %s should not be NULL\n",
542                 module_name);
543     }
544 }
545
546 START_TEST(loader)
547 {
548     test_Loader();
549     test_ImportDescriptors();
550 }