2009-07-30 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / metadata / coree.c
index c47a159edff8c2c2642a4b7224dc483df5f33439..ab879b9a6a883cabf91fe541452d42c3a933a64e 100644 (file)
 
 #ifdef PLATFORM_WIN32
 
+#if _WIN32_WINNT < 0x0501
+/* Required for ACTCTX. */
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#endif /* _WIN32_WINNT < 0x0501 */
+
 #include <string.h>
 #include <glib.h>
 #include <mono/io-layer/io-layer.h>
+#include <mono/utils/mono-path.h>
+#include "cil-coff.h"
 #include "metadata-internals.h"
 #include "image.h"
 #include "assembly.h"
+#include "domain-internals.h"
 #include "appdomain.h"
 #include "object.h"
 #include "loader.h"
 #include "environment.h"
 #include "coree.h"
 
-#define STATUS_SUCCESS 0x00000000L
-#define STATUS_INVALID_IMAGE_FORMAT 0xC000007BL
-
-typedef struct _EXPORT_FIXUP
-{
-       LPCSTR Name;
-       DWORD_PTR ProcAddress;
-} EXPORT_FIXUP;
-
-HMODULE mono_module_handle = NULL;
 HMODULE coree_module_handle = NULL;
 
+static gboolean init_from_coree = FALSE;
+
 gchar*
 mono_get_module_file_name (HMODULE module_handle)
 {
@@ -84,8 +85,9 @@ BOOL STDMETHODCALLTYPE _CorDllMain(HINSTANCE hInst, DWORD dwReason, LPVOID lpRes
                file_name = mono_get_module_file_name (hInst);
 
                if (mono_get_root_domain ()) {
-                       image = mono_image_open_from_module_handle (hInst, mono_path_resolve_symlinks (file_name), NULL);
+                       image = mono_image_open_from_module_handle (hInst, mono_path_resolve_symlinks (file_name), TRUE, NULL);
                } else {
+                       init_from_coree = TRUE;
                        mono_runtime_load (file_name, NULL);
                        error = (gchar*) mono_check_corlib_version ();
                        if (error) {
@@ -96,6 +98,12 @@ BOOL STDMETHODCALLTYPE _CorDllMain(HINSTANCE hInst, DWORD dwReason, LPVOID lpRes
                        }
 
                        image = mono_image_open (file_name, NULL);
+                       if (image) {
+                               image->has_entry_point = TRUE;
+                               mono_close_exe_image ();
+                               /* Decrement reference count to zero. (Image will not be closed.) */
+                               mono_image_close (image);
+                       }
                }
 
                if (!image) {
@@ -108,9 +116,20 @@ BOOL STDMETHODCALLTYPE _CorDllMain(HINSTANCE hInst, DWORD dwReason, LPVOID lpRes
                 * loader trampolines should be used and assembly loading should
                 * probably be delayed until the first call to an exported function.
                 */
-               if (image->tables [MONO_TABLE_ASSEMBLY].rows)
+               if (image->tables [MONO_TABLE_ASSEMBLY].rows && ((MonoCLIImageInfo*) image->image_info)->cli_cli_header.ch_vtable_fixups.rva)
                        assembly = mono_assembly_open (file_name, NULL);
 
+               g_free (file_name);
+               break;
+       case DLL_PROCESS_DETACH:
+               if (lpReserved != NULL)
+                       /* The process is terminating. */
+                       return TRUE;
+               file_name = mono_get_module_file_name (hInst);
+               image = mono_image_loaded (file_name);
+               if (image)
+                       mono_image_close (image);
+
                g_free (file_name);
                break;
        }
@@ -119,7 +138,7 @@ BOOL STDMETHODCALLTYPE _CorDllMain(HINSTANCE hInst, DWORD dwReason, LPVOID lpRes
 }
 
 /* Called by ntdll.dll reagardless of entry point after _CorValidateImage. */
-__int32 STDMETHODCALLTYPE _CorExeMain()
+__int32 STDMETHODCALLTYPE _CorExeMain(void)
 {
        MonoDomain* domain;
        MonoAssembly* assembly;
@@ -133,7 +152,8 @@ __int32 STDMETHODCALLTYPE _CorExeMain()
        gchar** argv;
        int i;
 
-       file_name = mono_get_module_file_name (GetModuleHandle (NULL));
+       file_name = mono_get_module_file_name (NULL);
+       init_from_coree = TRUE;
        domain = mono_runtime_load (file_name, NULL);
 
        error = (gchar*) mono_check_corlib_version ();
@@ -146,6 +166,7 @@ __int32 STDMETHODCALLTYPE _CorExeMain()
        }
 
        assembly = mono_assembly_open (file_name, NULL);
+       mono_close_exe_image ();
        if (!assembly) {
                g_free (file_name);
                MessageBox (NULL, L"Cannot open assembly.", NULL, MB_ICONERROR);
@@ -189,11 +210,14 @@ __int32 STDMETHODCALLTYPE _CorExeMain()
 /* Called by msvcrt.dll when shutting down. */
 void STDMETHODCALLTYPE CorExitProcess(int exitCode)
 {
-       if (!mono_runtime_is_shutting_down ()) {
+       /* FIXME: This is not currently supported by the runtime. */
+#if 0
+       if (mono_get_root_domain () && !mono_runtime_is_shutting_down ()) {
                mono_runtime_set_shutting_down ();
                mono_thread_suspend_all_other_threads ();
                mono_runtime_quit ();
        }
+#endif
        ExitProcess (exitCode);
 }
 
@@ -201,30 +225,160 @@ void STDMETHODCALLTYPE CorExitProcess(int exitCode)
 STDAPI _CorValidateImage(PVOID *ImageBase, LPCWSTR FileName)
 {
        IMAGE_DOS_HEADER* DosHeader;
-       IMAGE_NT_HEADERS* NtHeaders;
+       IMAGE_NT_HEADERS32* NtHeaders32;
+       IMAGE_NT_HEADERS64* NtHeaders64;
+       IMAGE_DATA_DIRECTORY* CliHeaderDir;
+       MonoCLIHeader* CliHeader;
+       DWORD SizeOfHeaders;
        DWORD* Address;
-       DWORD dwOldProtect;
+       DWORD OldProtect;
 
        DosHeader = (IMAGE_DOS_HEADER*)*ImageBase;
        if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE)
                return STATUS_INVALID_IMAGE_FORMAT;
 
-       NtHeaders = (IMAGE_NT_HEADERS*)((DWORD_PTR)DosHeader + DosHeader->e_lfanew);
-       if (NtHeaders->Signature != IMAGE_NT_SIGNATURE)
+       NtHeaders32 = (IMAGE_NT_HEADERS32*)((DWORD_PTR)DosHeader + DosHeader->e_lfanew);
+       if (NtHeaders32->Signature != IMAGE_NT_SIGNATURE)
                return STATUS_INVALID_IMAGE_FORMAT;
 
-       if (NtHeaders->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)
+#ifdef _WIN64
+       NtHeaders64 = (IMAGE_NT_HEADERS64*)NtHeaders32;
+       if (NtHeaders64->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
+       {
+               if (NtHeaders64->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
+                       return STATUS_INVALID_IMAGE_FORMAT;
+
+               CliHeaderDir = &NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];
+               if (!CliHeaderDir->VirtualAddress)
+                       return STATUS_INVALID_IMAGE_FORMAT;
+
+               CliHeader = (MonoCLIHeader*)((DWORD_PTR)DosHeader + CliHeaderDir->VirtualAddress);
+               if (CliHeader->ch_flags & CLI_FLAGS_32BITREQUIRED)
+                       return STATUS_INVALID_IMAGE_FORMAT;
+
+               if (CliHeader->ch_flags & CLI_FLAGS_ILONLY)
+               {
+                       /* Avoid calling _CorDllMain because imports are not resolved for IL only images. */
+                       if (NtHeaders64->OptionalHeader.AddressOfEntryPoint != 0)
+                       {
+                               Address = &NtHeaders64->OptionalHeader.AddressOfEntryPoint;
+                               if (!VirtualProtect(Address, sizeof(DWORD), PAGE_READWRITE, &OldProtect))
+                                       return E_UNEXPECTED;
+                               *Address = (DWORD)0;
+                               if (!VirtualProtect(Address, sizeof(DWORD), OldProtect, &OldProtect))
+                                       return E_UNEXPECTED;
+                       }
+               }
+
+               return STATUS_SUCCESS;
+       }
+
+       if (NtHeaders32->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
+               return STATUS_INVALID_IMAGE_FORMAT;
+
+       if (NtHeaders32->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
+               return STATUS_INVALID_IMAGE_FORMAT;
+
+       CliHeaderDir = &NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];
+       if (!CliHeaderDir->VirtualAddress)
+               return STATUS_INVALID_IMAGE_FORMAT;
+
+       CliHeader = (MonoCLIHeader*)((DWORD_PTR)DosHeader + CliHeaderDir->VirtualAddress);
+       if (!(CliHeader->ch_flags & CLI_FLAGS_ILONLY) || (CliHeader->ch_flags & CLI_FLAGS_32BITREQUIRED))
+               return STATUS_INVALID_IMAGE_FORMAT;
+
+       /* Fixup IMAGE_NT_HEADERS32 to IMAGE_NT_HEADERS64. */
+       SizeOfHeaders = NtHeaders32->OptionalHeader.SizeOfHeaders;
+       if (SizeOfHeaders < DosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS64) + (sizeof(IMAGE_SECTION_HEADER) * NtHeaders32->FileHeader.NumberOfSections))
                return STATUS_INVALID_IMAGE_FORMAT;
 
-       Address = &NtHeaders->OptionalHeader.AddressOfEntryPoint;
-       if (!VirtualProtect(Address, sizeof(DWORD), PAGE_READWRITE, &dwOldProtect))
+       if (!VirtualProtect(DosHeader, SizeOfHeaders, PAGE_READWRITE, &OldProtect))
                return E_UNEXPECTED;
-       if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL)
+
+       memmove(NtHeaders64 + 1, IMAGE_FIRST_SECTION(NtHeaders32), sizeof(IMAGE_SECTION_HEADER) * NtHeaders32->FileHeader.NumberOfSections);
+
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1].Size = 0;
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1].VirtualAddress = 0;
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size;
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress;
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size = 0;
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress = 0;
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = 0;
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = 0;
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size = 0;
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress = 0;
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size = 0;
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = 0;
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_GLOBALPTR].Size = 0;
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_GLOBALPTR].VirtualAddress = 0;
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_ARCHITECTURE].Size = 0;
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_ARCHITECTURE].VirtualAddress = 0;
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress;
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size = 0;
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress = 0;
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size;
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = 0;
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = 0;
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = 0;
+       NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = 0;
+
+       NtHeaders64->OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
+       NtHeaders64->OptionalHeader.LoaderFlags = NtHeaders32->OptionalHeader.LoaderFlags;
+       NtHeaders64->OptionalHeader.SizeOfHeapCommit = (ULONGLONG)NtHeaders32->OptionalHeader.SizeOfHeapCommit;
+       NtHeaders64->OptionalHeader.SizeOfHeapReserve = (ULONGLONG)NtHeaders32->OptionalHeader.SizeOfHeapReserve;
+       NtHeaders64->OptionalHeader.SizeOfStackCommit = (ULONGLONG)NtHeaders32->OptionalHeader.SizeOfStackCommit;
+       NtHeaders64->OptionalHeader.SizeOfStackReserve = (ULONGLONG)NtHeaders32->OptionalHeader.SizeOfStackReserve;
+       NtHeaders64->OptionalHeader.DllCharacteristics = NtHeaders32->OptionalHeader.DllCharacteristics;
+       NtHeaders64->OptionalHeader.Subsystem = NtHeaders32->OptionalHeader.Subsystem;
+       NtHeaders64->OptionalHeader.CheckSum = NtHeaders32->OptionalHeader.CheckSum;
+       NtHeaders64->OptionalHeader.SizeOfHeaders = NtHeaders32->OptionalHeader.SizeOfHeaders;
+       NtHeaders64->OptionalHeader.SizeOfImage = NtHeaders32->OptionalHeader.SizeOfImage;
+       NtHeaders64->OptionalHeader.Win32VersionValue = NtHeaders32->OptionalHeader.Win32VersionValue;
+       NtHeaders64->OptionalHeader.MinorSubsystemVersion = NtHeaders32->OptionalHeader.MinorSubsystemVersion;
+       NtHeaders64->OptionalHeader.MajorSubsystemVersion = NtHeaders32->OptionalHeader.MajorSubsystemVersion;
+       NtHeaders64->OptionalHeader.MinorImageVersion = NtHeaders32->OptionalHeader.MinorImageVersion;
+       NtHeaders64->OptionalHeader.MajorImageVersion = NtHeaders32->OptionalHeader.MajorImageVersion;
+       NtHeaders64->OptionalHeader.MinorOperatingSystemVersion = NtHeaders32->OptionalHeader.MinorOperatingSystemVersion;
+       NtHeaders64->OptionalHeader.MajorOperatingSystemVersion = NtHeaders32->OptionalHeader.MajorOperatingSystemVersion;
+       NtHeaders64->OptionalHeader.FileAlignment = NtHeaders32->OptionalHeader.FileAlignment;
+       NtHeaders64->OptionalHeader.SectionAlignment = NtHeaders32->OptionalHeader.SectionAlignment;
+       NtHeaders64->OptionalHeader.ImageBase = (ULONGLONG)NtHeaders32->OptionalHeader.ImageBase;
+       /* BaseOfCode is at the same offset. */
+       NtHeaders64->OptionalHeader.AddressOfEntryPoint = 0;
+       NtHeaders64->OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC;
+       NtHeaders64->FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER64);
+
+       if (!VirtualProtect(DosHeader, SizeOfHeaders, OldProtect, &OldProtect))
+               return E_UNEXPECTED;
+#else
+       if (NtHeaders32->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
+               return STATUS_INVALID_IMAGE_FORMAT;
+
+       if (NtHeaders32->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
+               return STATUS_INVALID_IMAGE_FORMAT;
+
+       CliHeaderDir = &NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];
+       if (!CliHeaderDir->VirtualAddress)
+               return STATUS_INVALID_IMAGE_FORMAT;
+
+       Address = &NtHeaders32->OptionalHeader.AddressOfEntryPoint;
+       if (!VirtualProtect(Address, sizeof(DWORD), PAGE_READWRITE, &OldProtect))
+               return E_UNEXPECTED;
+       if (NtHeaders32->FileHeader.Characteristics & IMAGE_FILE_DLL)
                *Address = (DWORD)((DWORD_PTR)&_CorDllMain - (DWORD_PTR)DosHeader);
        else
                *Address = (DWORD)((DWORD_PTR)&_CorExeMain - (DWORD_PTR)DosHeader);
-       if (!VirtualProtect(Address, sizeof(DWORD), dwOldProtect, &dwOldProtect))
+       if (!VirtualProtect(Address, sizeof(DWORD), OldProtect, &OldProtect))
                return E_UNEXPECTED;
+#endif
 
        return STATUS_SUCCESS;
 }
@@ -235,19 +389,127 @@ STDAPI_(VOID) _CorImageUnloading(PVOID ImageBase)
        /* Nothing to do. */
 }
 
+STDAPI CorBindToRuntimeEx(LPCWSTR pwszVersion, LPCWSTR pwszBuildFlavor, DWORD startupFlags, REFCLSID rclsid, REFIID riid, LPVOID FAR *ppv)
+{
+       if (ppv == NULL)
+               return E_POINTER;
+
+       *ppv = NULL;
+       return E_NOTIMPL;
+}
+
+STDAPI CorBindToRuntime(LPCWSTR pwszVersion, LPCWSTR pwszBuildFlavor, REFCLSID rclsid, REFIID riid, LPVOID FAR *ppv)
+{
+       return CorBindToRuntimeEx (pwszVersion, pwszBuildFlavor, 0, rclsid, riid, ppv);
+}
+
+HMODULE WINAPI MonoLoadImage(LPCWSTR FileName)
+{
+       HANDLE FileHandle;
+       DWORD FileSize;
+       HANDLE MapHandle;
+       IMAGE_DOS_HEADER* DosHeader;
+       IMAGE_NT_HEADERS32* NtHeaders32;
+       IMAGE_NT_HEADERS64* NtHeaders64;
+       HMODULE ModuleHandle;
+
+       FileHandle = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+       if (FileHandle == INVALID_HANDLE_VALUE)
+               return NULL;
+
+       FileSize = GetFileSize(FileHandle, NULL); 
+       if (FileSize == INVALID_FILE_SIZE)
+               goto CloseFile;
+
+       MapHandle = CreateFileMapping(FileHandle, NULL, PAGE_READONLY, 0, 0, NULL);
+       if (MapHandle == NULL)
+               goto CloseFile;
+
+       DosHeader = (IMAGE_DOS_HEADER*)MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0);
+       if (DosHeader == NULL)
+               goto CloseMap;
+
+       if (FileSize < sizeof(IMAGE_DOS_HEADER) || DosHeader->e_magic != IMAGE_DOS_SIGNATURE || FileSize < DosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS32))
+               goto InvalidImageFormat;
+
+       NtHeaders32 = (IMAGE_NT_HEADERS32*)((DWORD_PTR)DosHeader + DosHeader->e_lfanew);
+       if (NtHeaders32->Signature != IMAGE_NT_SIGNATURE)
+               goto InvalidImageFormat;
+
+#ifdef _WIN64
+       NtHeaders64 = (IMAGE_NT_HEADERS64*)NtHeaders32;
+       if (NtHeaders64->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
+       {
+               if (FileSize < DosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS64) ||
+                       NtHeaders64->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR ||
+                       !NtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress)
+                               goto InvalidImageFormat;
+
+               goto ValidImage;
+       }
+#endif
+
+       if (NtHeaders32->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC ||
+               NtHeaders32->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR ||
+               !NtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress)
+       {
+InvalidImageFormat:
+               SetLastError(STATUS_INVALID_IMAGE_FORMAT);
+               goto UnmapView;
+       }
+
+ValidImage:
+       UnmapViewOfFile(DosHeader);
+       CloseHandle(MapHandle);
+
+       ModuleHandle = LoadLibrary(FileName);
+
+       CloseHandle(FileHandle);
+       return ModuleHandle;
+
+UnmapView:
+       UnmapViewOfFile(DosHeader);
+CloseMap:
+       CloseHandle(MapHandle);
+CloseFile:
+       CloseHandle(FileHandle);
+       return NULL;
+}
+
+typedef struct _EXPORT_FIXUP
+{
+       LPCSTR Name;
+       union
+       {
+               PVOID Pointer;
+               DWORD_PTR DWordPtr;
+               BYTE Bytes[sizeof(PVOID)];
+#ifdef _M_IA64
+               PLABEL_DESCRIPTOR* PLabel;
+#endif
+       } ProcAddress;
+} EXPORT_FIXUP;
+
+/* Has to be binary ordered. */
+static const EXPORT_FIXUP ExportFixups[] = {
+       {"CorBindToRuntime", &CorBindToRuntime},
+       {"CorBindToRuntimeEx", &CorBindToRuntimeEx},
+       {"CorExitProcess", &CorExitProcess},
+       {"_CorDllMain", &_CorDllMain},
+       {"_CorExeMain", &_CorExeMain},
+       {"_CorImageUnloading", &_CorImageUnloading},
+       {"_CorValidateImage", &_CorValidateImage},
+       {NULL, NULL}
+};
+
+#define EXPORT_FIXUP_COUNT (sizeof(ExportFixups) / sizeof(EXPORT_FIXUP) - 1)
+
+static HMODULE ExportFixupModuleHandle = NULL;
+static DWORD ExportFixupRvas[EXPORT_FIXUP_COUNT];
+
 /* Fixup exported functions of mscoree.dll to our implementations. */
 STDAPI MonoFixupCorEE(HMODULE ModuleHandle)
 {
-       /* Has to be binary ordered. */
-       const EXPORT_FIXUP ExportFixups[] = {
-               {"CorExitProcess", (DWORD_PTR)&CorExitProcess},
-               {"_CorDllMain", (DWORD_PTR)&_CorDllMain},
-               {"_CorExeMain", (DWORD_PTR)&_CorExeMain},
-               {"_CorImageUnloading", (DWORD_PTR)&_CorImageUnloading},
-               {"_CorValidateImage", (DWORD_PTR)&_CorValidateImage},
-               {NULL, 0}
-       };
-
        IMAGE_DOS_HEADER* DosHeader;
        IMAGE_NT_HEADERS* NtHeaders;
        IMAGE_DATA_DIRECTORY* ExportDataDir;
@@ -256,13 +518,40 @@ STDAPI MonoFixupCorEE(HMODULE ModuleHandle)
        DWORD* Names;
        WORD* NameOrdinals;
        EXPORT_FIXUP* ExportFixup;
+       DWORD* ExportFixupRva;
        DWORD* Address;
-       DWORD dwOldProtect;
-       DWORD_PTR ProcAddress;
+       DWORD OldProtect;
+       DWORD ProcRva;
        DWORD i;
+       int cmp;
+#ifdef _WIN64
+       MEMORY_BASIC_INFORMATION MemoryInfo;
+       PVOID Region;
+       PVOID RegionBase;
+       PVOID MaxRegionBase;
+#ifdef _M_IA64
+       PLABEL_DESCRIPTOR* PLabel;
+
+#define ELEMENT_SIZE sizeof(PLABEL_DESCRIPTOR)
+#define REGION_WRITE_PROTECT PAGE_READWRITE
+#define REGION_PROTECT PAGE_READ
+#else
+       BYTE* Trampoline;
+
+#define ELEMENT_SIZE 13
+#define REGION_WRITE_PROTECT PAGE_EXECUTE_READWRITE
+#define REGION_PROTECT PAGE_EXECUTE_READ
+#endif
+#endif
+
+       if (ExportFixupModuleHandle != NULL)
+               return ModuleHandle == ExportFixupModuleHandle ? S_OK : E_FAIL;
 
        DosHeader = (IMAGE_DOS_HEADER*)ModuleHandle;
-       if (DosHeader == NULL || DosHeader->e_magic != IMAGE_DOS_SIGNATURE)
+       if (DosHeader == NULL)
+               return E_POINTER;
+
+       if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE)
                return E_INVALIDARG;
 
        NtHeaders = (IMAGE_NT_HEADERS*)((DWORD_PTR)DosHeader + DosHeader->e_lfanew);
@@ -276,34 +565,95 @@ STDAPI MonoFixupCorEE(HMODULE ModuleHandle)
                return E_FAIL;
 
        ExportDataDir = &NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
-       if (!ExportDataDir->VirtualAddress || !ExportDataDir->Size)
+       if (!ExportDataDir->VirtualAddress)
                return E_FAIL;
 
+#ifdef _WIN64
+       /* Allocate memory after base address because RVAs are 32-bit unsigned integers. */
+       RegionBase = DosHeader;
+       MaxRegionBase = (PVOID)((DWORD_PTR)RegionBase + (DWORD_PTR)(0x100000000L - (ELEMENT_SIZE * (EXPORT_FIXUP_COUNT - 1))));
+       for (;;)
+       {
+               if (!VirtualQuery(RegionBase, &MemoryInfo, sizeof(MEMORY_BASIC_INFORMATION)))
+                       return E_UNEXPECTED;
+               if (MemoryInfo.State == MEM_FREE && MemoryInfo.RegionSize >= ELEMENT_SIZE * EXPORT_FIXUP_COUNT)
+               {
+                       Region = VirtualAlloc(RegionBase, ELEMENT_SIZE * EXPORT_FIXUP_COUNT, MEM_COMMIT | MEM_RESERVE, REGION_WRITE_PROTECT);
+                       if (Region != NULL)
+                               break;
+               }
+               RegionBase = (PVOID)((DWORD_PTR)MemoryInfo.BaseAddress + (DWORD_PTR)MemoryInfo.RegionSize);
+               if (RegionBase > MaxRegionBase)
+                       return E_OUTOFMEMORY;
+       }
+
+#ifdef _M_IA64
+       PLabel = (PLABEL_DESCRIPTOR*)Region;
+#else
+       Trampoline = (BYTE*)Region;
+#endif
+#endif
+
        ExportDir = (IMAGE_EXPORT_DIRECTORY*)((DWORD_PTR)DosHeader + ExportDataDir->VirtualAddress);
        Functions = (DWORD*)((DWORD_PTR)DosHeader + ExportDir->AddressOfFunctions);
        Names = (DWORD*)((DWORD_PTR)DosHeader + ExportDir->AddressOfNames);
        NameOrdinals = (WORD*)((DWORD_PTR)DosHeader + ExportDir->AddressOfNameOrdinals);
        ExportFixup = (EXPORT_FIXUP*)&ExportFixups;
+       ExportFixupRva = (DWORD*)&ExportFixupRvas;
 
        for (i = 0; i < ExportDir->NumberOfNames; i++)
        {
-               int cmp = strcmp((LPCSTR)((DWORD_PTR)DosHeader + Names[i]), ExportFixup->Name);
+               cmp = strcmp((LPCSTR)((DWORD_PTR)DosHeader + Names[i]), ExportFixup->Name);
                if (cmp > 0)
                        return E_FAIL;
+
                if (cmp == 0)
                {
+#ifdef _WIN64
+#if defined(_M_IA64)
+                       ProcRva = (DWORD)((DWORD_PTR)PLabel - (DWORD_PTR)DosHeader);
+                       *(PLabel)++ = *ExportFixup->ProcAddress.PLabel;
+#elif defined(_M_AMD64)
+                       ProcRva = (DWORD)((DWORD_PTR)Trampoline - (DWORD_PTR)DosHeader);
+                       /* mov r11, ExportFixup->ProcAddress */
+                       *(Trampoline)++ = 0x49;
+                       *(Trampoline)++ = 0xBB;
+                       *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[0];
+                       *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[1];
+                       *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[2];
+                       *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[3];
+                       *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[4];
+                       *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[5];
+                       *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[6];
+                       *(Trampoline)++ = ExportFixup->ProcAddress.Bytes[7];
+                       /* jmp r11 */
+                       *(Trampoline)++ = 0x41;
+                       *(Trampoline)++ = 0xFF;
+                       *(Trampoline)++ = 0xE3;
+#else
+#error Unsupported architecture.
+#endif
+#else
+                       ProcRva = (DWORD)(ExportFixup->ProcAddress.DWordPtr - (DWORD_PTR)DosHeader);
+#endif
                        Address = &Functions[NameOrdinals[i]];
-                       ProcAddress = (DWORD_PTR)DosHeader + *Address;
-                       if (ProcAddress != ExportFixup->ProcAddress) {
-                               if (!VirtualProtect(Address, sizeof(DWORD), PAGE_READWRITE, &dwOldProtect))
-                                       return E_UNEXPECTED;
-                               *Address = (DWORD)(ExportFixup->ProcAddress - (DWORD_PTR)DosHeader);
-                               if (!VirtualProtect(Address, sizeof(DWORD), dwOldProtect, &dwOldProtect))
-                                       return E_UNEXPECTED;
-                       }
+                       if (!VirtualProtect(Address, sizeof(DWORD), PAGE_READWRITE, &OldProtect))
+                               return E_UNEXPECTED;
+                       *ExportFixupRva = *Address;
+                       *Address = ProcRva;
+                       if (!VirtualProtect(Address, sizeof(DWORD), OldProtect, &OldProtect))
+                               return E_UNEXPECTED;
                        ExportFixup++;
-                       if (ExportFixup->Name == NULL)
+                       if (ExportFixup->Name == NULL) {
+#ifdef _WIN64
+                               if (!VirtualProtect(Region, ELEMENT_SIZE * EXPORT_FIXUP_COUNT, REGION_PROTECT, &OldProtect))
+                                       return E_UNEXPECTED;
+#endif
+
+                               ExportFixupModuleHandle = ModuleHandle;
                                return S_OK;
+                       }
+                       ExportFixupRva++;
                }
        }
        return E_FAIL;
@@ -315,11 +665,14 @@ STDAPI MonoFixupExe(HMODULE ModuleHandle)
        IMAGE_DOS_HEADER* DosHeader;
        IMAGE_NT_HEADERS* NtHeaders;
        DWORD_PTR* Address;
-       DWORD dwOldProtect;
+       DWORD OldProtect;
        DWORD_PTR BaseDiff;
 
        DosHeader = (IMAGE_DOS_HEADER*)ModuleHandle;
-       if (DosHeader == NULL || DosHeader->e_magic != IMAGE_DOS_SIGNATURE)
+       if (DosHeader == NULL)
+               return E_POINTER;
+
+       if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE)
                return E_INVALIDARG;
 
        NtHeaders = (IMAGE_NT_HEADERS*)((DWORD_PTR)DosHeader + DosHeader->e_lfanew);
@@ -332,6 +685,20 @@ STDAPI MonoFixupExe(HMODULE ModuleHandle)
        if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL)
                return S_OK;
 
+       if (NtHeaders->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
+       {
+               IMAGE_DATA_DIRECTORY* CliHeaderDir;
+               MonoCLIHeader* CliHeader;
+
+               CliHeaderDir = &NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];
+               if (CliHeaderDir->VirtualAddress)
+               {
+                       CliHeader = (MonoCLIHeader*)((DWORD_PTR)DosHeader + CliHeaderDir->VirtualAddress);
+                       if (CliHeader->ch_flags & CLI_FLAGS_ILONLY)
+                               return S_OK;
+               }
+       }
+
        BaseDiff = (DWORD_PTR)DosHeader - NtHeaders->OptionalHeader.ImageBase;
        if (BaseDiff != 0)
        {
@@ -339,10 +706,10 @@ STDAPI MonoFixupExe(HMODULE ModuleHandle)
                        return E_FAIL;
 
                Address = &NtHeaders->OptionalHeader.ImageBase;
-               if (!VirtualProtect(Address, sizeof(DWORD_PTR), PAGE_READWRITE, &dwOldProtect))
+               if (!VirtualProtect(Address, sizeof(DWORD_PTR), PAGE_READWRITE, &OldProtect))
                        return E_UNEXPECTED;
                *Address = (DWORD_PTR)DosHeader;
-               if (!VirtualProtect(Address, sizeof(DWORD_PTR), dwOldProtect, &dwOldProtect))
+               if (!VirtualProtect(Address, sizeof(DWORD_PTR), OldProtect, &OldProtect))
                        return E_UNEXPECTED;
 
                if (NtHeaders->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_BASERELOC)
@@ -356,7 +723,7 @@ STDAPI MonoFixupExe(HMODULE ModuleHandle)
                        DWORD_PTR UNALIGNED *RelocFixup;
 
                        BaseRelocDir = &NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
-                       if (BaseRelocDir->VirtualAddress && BaseRelocDir->Size)
+                       if (BaseRelocDir->VirtualAddress)
                        {
                                BaseReloc = (IMAGE_BASE_RELOCATION*)((DWORD_PTR)DosHeader + BaseRelocDir->VirtualAddress);
                                BaseRelocSize = BaseRelocDir->Size;
@@ -369,8 +736,8 @@ STDAPI MonoFixupExe(HMODULE ModuleHandle)
                                                return E_FAIL;
 
                                        BaseRelocSize -= RelocBlockSize;
-                                       RelocBlock = (USHORT*)((DWORD_PTR)BaseReloc + IMAGE_SIZEOF_BASE_RELOCATION);
-                                       RelocBlockSize -= IMAGE_SIZEOF_BASE_RELOCATION;
+                                       RelocBlock = (USHORT*)((DWORD_PTR)BaseReloc + sizeof(IMAGE_BASE_RELOCATION));
+                                       RelocBlockSize -= sizeof(IMAGE_BASE_RELOCATION);
                                        RelocBlockSize /= sizeof(USHORT);
 
                                        while (RelocBlockSize-- != 0)
@@ -388,10 +755,10 @@ STDAPI MonoFixupExe(HMODULE ModuleHandle)
 #else
                                                        case IMAGE_REL_BASED_HIGHLOW:
 #endif
-                                                               if (!VirtualProtect(RelocFixup, sizeof(DWORD_PTR), PAGE_EXECUTE_READWRITE, &dwOldProtect))
+                                                               if (!VirtualProtect(RelocFixup, sizeof(DWORD_PTR), PAGE_EXECUTE_READWRITE, &OldProtect))
                                                                        return E_UNEXPECTED;
                                                                *RelocFixup += BaseDiff;
-                                                               if (!VirtualProtect(RelocFixup, sizeof(DWORD_PTR), dwOldProtect, &dwOldProtect))
+                                                               if (!VirtualProtect(RelocFixup, sizeof(DWORD_PTR), OldProtect, &OldProtect))
                                                                        return E_UNEXPECTED;
                                                                break;
 
@@ -438,10 +805,10 @@ STDAPI MonoFixupExe(HMODULE ModuleHandle)
                                        if (ProcAddress == 0)
                                                return E_FAIL;
                                        Address = (DWORD_PTR*)((DWORD_PTR)ImportThunkData - ImportDesc->OriginalFirstThunk + ImportDesc->FirstThunk);
-                                       if (!VirtualProtect(Address, sizeof(DWORD_PTR), PAGE_READWRITE, &dwOldProtect))
+                                       if (!VirtualProtect(Address, sizeof(DWORD_PTR), PAGE_READWRITE, &OldProtect))
                                                return E_UNEXPECTED;
                                        *Address = ProcAddress;
-                                       if (!VirtualProtect(Address, sizeof(DWORD_PTR), dwOldProtect, &dwOldProtect))
+                                       if (!VirtualProtect(Address, sizeof(DWORD_PTR), OldProtect, &OldProtect))
                                                return E_UNEXPECTED;
                                        ImportThunkData++;
                                }
@@ -454,9 +821,71 @@ STDAPI MonoFixupExe(HMODULE ModuleHandle)
        return S_OK;
 }
 
+static void
+mono_set_act_ctx (const char* file_name)
+{
+       typedef HANDLE (WINAPI* CREATEACTCTXW_PROC) (PCACTCTXW pActCtx);
+       typedef BOOL (WINAPI* ACTIVATEACTCTX_PROC) (HANDLE hActCtx, ULONG_PTR* lpCookie);
+
+       HMODULE kernel32_handle;
+       CREATEACTCTXW_PROC CreateActCtx_proc;
+       ACTIVATEACTCTX_PROC ActivateActCtx_proc;
+       gchar* full_path;
+       gunichar2* full_path_utf16;
+       gchar* dir_name;
+       gunichar2* dir_name_utf16;
+       gchar* base_name;
+       gunichar2* base_name_utf16;
+       ACTCTX act_ctx;
+       HANDLE handle;
+       ULONG_PTR cookie;
+
+       kernel32_handle = GetModuleHandle (L"kernel32.dll");
+       if (!kernel32_handle)
+               return;
+       CreateActCtx_proc = (CREATEACTCTXW_PROC) GetProcAddress (kernel32_handle, "CreateActCtxW");
+       if (!CreateActCtx_proc)
+               return;
+       ActivateActCtx_proc = (ACTIVATEACTCTX_PROC) GetProcAddress (kernel32_handle, "ActivateActCtx");
+       if (!ActivateActCtx_proc)
+               return;
+
+       full_path = mono_path_canonicalize (file_name);
+       full_path_utf16 = g_utf8_to_utf16 (full_path, -1, NULL, NULL, NULL);
+       dir_name = g_path_get_dirname (full_path);
+       dir_name_utf16 = g_utf8_to_utf16 (dir_name, -1, NULL, NULL, NULL);
+       base_name = g_path_get_basename (full_path);
+       base_name_utf16 = g_utf8_to_utf16 (base_name, -1, NULL, NULL, NULL);
+       g_free (base_name);
+       g_free (dir_name);
+       g_free (full_path);
+
+       memset (&act_ctx, 0, sizeof (ACTCTX));
+       act_ctx.cbSize = sizeof (ACTCTX);
+       act_ctx.dwFlags = ACTCTX_FLAG_SET_PROCESS_DEFAULT | ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID | ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_APPLICATION_NAME_VALID;
+       act_ctx.lpSource = full_path_utf16;
+       act_ctx.lpAssemblyDirectory = dir_name_utf16;
+       act_ctx.lpResourceName = MAKEINTRESOURCE (CREATEPROCESS_MANIFEST_RESOURCE_ID);
+       act_ctx.lpApplicationName = base_name_utf16;
+
+       handle = CreateActCtx_proc (&act_ctx);
+       if (handle == INVALID_HANDLE_VALUE && GetLastError () == ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET) {
+               act_ctx.dwFlags &= ~ACTCTX_FLAG_SET_PROCESS_DEFAULT;
+               handle = CreateActCtx_proc (&act_ctx);
+       }
+
+       g_free (base_name_utf16);
+       g_free (dir_name_utf16);
+       g_free (full_path_utf16);
+
+       if (handle != INVALID_HANDLE_VALUE)
+               ActivateActCtx_proc (handle, &cookie);
+}
+
 void
-mono_load_coree ()
+mono_load_coree (const char* exe_file_name)
 {
+       HMODULE module_handle;
        gunichar2* file_name;
        UINT required_size;
        UINT size;
@@ -464,6 +893,9 @@ mono_load_coree ()
        if (coree_module_handle)
                return;
 
+       if (!init_from_coree && exe_file_name)
+               mono_set_act_ctx (exe_file_name);
+
        /* ntdll.dll loads mscoree.dll from the system32 directory. */
        required_size = GetSystemDirectory (NULL, 0);
        file_name = g_new (gunichar2, required_size + 12);
@@ -473,19 +905,21 @@ mono_load_coree ()
                file_name [size++] = L'\\';
        memcpy (&file_name [size], L"mscoree.dll", 12 * sizeof (gunichar2));
 
-       coree_module_handle = LoadLibrary (file_name);
+       module_handle = LoadLibrary (file_name);
        g_free (file_name);
 
-       if (coree_module_handle && !SUCCEEDED (MonoFixupCorEE (coree_module_handle))) {
-               FreeLibrary (coree_module_handle);
-               coree_module_handle = NULL;
+       if (module_handle && !SUCCEEDED (MonoFixupCorEE (module_handle))) {
+               FreeLibrary (module_handle);
+               module_handle = NULL;
        }
+
+       coree_module_handle = module_handle;
 }
 
 void
 mono_fixup_exe_image (MonoImage* image)
 {
-       if (image && image->is_module_handle && (HMODULE) image->raw_data != GetModuleHandle (NULL))
+       if (!init_from_coree && image && image->is_module_handle)
                MonoFixupExe ((HMODULE) image->raw_data);
 }