diff options
Diffstat (limited to 'erts/etc/win32/win_erlexec.c')
-rw-r--r-- | erts/etc/win32/win_erlexec.c | 405 |
1 files changed, 405 insertions, 0 deletions
diff --git a/erts/etc/win32/win_erlexec.c b/erts/etc/win32/win_erlexec.c new file mode 100644 index 0000000000..0eed8e28b9 --- /dev/null +++ b/erts/etc/win32/win_erlexec.c @@ -0,0 +1,405 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1997-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Extra support for running the emulator on Windows. + * Most of this only used when beam is run as a separate process. + */ + +#pragma comment(linker,"/manifestdependency:\"type='win32' "\ + "name='Microsoft.Windows.Common-Controls' "\ + "version='6.0.0.0' processorArchitecture='*' "\ + "publicKeyToken='6595b64144ccf1df' language='*'\"") + +#include <windows.h> +#include <winuser.h> +#include <wincon.h> +#include <process.h> +#include "sys.h" +#include "erl_driver.h" + +extern int nohup; +extern int keep_window; +void error(char* format, ...); + +/* + * Local functions. + */ +#define LOAD_BEAM_DYNAMICALLY 1 +static int start(char* emu, char** argv); +static void start_winsock(void); +static char* last_error(void); +static char* last_wsa_error(void); +static char* win32_errorstr(int error); +static int has_console(void); +static char** fnuttify_argv(char **argv); +static void free_fnuttified(char **v); +static int windowed = 0; + +#ifdef LOAD_BEAM_DYNAMICALLY +typedef int SysGetKeyFunction(int); +typedef void ErlStartFunction(int, char **); +typedef void SysPrimitiveInitFunction(HMODULE); +static SysGetKeyFunction *sys_get_key_p; +static ErlStartFunction *erl_start_p; +static SysPrimitiveInitFunction *sys_primitive_init_p; + +static HMODULE load_win_beam_dll(char *name) +{ + HMODULE beam_module; + beam_module=LoadLibrary(name); + if (beam_module == INVALID_HANDLE_VALUE || beam_module == NULL) { + error("Unable to load emulator DLL\n(%s)",name); + return NULL; + } + sys_get_key_p = (SysGetKeyFunction *) + GetProcAddress(beam_module, "sys_get_key"); + erl_start_p = (ErlStartFunction *) + GetProcAddress(beam_module, "erl_start"); + sys_primitive_init_p = (SysPrimitiveInitFunction *) + GetProcAddress(beam_module, "sys_primitive_init"); + return beam_module; +} +#endif + +#define DLL_ENV "ERL_EMULATOR_DLL" + +static void +set_env(char *key, char *value) +{ + if (!SetEnvironmentVariable((LPCTSTR) key, (LPCTSTR) value)) + error("SetEnvironmentVariable(\"%s\", \"%s\") failed!", key, value); +} + +static char * +get_env(char *key) +{ + DWORD size = 32; + char *value = NULL; + while (1) { + DWORD nsz; + if (value) + free(value); + value = malloc(size); + if (!value) + error("GetEnvironmentVariable(\"%s\") failed", key); + SetLastError(0); + nsz = GetEnvironmentVariable((LPCTSTR) key, (LPTSTR) value, size); + if (nsz == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND) { + free(value); + return NULL; + } + if (nsz <= size) + return value; + size = nsz; + } +} + +free_env_val(char *value) +{ + if (value) + free(value); +} + + +int +start_win_emulator(char* emu, char *start_prog, char** argv, int start_detached) +{ + int result; + + windowed = 1; + if (start_detached) { + char *buff; + close(0); + close(1); + close(2); + + set_env("ERL_CONSOLE_MODE", "detached"); + set_env(DLL_ENV, emu); + + argv[0] = start_prog; + argv = fnuttify_argv(argv); + result = spawnv(_P_DETACH, start_prog, argv); + free_fnuttified(argv); + } else { + int argc = 0; +#ifdef LOAD_BEAM_DYNAMICALLY + HMODULE beam_module = load_win_beam_dll(emu); +#endif + set_env("ERL_CONSOLE_MODE", "window"); + while (argv[argc] != NULL) { + ++argc; + } +#ifdef ARGS_HARDDEBUG + { + char sbuf[2048] = ""; + int i; + for (i = 0; i < argc; ++i) { + strcat(sbuf,"|"); + strcat(sbuf, argv[i]); + strcat(sbuf,"| "); + } + MessageBox(NULL, sbuf, "Werl", MB_OK|MB_ICONERROR); + } +#endif +#ifdef LOAD_BEAM_DYNAMICALLY + (*sys_primitive_init_p)(beam_module); + (*erl_start_p)(argc,argv); +#else + erl_start(argc, argv); +#endif + result = 0; + } + if (result == -1) { + error("Failed to execute %s: %s", emu, win32_errorstr(_doserrno)); + } + return 0; +} + +void __cdecl +do_keep_window(void) +{ + printf("\nPress any key to close window.\n"); +#ifdef LOAD_BEAM_DYNAMICALLY + (*sys_get_key_p)(0); +#else + sys_get_key(0); +#endif +} + +int +start_emulator(char* emu, char *start_prog, char** argv, int start_detached) +{ + int result; + static char console_mode[] = "tty:ccc"; + char* fd_type; + char* title; + +#ifdef HARDDEBUG + fprintf(stderr,"emu = %s, start_prog = %s\n",emu, start_prog); +#endif + + fd_type = strchr(console_mode, ':'); + fd_type++; + _flushall(); + + /* + * If no console, we will spawn the emulator detached. + */ + + if (start_detached) { + char *buff; + close(0); + close(1); + close(2); + set_env("ERL_CONSOLE_MODE", "detached"); + set_env(DLL_ENV, emu); + + argv[0] = start_prog; + argv = fnuttify_argv(argv); +#ifdef ARGS_HARDDEBUG + { + char buffer[2048]; + int i; + sprintf(buffer,"Start detached [%s]\n",start_prog); + for(i=0;argv[i] != NULL;++i) { + strcat(buffer,"|"); + strcat(buffer,argv[i]); + strcat(buffer,"|\n"); + } + MessageBox(NULL, buffer,"Start detached",MB_OK); + } +#endif + result = spawnv(_P_DETACH, start_prog, argv); + free_fnuttified(argv); + if (result == -1) { +#ifdef ARGS_HARDDEBUG + MessageBox(NULL, "_spawnv failed","Start detached",MB_OK); +#endif + return 1; + } + SetPriorityClass((HANDLE) result, GetPriorityClass(GetCurrentProcess())); + } else { + int argc = 0; +#ifdef LOAD_BEAM_DYNAMICALLY + HMODULE beam_module = load_win_beam_dll(emu); +#endif + + /* + * Start the emulator. + */ + + title = get_env("ERL_WINDOW_TITLE"); + if (title) { + SetConsoleTitle(title); + } + free_env_val(title); + + set_env("ERL_CONSOLE_MODE", console_mode); + while (argv[argc] != NULL) { + ++argc; + } + if (keep_window) { + atexit(do_keep_window); + } +#ifdef ARGS_HARDDEBUG + { + char sbuf[2048] = ""; + int i; + for (i = 0; i < argc; ++i) { + strcat(sbuf,"|"); + strcat(sbuf, argv[i]); + strcat(sbuf,"|\n"); + } + MessageBox(NULL, sbuf, "erl", MB_OK); + } +#endif +#ifdef LOAD_BEAM_DYNAMICALLY + (*sys_primitive_init_p)(beam_module); + (*erl_start_p)(argc,argv); +#else + erl_start(argc, argv); +#endif + } + return 0; +} + +void +error(char* format, ...) +{ + char sbuf[2048]; + va_list ap; + + va_start(ap, format); + vsprintf(sbuf, format, ap); + va_end(ap); + + if (!windowed && has_console()) { + fprintf(stderr, "%s\n", sbuf); + } else { + MessageBox(NULL, sbuf, "Werl", MB_OK|MB_ICONERROR); + } + exit(1); +} + +static char* +last_error(void) +{ + return win32_errorstr(GetLastError()); +} + +/* + * Returns a human-readable description of the last error. + * The returned pointer will be valid only as long as last-error() + * isn't called again. + */ + +static char* +win32_errorstr(int error) +{ + static LPTSTR lpBufPtr = NULL; + + if (lpBufPtr) + LocalFree(lpBufPtr); + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + error, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpBufPtr, + 0, + NULL); + SetLastError(error); + return lpBufPtr; +} + +static int +has_console(void) +{ + HANDLE handle = CreateFile("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + if (handle != INVALID_HANDLE_VALUE) { + CloseHandle(handle); + return 1; + } else { + return 0; + } +} + +static char** fnuttify_argv(char **argv) +{ + char **v; + char *p; + char *q; + int c; + int i; + int n; + int m; + + for (c = 0; argv[c]; ++c) + ; + + v = malloc(sizeof(char *) * (c+1)); + v[c] = NULL; + for (i = 0; i < c; ++i) { + p = argv[i]; + n = m = 0; + while (*p) { + if (*p == ' ') { + m = 2; + } else if (*p == '"') { + m = 2; + ++n; + } + ++p; + } + v[i] = malloc((p - argv[i]) + 1 + n + m); + p = argv[i]; + q = v[i]; + if (n || m) { + if (m) { + *q++ = '"'; + } + while (*p) { + if (*p == '"') { + *q++ = '\\'; + } + *q++ = *p++; + } + if (m) { + *q++ = '"'; + } + *q = '\0'; + } else { + strcpy(q,p); + } + } + return v; +} + +static void free_fnuttified(char **v) +{ + char **t = v; + + while(*t) { + free(*t); + ++t; + } + free(v); +} |