/* * %CopyrightBegin% * * Copyright Ericsson AB 1997-2011. 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> #ifdef HAVE_CONFIG_H # include "config.h" #endif #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); }