1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
|
/**************************************************************************/
/* */
/* OCaml */
/* */
/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
/* */
/* Copyright 1998 Institut National de Recherche en Informatique et */
/* en Automatique. */
/* */
/* All rights reserved. This file is distributed under the terms of */
/* the GNU Lesser General Public License version 2.1, with the */
/* special exception on linking described in the file LICENSE. */
/* */
/**************************************************************************/
#define CAML_INTERNALS
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "caml/mlvalues.h"
#include "caml/exec.h"
#ifndef __MINGW32__
#pragma comment(linker , "/subsystem:console")
#pragma comment(lib , "kernel32")
#ifdef _UCRT
#pragma comment(lib , "ucrt.lib")
#pragma comment(lib , "vcruntime.lib")
#endif
#endif
Caml_inline unsigned long read_size(const char * const ptr)
{
const unsigned char * const p = (const unsigned char * const) ptr;
return ((unsigned long) p[0] << 24) | ((unsigned long) p[1] << 16) |
((unsigned long) p[2] << 8) | p[3];
}
Caml_inline char * read_runtime_path(HANDLE h)
{
char buffer[TRAILER_SIZE];
static char runtime_path[MAX_PATH];
DWORD nread;
int num_sections, path_size;
long ofs;
if (SetFilePointer(h, -TRAILER_SIZE, NULL, FILE_END) == -1) return NULL;
if (! ReadFile(h, buffer, TRAILER_SIZE, &nread, NULL)) return NULL;
if (nread != TRAILER_SIZE) return NULL;
num_sections = read_size(buffer);
ofs = TRAILER_SIZE + num_sections * 8;
if (SetFilePointer(h, - ofs, NULL, FILE_END) == -1) return NULL;
path_size = 0;
for (int i = 0; i < num_sections; i++) {
if (! ReadFile(h, buffer, 8, &nread, NULL) || nread != 8) return NULL;
if (buffer[0] == 'R' && buffer[1] == 'N' &&
buffer[2] == 'T' && buffer[3] == 'M') {
path_size = read_size(buffer + 4);
ofs += path_size;
} else if (path_size > 0)
ofs += read_size(buffer + 4);
}
if (path_size == 0) return NULL;
if (path_size >= MAX_PATH) return NULL;
if (SetFilePointer(h, -ofs, NULL, FILE_END) == -1) return NULL;
if (! ReadFile(h, runtime_path, path_size, &nread, NULL)) return NULL;
if (nread != path_size) return NULL;
return runtime_path;
}
static BOOL WINAPI ctrl_handler(DWORD event)
{
if (event == CTRL_C_EVENT || event == CTRL_BREAK_EVENT)
return TRUE; /* pretend we've handled them */
else
return FALSE;
}
#if WINDOWS_UNICODE
#define CP CP_UTF8
#else
#define CP CP_ACP
#endif
static void write_console(HANDLE hOut, WCHAR *wstr)
{
DWORD consoleMode, numwritten, len;
static char str[MAX_PATH];
if (GetConsoleMode(hOut, &consoleMode) != 0) {
/* The output stream is a Console */
WriteConsole(hOut, wstr, wcslen(wstr), &numwritten, NULL);
} else { /* The output stream is redirected */
len =
WideCharToMultiByte(CP, 0, wstr, wcslen(wstr), str, sizeof(str),
NULL, NULL);
WriteFile(hOut, str, len, &numwritten, NULL);
}
}
CAMLnoret Caml_inline void run_runtime(wchar_t * runtime,
wchar_t * const cmdline)
{
wchar_t path[MAX_PATH];
STARTUPINFO stinfo;
PROCESS_INFORMATION procinfo;
DWORD retcode;
if (SearchPath(NULL, runtime, L".exe", sizeof(path)/sizeof(wchar_t),
path, NULL) == 0) {
HANDLE errh;
errh = GetStdHandle(STD_ERROR_HANDLE);
write_console(errh, L"Cannot exec ");
write_console(errh, runtime);
write_console(errh, L"\r\n");
ExitProcess(2);
}
/* Need to ignore ctrl-C and ctrl-break, otherwise we'll die and take
the underlying OCaml program with us! */
SetConsoleCtrlHandler(ctrl_handler, TRUE);
stinfo.cb = sizeof(stinfo);
stinfo.lpReserved = NULL;
stinfo.lpDesktop = NULL;
stinfo.lpTitle = NULL;
stinfo.dwFlags = 0;
stinfo.cbReserved2 = 0;
stinfo.lpReserved2 = NULL;
if (!CreateProcess(path, cmdline, NULL, NULL, TRUE, 0, NULL, NULL,
&stinfo, &procinfo)) {
HANDLE errh;
errh = GetStdHandle(STD_ERROR_HANDLE);
write_console(errh, L"Cannot exec ");
write_console(errh, runtime);
write_console(errh, L"\r\n");
ExitProcess(2);
}
CloseHandle(procinfo.hThread);
WaitForSingleObject(procinfo.hProcess , INFINITE);
GetExitCodeProcess(procinfo.hProcess , &retcode);
CloseHandle(procinfo.hProcess);
ExitProcess(retcode);
}
int wmain(void)
{
wchar_t truename[MAX_PATH];
wchar_t * cmdline = GetCommandLine();
char * runtime_path;
wchar_t wruntime_path[MAX_PATH];
HANDLE h;
GetModuleFileName(NULL, truename, sizeof(truename)/sizeof(wchar_t));
h = CreateFile(truename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
if (h == INVALID_HANDLE_VALUE ||
(runtime_path = read_runtime_path(h)) == NULL) {
HANDLE errh;
errh = GetStdHandle(STD_ERROR_HANDLE);
write_console(errh, truename);
write_console(errh, L" not found or is not a bytecode executable file\r\n");
ExitProcess(2);
}
CloseHandle(h);
MultiByteToWideChar(CP, 0, runtime_path, -1, wruntime_path,
sizeof(wruntime_path)/sizeof(wchar_t));
run_runtime(wruntime_path , cmdline);
}
|