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