Merge pull request #3106 from lambdageek/dev/monoerror-unhandled
[mono.git] / mono / metadata / coree.c
1 /*
2  * coree.c: mscoree.dll functions
3  *
4  * Author:
5  *   Kornel Pal <http://www.kornelpal.hu/>
6  *
7  * Copyright (C) 2008 Kornel Pal
8  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
9  */
10
11 #include <config.h>
12
13 #ifdef HOST_WIN32
14
15 #include <string.h>
16 #include <glib.h>
17 #include <mono/io-layer/io-layer.h>
18 #include <mono/utils/mono-path.h>
19 #include "cil-coff.h"
20 #include "metadata-internals.h"
21 #include "image.h"
22 #include "assembly.h"
23 #include "domain-internals.h"
24 #include "appdomain.h"
25 #include "object.h"
26 #include "object-internals.h"
27 #include "loader.h"
28 #include "threads.h"
29 #include "environment.h"
30 #include "coree.h"
31
32 #include <shellapi.h>
33
34 HMODULE coree_module_handle = NULL;
35
36 static gboolean init_from_coree = FALSE;
37
38 gchar*
39 mono_get_module_file_name (HMODULE module_handle)
40 {
41         gunichar2* file_name;
42         gchar* file_name_utf8;
43         DWORD buffer_size;
44         DWORD size;
45
46         buffer_size = 1024;
47         file_name = g_new (gunichar2, buffer_size);
48
49         for (;;) {
50                 size = GetModuleFileName (module_handle, file_name, buffer_size);
51                 if (!size) {
52                         g_free (file_name);
53                         return NULL;
54                 }
55
56                 g_assert (size <= buffer_size);
57                 if (size != buffer_size)
58                         break;
59
60                 buffer_size += 1024;
61                 file_name = g_realloc (file_name, buffer_size * sizeof (gunichar2));
62         }
63
64         file_name_utf8 = g_utf16_to_utf8 (file_name, size, NULL, NULL, NULL);
65         g_free (file_name);
66
67         return file_name_utf8;
68 }
69
70 /* Entry point called by LdrLoadDll of ntdll.dll after _CorValidateImage. */
71 BOOL STDMETHODCALLTYPE _CorDllMain(HINSTANCE hInst, DWORD dwReason, LPVOID lpReserved)
72 {
73         MonoAssembly* assembly;
74         MonoImage* image;
75         gchar* file_name;
76         gchar* error;
77
78         switch (dwReason)
79         {
80         case DLL_PROCESS_ATTACH:
81                 DisableThreadLibraryCalls (hInst);
82
83                 file_name = mono_get_module_file_name (hInst);
84
85                 if (mono_get_root_domain ()) {
86                         image = mono_image_open_from_module_handle (hInst, mono_path_resolve_symlinks (file_name), TRUE, NULL);
87                 } else {
88                         init_from_coree = TRUE;
89                         mono_runtime_load (file_name, NULL);
90                         error = (gchar*) mono_check_corlib_version ();
91                         if (error) {
92                                 g_free (error);
93                                 g_free (file_name);
94                                 mono_runtime_quit ();
95                                 return FALSE;
96                         }
97
98                         image = mono_image_open (file_name, NULL);
99                         if (image) {
100                                 image->has_entry_point = TRUE;
101                                 mono_close_exe_image ();
102                                 /* Decrement reference count to zero. (Image will not be closed.) */
103                                 mono_image_close (image);
104                         }
105                 }
106
107                 if (!image) {
108                         g_free (file_name);
109                         return FALSE;
110                 }
111
112                 /*
113                  * FIXME: Find a better way to call mono_image_fixup_vtable. Only
114                  * loader trampolines should be used and assembly loading should
115                  * probably be delayed until the first call to an exported function.
116                  */
117                 if (image->tables [MONO_TABLE_ASSEMBLY].rows && ((MonoCLIImageInfo*) image->image_info)->cli_cli_header.ch_vtable_fixups.rva)
118                         assembly = mono_assembly_open (file_name, NULL);
119
120                 g_free (file_name);
121                 break;
122         case DLL_PROCESS_DETACH:
123                 if (lpReserved != NULL)
124                         /* The process is terminating. */
125                         return TRUE;
126                 file_name = mono_get_module_file_name (hInst);
127                 image = mono_image_loaded (file_name);
128                 if (image)
129                         mono_image_close (image);
130
131                 g_free (file_name);
132                 break;
133         }
134
135         return TRUE;
136 }
137
138 /* Called by ntdll.dll reagardless of entry point after _CorValidateImage. */
139 __int32 STDMETHODCALLTYPE _CorExeMain(void)
140 {
141         MonoError error;
142         MonoDomain* domain;
143         MonoAssembly* assembly;
144         MonoImage* image;
145         MonoMethod* method;
146         guint32 entry;
147         gchar* file_name;
148         gchar* corlib_version_error;
149         int argc;
150         gunichar2** argvw;
151         gchar** argv;
152         int i;
153
154         file_name = mono_get_module_file_name (NULL);
155         init_from_coree = TRUE;
156         domain = mono_runtime_load (file_name, NULL);
157
158         corlib_version_error = (gchar*) mono_check_corlib_version ();
159         if (corlib_version_error) {
160                 g_free (corlib_version_error);
161                 g_free (file_name);
162                 MessageBox (NULL, L"Corlib not in sync with this runtime.", NULL, MB_ICONERROR);
163                 mono_runtime_quit ();
164                 ExitProcess (1);
165         }
166
167         assembly = mono_assembly_open (file_name, NULL);
168         mono_close_exe_image ();
169         if (!assembly) {
170                 g_free (file_name);
171                 MessageBox (NULL, L"Cannot open assembly.", NULL, MB_ICONERROR);
172                 mono_runtime_quit ();
173                 ExitProcess (1);
174         }
175
176         image = assembly->image;
177         entry = mono_image_get_entry_point (image);
178         if (!entry) {
179                 g_free (file_name);
180                 MessageBox (NULL, L"Assembly doesn't have an entry point.", NULL, MB_ICONERROR);
181                 mono_runtime_quit ();
182                 ExitProcess (1);
183         }
184
185         method = mono_get_method_checked (image, entry, NULL, NULL, &error);
186         if (method == NULL) {
187                 g_free (file_name);
188                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
189                 MessageBox (NULL, L"The entry point method could not be loaded.", NULL, MB_ICONERROR);
190                 mono_runtime_quit ();
191                 ExitProcess (1);
192         }
193
194         argvw = CommandLineToArgvW (GetCommandLine (), &argc);
195         argv = g_new0 (gchar*, argc);
196         argv [0] = file_name;
197         for (i = 1; i < argc; ++i)
198                 argv [i] = g_utf16_to_utf8 (argvw [i], -1, NULL, NULL, NULL);
199         LocalFree (argvw);
200
201         mono_runtime_run_main_checked (method, argc, argv, &error);
202         mono_error_raise_exception (&error); /* OK, triggers unhandled exn handler */
203         mono_thread_manage ();
204
205         mono_runtime_quit ();
206
207         /* return does not terminate the process. */
208         ExitProcess (mono_environment_exitcode_get ());
209 }
210
211 /* Called by msvcrt.dll when shutting down. */
212 void STDMETHODCALLTYPE CorExitProcess(int exitCode)
213 {
214         /* FIXME: This is not currently supported by the runtime. */
215 #if 0
216         if (mono_get_root_domain () && !mono_runtime_is_shutting_down ()) {
217                 mono_runtime_set_shutting_down ();
218                 mono_thread_suspend_all_other_threads ();
219                 mono_runtime_quit ();
220         }
221 #endif
222         ExitProcess (exitCode);
223 }
224
225 /* Called by ntdll.dll before _CorDllMain and _CorExeMain. */
226 STDAPI _CorValidateImage(PVOID *ImageBase, LPCWSTR FileName)
227 {
228         IMAGE_DOS_HEADER* DosHeader;
229         IMAGE_NT_HEADERS32* NtHeaders32;
230         IMAGE_DATA_DIRECTORY* CliHeaderDir;
231 #ifdef _WIN64
232         IMAGE_NT_HEADERS64* NtHeaders64;
233         MonoCLIHeader* CliHeader;
234         DWORD SizeOfHeaders;
235 #endif
236         DWORD* Address;
237         DWORD OldProtect;
238
239         DosHeader = (IMAGE_DOS_HEADER*)*ImageBase;
240         if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE)
241                 return STATUS_INVALID_IMAGE_FORMAT;
242
243         NtHeaders32 = (IMAGE_NT_HEADERS32*)((DWORD_PTR)DosHeader + DosHeader->e_lfanew);
244         if (NtHeaders32->Signature != IMAGE_NT_SIGNATURE)
245                 return STATUS_INVALID_IMAGE_FORMAT;
246
247 #ifdef _WIN64
248         NtHeaders64 = (IMAGE_NT_HEADERS64*)NtHeaders32;
249         if (NtHeaders64->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
250         {
251                 if (NtHeaders64->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
252                         return STATUS_INVALID_IMAGE_FORMAT;
253
254                 CliHeaderDir = &NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];
255                 if (!CliHeaderDir->VirtualAddress)
256                         return STATUS_INVALID_IMAGE_FORMAT;
257
258                 CliHeader = (MonoCLIHeader*)((DWORD_PTR)DosHeader + CliHeaderDir->VirtualAddress);
259                 if (CliHeader->ch_flags & CLI_FLAGS_32BITREQUIRED)
260                         return STATUS_INVALID_IMAGE_FORMAT;
261
262                 if (CliHeader->ch_flags & CLI_FLAGS_ILONLY)
263                 {
264                         /* Avoid calling _CorDllMain because imports are not resolved for IL only images. */
265                         if (NtHeaders64->OptionalHeader.AddressOfEntryPoint != 0)
266                         {
267                                 Address = &NtHeaders64->OptionalHeader.AddressOfEntryPoint;
268                                 if (!VirtualProtect(Address, sizeof(DWORD), PAGE_READWRITE, &OldProtect))
269                                         return E_UNEXPECTED;
270                                 *Address = (DWORD)0;
271                                 if (!VirtualProtect(Address, sizeof(DWORD), OldProtect, &OldProtect))
272                                         return E_UNEXPECTED;
273                         }
274                 }
275
276                 return STATUS_SUCCESS;
277         }
278
279         if (NtHeaders32->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
280                 return STATUS_INVALID_IMAGE_FORMAT;
281
282         if (NtHeaders32->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
283                 return STATUS_INVALID_IMAGE_FORMAT;
284
285         CliHeaderDir = &NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];
286         if (!CliHeaderDir->VirtualAddress)
287                 return STATUS_INVALID_IMAGE_FORMAT;
288
289         CliHeader = (MonoCLIHeader*)((DWORD_PTR)DosHeader + CliHeaderDir->VirtualAddress);
290         if (!(CliHeader->ch_flags & CLI_FLAGS_ILONLY) || (CliHeader->ch_flags & CLI_FLAGS_32BITREQUIRED))
291                 return STATUS_INVALID_IMAGE_FORMAT;
292
293         /* Fixup IMAGE_NT_HEADERS32 to IMAGE_NT_HEADERS64. */
294         SizeOfHeaders = NtHeaders32->OptionalHeader.SizeOfHeaders;
295         if (SizeOfHeaders < DosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS64) + (sizeof(IMAGE_SECTION_HEADER) * NtHeaders32->FileHeader.NumberOfSections))
296                 return STATUS_INVALID_IMAGE_FORMAT;
297
298         if (!VirtualProtect(DosHeader, SizeOfHeaders, PAGE_READWRITE, &OldProtect))
299                 return E_UNEXPECTED;
300
301         memmove(NtHeaders64 + 1, IMAGE_FIRST_SECTION(NtHeaders32), sizeof(IMAGE_SECTION_HEADER) * NtHeaders32->FileHeader.NumberOfSections);
302
303         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1].Size = 0;
304         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1].VirtualAddress = 0;
305         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size;
306         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress;
307         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size = 0;
308         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress = 0;
309         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = 0;
310         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = 0;
311         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;
312         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;
313         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size = 0;
314         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress = 0;
315         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size = 0;
316         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = 0;
317         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_GLOBALPTR].Size = 0;
318         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_GLOBALPTR].VirtualAddress = 0;
319         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_ARCHITECTURE].Size = 0;
320         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_ARCHITECTURE].VirtualAddress = 0;
321         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
322         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
323         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
324         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
325         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
326         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress;
327         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size = 0;
328         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress = 0;
329         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size;
330         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
331         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = 0;
332         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = 0;
333         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = 0;
334         NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = 0;
335
336         NtHeaders64->OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
337         NtHeaders64->OptionalHeader.LoaderFlags = NtHeaders32->OptionalHeader.LoaderFlags;
338         NtHeaders64->OptionalHeader.SizeOfHeapCommit = (ULONGLONG)NtHeaders32->OptionalHeader.SizeOfHeapCommit;
339         NtHeaders64->OptionalHeader.SizeOfHeapReserve = (ULONGLONG)NtHeaders32->OptionalHeader.SizeOfHeapReserve;
340         NtHeaders64->OptionalHeader.SizeOfStackCommit = (ULONGLONG)NtHeaders32->OptionalHeader.SizeOfStackCommit;
341         NtHeaders64->OptionalHeader.SizeOfStackReserve = (ULONGLONG)NtHeaders32->OptionalHeader.SizeOfStackReserve;
342         NtHeaders64->OptionalHeader.DllCharacteristics = NtHeaders32->OptionalHeader.DllCharacteristics;
343         NtHeaders64->OptionalHeader.Subsystem = NtHeaders32->OptionalHeader.Subsystem;
344         NtHeaders64->OptionalHeader.CheckSum = NtHeaders32->OptionalHeader.CheckSum;
345         NtHeaders64->OptionalHeader.SizeOfHeaders = NtHeaders32->OptionalHeader.SizeOfHeaders;
346         NtHeaders64->OptionalHeader.SizeOfImage = NtHeaders32->OptionalHeader.SizeOfImage;
347         NtHeaders64->OptionalHeader.Win32VersionValue = NtHeaders32->OptionalHeader.Win32VersionValue;
348         NtHeaders64->OptionalHeader.MinorSubsystemVersion = NtHeaders32->OptionalHeader.MinorSubsystemVersion;
349         NtHeaders64->OptionalHeader.MajorSubsystemVersion = NtHeaders32->OptionalHeader.MajorSubsystemVersion;
350         NtHeaders64->OptionalHeader.MinorImageVersion = NtHeaders32->OptionalHeader.MinorImageVersion;
351         NtHeaders64->OptionalHeader.MajorImageVersion = NtHeaders32->OptionalHeader.MajorImageVersion;
352         NtHeaders64->OptionalHeader.MinorOperatingSystemVersion = NtHeaders32->OptionalHeader.MinorOperatingSystemVersion;
353         NtHeaders64->OptionalHeader.MajorOperatingSystemVersion = NtHeaders32->OptionalHeader.MajorOperatingSystemVersion;
354         NtHeaders64->OptionalHeader.FileAlignment = NtHeaders32->OptionalHeader.FileAlignment;
355         NtHeaders64->OptionalHeader.SectionAlignment = NtHeaders32->OptionalHeader.SectionAlignment;
356         NtHeaders64->OptionalHeader.ImageBase = (ULONGLONG)NtHeaders32->OptionalHeader.ImageBase;
357         /* BaseOfCode is at the same offset. */
358         NtHeaders64->OptionalHeader.AddressOfEntryPoint = 0;
359         NtHeaders64->OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC;
360         NtHeaders64->FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER64);
361
362         if (!VirtualProtect(DosHeader, SizeOfHeaders, OldProtect, &OldProtect))
363                 return E_UNEXPECTED;
364 #else
365         if (NtHeaders32->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
366                 return STATUS_INVALID_IMAGE_FORMAT;
367
368         if (NtHeaders32->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
369                 return STATUS_INVALID_IMAGE_FORMAT;
370
371         CliHeaderDir = &NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];
372         if (!CliHeaderDir->VirtualAddress)
373                 return STATUS_INVALID_IMAGE_FORMAT;
374
375         Address = &NtHeaders32->OptionalHeader.AddressOfEntryPoint;
376         if (!VirtualProtect(Address, sizeof(DWORD), PAGE_READWRITE, &OldProtect))
377                 return E_UNEXPECTED;
378         if (NtHeaders32->FileHeader.Characteristics & IMAGE_FILE_DLL)
379                 *Address = (DWORD)((DWORD_PTR)&_CorDllMain - (DWORD_PTR)DosHeader);
380         else
381                 *Address = (DWORD)((DWORD_PTR)&_CorExeMain - (DWORD_PTR)DosHeader);
382         if (!VirtualProtect(Address, sizeof(DWORD), OldProtect, &OldProtect))
383                 return E_UNEXPECTED;
384 #endif
385
386         return STATUS_SUCCESS;
387 }
388
389 /* Called by ntdll.dll. */
390 STDAPI_(VOID) _CorImageUnloading(PVOID ImageBase)
391 {
392         /* Nothing to do. */
393 }
394
395 STDAPI CorBindToRuntimeEx(LPCWSTR pwszVersion, LPCWSTR pwszBuildFlavor, DWORD startupFlags, REFCLSID rclsid, REFIID riid, LPVOID FAR *ppv)
396 {
397         if (ppv == NULL)
398                 return E_POINTER;
399
400         *ppv = NULL;
401         return E_NOTIMPL;
402 }
403
404 STDAPI CorBindToRuntime(LPCWSTR pwszVersion, LPCWSTR pwszBuildFlavor, REFCLSID rclsid, REFIID riid, LPVOID FAR *ppv)
405 {
406         return CorBindToRuntimeEx (pwszVersion, pwszBuildFlavor, 0, rclsid, riid, ppv);
407 }
408
409 HMODULE WINAPI MonoLoadImage(LPCWSTR FileName)
410 {
411         HANDLE FileHandle;
412         DWORD FileSize;
413         HANDLE MapHandle;
414         IMAGE_DOS_HEADER* DosHeader;
415         IMAGE_NT_HEADERS32* NtHeaders32;
416 #ifdef _WIN64
417         IMAGE_NT_HEADERS64* NtHeaders64;
418 #endif
419         HMODULE ModuleHandle;
420
421         FileHandle = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
422         if (FileHandle == INVALID_HANDLE_VALUE)
423                 return NULL;
424
425         FileSize = GetFileSize(FileHandle, NULL); 
426         if (FileSize == INVALID_FILE_SIZE)
427                 goto CloseFile;
428
429         MapHandle = CreateFileMapping(FileHandle, NULL, PAGE_READONLY, 0, 0, NULL);
430         if (MapHandle == NULL)
431                 goto CloseFile;
432
433         DosHeader = (IMAGE_DOS_HEADER*)MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0);
434         if (DosHeader == NULL)
435                 goto CloseMap;
436
437         if (FileSize < sizeof(IMAGE_DOS_HEADER) || DosHeader->e_magic != IMAGE_DOS_SIGNATURE || FileSize < DosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS32))
438                 goto InvalidImageFormat;
439
440         NtHeaders32 = (IMAGE_NT_HEADERS32*)((DWORD_PTR)DosHeader + DosHeader->e_lfanew);
441         if (NtHeaders32->Signature != IMAGE_NT_SIGNATURE)
442                 goto InvalidImageFormat;
443
444 #ifdef _WIN64
445         NtHeaders64 = (IMAGE_NT_HEADERS64*)NtHeaders32;
446         if (NtHeaders64->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
447         {
448                 if (FileSize < DosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS64) ||
449                         NtHeaders64->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR ||
450                         !NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress)
451                                 goto InvalidImageFormat;
452
453                 goto ValidImage;
454         }
455 #endif
456
457         if (NtHeaders32->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC ||
458                 NtHeaders32->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR ||
459                 !NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress)
460         {
461 InvalidImageFormat:
462                 SetLastError(STATUS_INVALID_IMAGE_FORMAT);
463                 goto UnmapView;
464         }
465
466 #ifdef _WIN64
467 ValidImage:
468 #endif
469         UnmapViewOfFile(DosHeader);
470         CloseHandle(MapHandle);
471
472         ModuleHandle = LoadLibrary(FileName);
473
474         CloseHandle(FileHandle);
475         return ModuleHandle;
476
477 UnmapView:
478         UnmapViewOfFile(DosHeader);
479 CloseMap:
480         CloseHandle(MapHandle);
481 CloseFile:
482         CloseHandle(FileHandle);
483         return NULL;
484 }
485
486 typedef struct _EXPORT_FIXUP
487 {
488         LPCSTR Name;
489         union
490         {
491                 PVOID Pointer;
492                 DWORD_PTR DWordPtr;
493                 BYTE Bytes[sizeof(PVOID)];
494 #ifdef _M_IA64
495                 PLABEL_DESCRIPTOR* PLabel;
496 #endif
497         } ProcAddress;
498 } EXPORT_FIXUP;
499
500 /* Has to be binary ordered. */
501 static const EXPORT_FIXUP ExportFixups[] = {
502         {"CorBindToRuntime", &CorBindToRuntime},
503         {"CorBindToRuntimeEx", &CorBindToRuntimeEx},
504         {"CorExitProcess", &CorExitProcess},
505         {"_CorDllMain", &_CorDllMain},
506         {"_CorExeMain", &_CorExeMain},
507         {"_CorImageUnloading", &_CorImageUnloading},
508         {"_CorValidateImage", &_CorValidateImage},
509         {NULL, NULL}
510 };
511
512 #define EXPORT_FIXUP_COUNT (sizeof(ExportFixups) / sizeof(EXPORT_FIXUP) - 1)
513
514 static HMODULE ExportFixupModuleHandle = NULL;
515 static DWORD ExportFixupRvas[EXPORT_FIXUP_COUNT];
516
517 /* Fixup exported functions of mscoree.dll to our implementations. */
518 STDAPI MonoFixupCorEE(HMODULE ModuleHandle)
519 {
520         IMAGE_DOS_HEADER* DosHeader;
521         IMAGE_NT_HEADERS* NtHeaders;
522         IMAGE_DATA_DIRECTORY* ExportDataDir;
523         IMAGE_EXPORT_DIRECTORY* ExportDir;
524         DWORD* Functions;
525         DWORD* Names;
526         WORD* NameOrdinals;
527         EXPORT_FIXUP* ExportFixup;
528         DWORD* ExportFixupRva;
529         DWORD* Address;
530         DWORD OldProtect;
531         DWORD ProcRva;
532         DWORD i;
533         int cmp;
534 #ifdef _WIN64
535         MEMORY_BASIC_INFORMATION MemoryInfo;
536         PVOID Region;
537         PVOID RegionBase;
538         PVOID MaxRegionBase;
539 #ifdef _M_IA64
540         PLABEL_DESCRIPTOR* PLabel;
541
542 #define ELEMENT_SIZE sizeof(PLABEL_DESCRIPTOR)
543 #define REGION_WRITE_PROTECT PAGE_READWRITE
544 #define REGION_PROTECT PAGE_READ
545 #else
546         BYTE* Trampoline;
547
548 #define ELEMENT_SIZE 13
549 #define REGION_WRITE_PROTECT PAGE_EXECUTE_READWRITE
550 #define REGION_PROTECT PAGE_EXECUTE_READ
551 #endif
552 #endif
553
554         if (ExportFixupModuleHandle != NULL)
555                 return ModuleHandle == ExportFixupModuleHandle ? S_OK : E_FAIL;
556
557         DosHeader = (IMAGE_DOS_HEADER*)ModuleHandle;
558         if (DosHeader == NULL)
559                 return E_POINTER;
560
561         if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE)
562                 return E_INVALIDARG;
563
564         NtHeaders = (IMAGE_NT_HEADERS*)((DWORD_PTR)DosHeader + DosHeader->e_lfanew);
565         if (NtHeaders->Signature != IMAGE_NT_SIGNATURE)
566                 return E_INVALIDARG;
567
568         if (NtHeaders->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)
569                 return E_INVALIDARG;
570
571         if (NtHeaders->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_EXPORT)
572                 return E_FAIL;
573
574         ExportDataDir = &NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
575         if (!ExportDataDir->VirtualAddress)
576                 return E_FAIL;
577
578 #ifdef _WIN64
579         /* Allocate memory after base address because RVAs are 32-bit unsigned integers. */
580         RegionBase = DosHeader;
581         MaxRegionBase = (PVOID)((DWORD_PTR)RegionBase + (DWORD_PTR)(0x100000000L - (ELEMENT_SIZE * (EXPORT_FIXUP_COUNT - 1))));
582         for (;;)
583         {
584                 if (!VirtualQuery(RegionBase, &MemoryInfo, sizeof(MEMORY_BASIC_INFORMATION)))
585                         return E_UNEXPECTED;
586                 if (MemoryInfo.State == MEM_FREE && MemoryInfo.RegionSize >= ELEMENT_SIZE * EXPORT_FIXUP_COUNT)
587                 {
588                         Region = VirtualAlloc(RegionBase, ELEMENT_SIZE * EXPORT_FIXUP_COUNT, MEM_COMMIT | MEM_RESERVE, REGION_WRITE_PROTECT);
589                         if (Region != NULL)
590                                 break;
591                 }
592                 RegionBase = (PVOID)((DWORD_PTR)MemoryInfo.BaseAddress + (DWORD_PTR)MemoryInfo.RegionSize);
593                 if (RegionBase > MaxRegionBase)
594                         return E_OUTOFMEMORY;
595         }
596
597 #ifdef _M_IA64
598         PLabel = (PLABEL_DESCRIPTOR*)Region;
599 #else
600         Trampoline = (BYTE*)Region;
601 #endif
602 #endif
603
604         ExportDir = (IMAGE_EXPORT_DIRECTORY*)((DWORD_PTR)DosHeader + ExportDataDir->VirtualAddress);
605         Functions = (DWORD*)((DWORD_PTR)DosHeader + ExportDir->AddressOfFunctions);
606         Names = (DWORD*)((DWORD_PTR)DosHeader + ExportDir->AddressOfNames);
607         NameOrdinals = (WORD*)((DWORD_PTR)DosHeader + ExportDir->AddressOfNameOrdinals);
608         ExportFixup = (EXPORT_FIXUP*)&ExportFixups;
609         ExportFixupRva = (DWORD*)&ExportFixupRvas;
610
611         for (i = 0; i < ExportDir->NumberOfNames; i++)
612         {
613                 cmp = strcmp((LPCSTR)((DWORD_PTR)DosHeader + Names[i]), ExportFixup->Name);
614                 if (cmp > 0)
615                         return E_FAIL;
616
617                 if (cmp == 0)
618                 {
619 #ifdef _WIN64
620 #if defined(_M_IA64)
621                         ProcRva = (DWORD)((DWORD_PTR)PLabel - (DWORD_PTR)DosHeader);
622                         *(PLabel)++ = *ExportFixup->ProcAddress.PLabel;
623 #elif defined(_M_AMD64)
624                         ProcRva = (DWORD)((DWORD_PTR)Trampoline - (DWORD_PTR)DosHeader);
625                         /* mov r11, ExportFixup->ProcAddress */
626                         *(Trampoline)++ = 0x49;
627                         *(Trampoline)++ = 0xBB;
628                         *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[0];
629                         *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[1];
630                         *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[2];
631                         *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[3];
632                         *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[4];
633                         *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[5];
634                         *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[6];
635                         *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[7];
636                         /* jmp r11 */
637                         *(Trampoline)++ = 0x41;
638                         *(Trampoline)++ = 0xFF;
639                         *(Trampoline)++ = 0xE3;
640 #else
641 #error Unsupported architecture.
642 #endif
643 #else
644                         ProcRva = (DWORD)(ExportFixup->ProcAddress.DWordPtr - (DWORD_PTR)DosHeader);
645 #endif
646                         Address = &Functions[NameOrdinals[i]];
647                         if (!VirtualProtect(Address, sizeof(DWORD), PAGE_READWRITE, &OldProtect))
648                                 return E_UNEXPECTED;
649                         *ExportFixupRva = *Address;
650                         *Address = ProcRva;
651                         if (!VirtualProtect(Address, sizeof(DWORD), OldProtect, &OldProtect))
652                                 return E_UNEXPECTED;
653                         ExportFixup++;
654                         if (ExportFixup->Name == NULL) {
655 #ifdef _WIN64
656                                 if (!VirtualProtect(Region, ELEMENT_SIZE * EXPORT_FIXUP_COUNT, REGION_PROTECT, &OldProtect))
657                                         return E_UNEXPECTED;
658 #endif
659
660                                 ExportFixupModuleHandle = ModuleHandle;
661                                 return S_OK;
662                         }
663                         ExportFixupRva++;
664                 }
665         }
666         return E_FAIL;
667 }
668
669 /* Executable images are only mapped by the OS loader. We need to do fixups for native code support. */
670 STDAPI MonoFixupExe(HMODULE ModuleHandle)
671 {
672         IMAGE_DOS_HEADER* DosHeader;
673         IMAGE_NT_HEADERS* NtHeaders;
674         DWORD_PTR* Address;
675         DWORD OldProtect;
676         DWORD_PTR BaseDiff;
677
678         DosHeader = (IMAGE_DOS_HEADER*)ModuleHandle;
679         if (DosHeader == NULL)
680                 return E_POINTER;
681
682         if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE)
683                 return E_INVALIDARG;
684
685         NtHeaders = (IMAGE_NT_HEADERS*)((DWORD_PTR)DosHeader + DosHeader->e_lfanew);
686         if (NtHeaders->Signature != IMAGE_NT_SIGNATURE)
687                 return E_INVALIDARG;
688
689         if (NtHeaders->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)
690                 return E_INVALIDARG;
691
692         if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL)
693                 return S_OK;
694
695         if (NtHeaders->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
696         {
697                 IMAGE_DATA_DIRECTORY* CliHeaderDir;
698                 MonoCLIHeader* CliHeader;
699
700                 CliHeaderDir = &NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];
701                 if (CliHeaderDir->VirtualAddress)
702                 {
703                         CliHeader = (MonoCLIHeader*)((DWORD_PTR)DosHeader + CliHeaderDir->VirtualAddress);
704                         if (CliHeader->ch_flags & CLI_FLAGS_ILONLY)
705                                 return S_OK;
706                 }
707         }
708
709         BaseDiff = (DWORD_PTR)DosHeader - NtHeaders->OptionalHeader.ImageBase;
710         if (BaseDiff != 0)
711         {
712                 if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
713                         return E_FAIL;
714
715                 Address = &NtHeaders->OptionalHeader.ImageBase;
716                 if (!VirtualProtect(Address, sizeof(DWORD_PTR), PAGE_READWRITE, &OldProtect))
717                         return E_UNEXPECTED;
718                 *Address = (DWORD_PTR)DosHeader;
719                 if (!VirtualProtect(Address, sizeof(DWORD_PTR), OldProtect, &OldProtect))
720                         return E_UNEXPECTED;
721
722                 if (NtHeaders->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_BASERELOC)
723                 {
724                         IMAGE_DATA_DIRECTORY* BaseRelocDir;
725                         IMAGE_BASE_RELOCATION* BaseReloc;
726                         USHORT* RelocBlock;
727                         ULONG BaseRelocSize;
728                         ULONG RelocBlockSize;
729                         USHORT RelocOffset;
730                         DWORD_PTR UNALIGNED *RelocFixup;
731
732                         BaseRelocDir = &NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
733                         if (BaseRelocDir->VirtualAddress)
734                         {
735                                 BaseReloc = (IMAGE_BASE_RELOCATION*)((DWORD_PTR)DosHeader + BaseRelocDir->VirtualAddress);
736                                 BaseRelocSize = BaseRelocDir->Size;
737
738                                 while (BaseRelocSize)
739                                 {
740                                         RelocBlockSize = BaseReloc->SizeOfBlock;
741
742                                         if (!RelocBlockSize || BaseRelocSize < RelocBlockSize)
743                                                 return E_FAIL;
744
745                                         BaseRelocSize -= RelocBlockSize;
746                                         RelocBlock = (USHORT*)((DWORD_PTR)BaseReloc + sizeof(IMAGE_BASE_RELOCATION));
747                                         RelocBlockSize -= sizeof(IMAGE_BASE_RELOCATION);
748                                         RelocBlockSize /= sizeof(USHORT);
749
750                                         while (RelocBlockSize-- != 0)
751                                         {
752                                                 RelocOffset = *RelocBlock & (USHORT)0x0fff;
753                                                 RelocFixup = (DWORD_PTR*)((DWORD_PTR)DosHeader + BaseReloc->VirtualAddress + RelocOffset);
754
755                                                 switch (*RelocBlock >> 12)
756                                                 {
757                                                         case IMAGE_REL_BASED_ABSOLUTE:
758                                                                 break;
759
760 #ifdef _WIN64
761                                                         case IMAGE_REL_BASED_DIR64:
762 #else
763                                                         case IMAGE_REL_BASED_HIGHLOW:
764 #endif
765                                                                 if (!VirtualProtect(RelocFixup, sizeof(DWORD_PTR), PAGE_EXECUTE_READWRITE, &OldProtect))
766                                                                         return E_UNEXPECTED;
767                                                                 *RelocFixup += BaseDiff;
768                                                                 if (!VirtualProtect(RelocFixup, sizeof(DWORD_PTR), OldProtect, &OldProtect))
769                                                                         return E_UNEXPECTED;
770                                                                 break;
771
772                                                         default:
773                                                                 return E_FAIL;
774                                                 }
775
776                                                 RelocBlock++;
777                                         }
778                                         BaseReloc = (IMAGE_BASE_RELOCATION*)RelocBlock;
779                                 }
780                         }
781                 }
782         }
783
784         if (NtHeaders->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_IMPORT)
785         {
786                 IMAGE_DATA_DIRECTORY* ImportDir;
787                 IMAGE_IMPORT_DESCRIPTOR* ImportDesc;
788                 HMODULE ImportModuleHandle;
789                 IMAGE_THUNK_DATA* ImportThunkData;
790                 DWORD_PTR ProcAddress;
791
792                 ImportDir = &NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
793                 if (ImportDir->VirtualAddress != 0)
794                 {
795                         ImportDesc = (IMAGE_IMPORT_DESCRIPTOR*)((DWORD_PTR)DosHeader + ImportDir->VirtualAddress);
796                         while (ImportDesc->Name && ImportDesc->OriginalFirstThunk)
797                         {
798                                 ImportModuleHandle = LoadLibraryA((PCSTR)((DWORD_PTR)DosHeader + ImportDesc->Name));
799                                 if (ImportModuleHandle == NULL)
800                                         return E_FAIL;
801
802                                 ImportThunkData = (IMAGE_THUNK_DATA*)((DWORD_PTR)DosHeader + ImportDesc->OriginalFirstThunk);
803                                 while (ImportThunkData->u1.Ordinal != 0)
804                                 {
805                                         if (IMAGE_SNAP_BY_ORDINAL(ImportThunkData->u1.Ordinal))
806                                                 ProcAddress = (DWORD_PTR)GetProcAddress(ImportModuleHandle, (LPCSTR)IMAGE_ORDINAL(ImportThunkData->u1.Ordinal));
807                                         else
808                                         {
809                                                 IMAGE_IMPORT_BY_NAME* ImportByName = (IMAGE_IMPORT_BY_NAME*)((DWORD_PTR)DosHeader + ImportThunkData->u1.AddressOfData);
810                                                 ProcAddress = (DWORD_PTR)GetProcAddress(ImportModuleHandle, ImportByName->Name);
811                                         }
812                                         if (ProcAddress == 0)
813                                                 return E_FAIL;
814                                         Address = (DWORD_PTR*)((DWORD_PTR)ImportThunkData - ImportDesc->OriginalFirstThunk + ImportDesc->FirstThunk);
815                                         if (!VirtualProtect(Address, sizeof(DWORD_PTR), PAGE_READWRITE, &OldProtect))
816                                                 return E_UNEXPECTED;
817                                         *Address = ProcAddress;
818                                         if (!VirtualProtect(Address, sizeof(DWORD_PTR), OldProtect, &OldProtect))
819                                                 return E_UNEXPECTED;
820                                         ImportThunkData++;
821                                 }
822
823                                 ImportDesc++;
824                         }
825                 }
826         }
827
828         return S_OK;
829 }
830
831 static void
832 mono_set_act_ctx (const char* file_name)
833 {
834         typedef HANDLE (WINAPI* CREATEACTCTXW_PROC) (PCACTCTXW pActCtx);
835         typedef BOOL (WINAPI* ACTIVATEACTCTX_PROC) (HANDLE hActCtx, ULONG_PTR* lpCookie);
836
837         HMODULE kernel32_handle;
838         CREATEACTCTXW_PROC CreateActCtx_proc;
839         ACTIVATEACTCTX_PROC ActivateActCtx_proc;
840         gchar* full_path;
841         gunichar2* full_path_utf16;
842         gchar* dir_name;
843         gunichar2* dir_name_utf16;
844         gchar* base_name;
845         gunichar2* base_name_utf16;
846         ACTCTX act_ctx;
847         HANDLE handle;
848         ULONG_PTR cookie;
849
850         kernel32_handle = GetModuleHandle (L"kernel32.dll");
851         if (!kernel32_handle)
852                 return;
853         CreateActCtx_proc = (CREATEACTCTXW_PROC) GetProcAddress (kernel32_handle, "CreateActCtxW");
854         if (!CreateActCtx_proc)
855                 return;
856         ActivateActCtx_proc = (ACTIVATEACTCTX_PROC) GetProcAddress (kernel32_handle, "ActivateActCtx");
857         if (!ActivateActCtx_proc)
858                 return;
859
860         full_path = mono_path_canonicalize (file_name);
861         full_path_utf16 = g_utf8_to_utf16 (full_path, -1, NULL, NULL, NULL);
862         dir_name = g_path_get_dirname (full_path);
863         dir_name_utf16 = g_utf8_to_utf16 (dir_name, -1, NULL, NULL, NULL);
864         base_name = g_path_get_basename (full_path);
865         base_name_utf16 = g_utf8_to_utf16 (base_name, -1, NULL, NULL, NULL);
866         g_free (base_name);
867         g_free (dir_name);
868         g_free (full_path);
869
870         memset (&act_ctx, 0, sizeof (ACTCTX));
871         act_ctx.cbSize = sizeof (ACTCTX);
872         act_ctx.dwFlags = ACTCTX_FLAG_SET_PROCESS_DEFAULT | ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID | ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_APPLICATION_NAME_VALID;
873         act_ctx.lpSource = full_path_utf16;
874         act_ctx.lpAssemblyDirectory = dir_name_utf16;
875         act_ctx.lpResourceName = MAKEINTRESOURCE (CREATEPROCESS_MANIFEST_RESOURCE_ID);
876         act_ctx.lpApplicationName = base_name_utf16;
877
878         handle = CreateActCtx_proc (&act_ctx);
879         if (handle == INVALID_HANDLE_VALUE && GetLastError () == ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET) {
880                 act_ctx.dwFlags &= ~ACTCTX_FLAG_SET_PROCESS_DEFAULT;
881                 handle = CreateActCtx_proc (&act_ctx);
882         }
883
884         g_free (base_name_utf16);
885         g_free (dir_name_utf16);
886         g_free (full_path_utf16);
887
888         if (handle != INVALID_HANDLE_VALUE)
889                 ActivateActCtx_proc (handle, &cookie);
890 }
891
892 void
893 mono_load_coree (const char* exe_file_name)
894 {
895         HMODULE module_handle;
896         gunichar2* file_name;
897         UINT required_size;
898         UINT size;
899
900         if (coree_module_handle)
901                 return;
902
903         if (!init_from_coree && exe_file_name)
904                 mono_set_act_ctx (exe_file_name);
905
906         /* ntdll.dll loads mscoree.dll from the system32 directory. */
907         required_size = GetSystemDirectory (NULL, 0);
908         file_name = g_new (gunichar2, required_size + 12);
909         size = GetSystemDirectory (file_name, required_size);
910         g_assert (size < required_size);
911         if (file_name [size - 1] != L'\\')
912                 file_name [size++] = L'\\';
913         memcpy (&file_name [size], L"mscoree.dll", 12 * sizeof (gunichar2));
914
915         module_handle = LoadLibrary (file_name);
916         g_free (file_name);
917
918         if (module_handle && !SUCCEEDED (MonoFixupCorEE (module_handle))) {
919                 FreeLibrary (module_handle);
920                 module_handle = NULL;
921         }
922
923         coree_module_handle = module_handle;
924 }
925
926 void
927 mono_fixup_exe_image (MonoImage* image)
928 {
929         if (!init_from_coree && image && image->is_module_handle)
930                 MonoFixupExe ((HMODULE) image->raw_data);
931 }
932
933 #endif /* HOST_WIN32 */