1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/os/windows/launcher/java_md.c Thu Dec 02 05:45:54 2010 -0800 1.3 @@ -0,0 +1,1465 @@ 1.4 +/* 1.5 + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.23 + * or visit www.oracle.com if you need additional information or have any 1.24 + * questions. 1.25 + * 1.26 + */ 1.27 + 1.28 +#include <windows.h> 1.29 +#include <io.h> 1.30 +#include <process.h> 1.31 +#include <stdlib.h> 1.32 +#include <stdio.h> 1.33 +#include <string.h> 1.34 +#include <sys/types.h> 1.35 +#include <sys/stat.h> 1.36 + 1.37 +#include <jni.h> 1.38 +#include "java.h" 1.39 +#ifndef GAMMA 1.40 +#include "version_comp.h" 1.41 +#endif 1.42 + 1.43 +#define JVM_DLL "jvm.dll" 1.44 +#define JAVA_DLL "java.dll" 1.45 +#define CRT_DLL "msvcr71.dll" 1.46 + 1.47 +/* 1.48 + * Prototypes. 1.49 + */ 1.50 +static jboolean GetPublicJREHome(char *path, jint pathsize); 1.51 +static jboolean GetJVMPath(const char *jrepath, const char *jvmtype, 1.52 + char *jvmpath, jint jvmpathsize); 1.53 +static jboolean GetJREPath(char *path, jint pathsize); 1.54 +static void EnsureJreInstallation(const char *jrepath); 1.55 + 1.56 +/* We supports warmup for UI stack that is performed in parallel 1.57 + * to VM initialization. 1.58 + * This helps to improve startup of UI application as warmup phase 1.59 + * might be long due to initialization of OS or hardware resources. 1.60 + * It is not CPU bound and therefore it does not interfere with VM init. 1.61 + * Obviously such warmup only has sense for UI apps and therefore it needs 1.62 + * to be explicitly requested by passing -Dsun.awt.warmup=true property 1.63 + * (this is always the case for plugin/javaws). 1.64 + * 1.65 + * Implementation launches new thread after VM starts and use it to perform 1.66 + * warmup code (platform dependent). 1.67 + * This thread is later reused as AWT toolkit thread as graphics toolkit 1.68 + * often assume that they are used from the same thread they were launched on. 1.69 + * 1.70 + * At the moment we only support warmup for D3D. It only possible on windows 1.71 + * and only if other flags do not prohibit this (e.g. OpenGL support requested). 1.72 + */ 1.73 +#undef ENABLE_AWT_PRELOAD 1.74 +#ifndef JAVA_ARGS /* turn off AWT preloading for javac, jar, etc */ 1.75 + #ifdef _X86_ /* for now disable AWT preloading for 64bit */ 1.76 + #define ENABLE_AWT_PRELOAD 1.77 + #endif 1.78 +#endif 1.79 + 1.80 +#ifdef ENABLE_AWT_PRELOAD 1.81 +/* "AWT was preloaded" flag; 1.82 + * Turned on by AWTPreload(). 1.83 + */ 1.84 +int awtPreloaded = 0; 1.85 + 1.86 +/* Calls a function with the name specified. 1.87 + * The function must be int(*fn)(void). 1.88 + */ 1.89 +int AWTPreload(const char *funcName); 1.90 +/* Stops AWT preloading. */ 1.91 +void AWTPreloadStop(); 1.92 + 1.93 +/* D3D preloading */ 1.94 +/* -1: not initialized; 0: OFF, 1: ON */ 1.95 +int awtPreloadD3D = -1; 1.96 +/* Command line parameter to swith D3D preloading on. */ 1.97 +#define PARAM_PRELOAD_D3D "-Dsun.awt.warmup" 1.98 +/* D3D/OpenGL management parameters (may disable D3D preloading) */ 1.99 +#define PARAM_NODDRAW "-Dsun.java2d.noddraw" 1.100 +#define PARAM_D3D "-Dsun.java2d.d3d" 1.101 +#define PARAM_OPENGL "-Dsun.java2d.opengl" 1.102 +/* funtion in awt.dll (src/windows/native/sun/java2d/d3d/D3DPipelineManager.cpp) */ 1.103 +#define D3D_PRELOAD_FUNC "preloadD3D" 1.104 + 1.105 + 1.106 +/* Extracts value of a parameter with the specified name 1.107 + * from command line argument (returns pointer in the argument). 1.108 + * Returns NULL if the argument does not contains the parameter. 1.109 + * e.g.: 1.110 + * GetParamValue("theParam", "theParam=value") returns pointer to "value". 1.111 + */ 1.112 +const char * GetParamValue(const char *paramName, const char *arg) { 1.113 + int nameLen = strlen(paramName); 1.114 + if (strncmp(paramName, arg, nameLen) == 0) { 1.115 + // arg[nameLen] is valid (may contain final NULL) 1.116 + if (arg[nameLen] == '=') { 1.117 + return arg + nameLen + 1; 1.118 + } 1.119 + } 1.120 + return NULL; 1.121 +} 1.122 + 1.123 +/* Checks if commandline argument contains property specified 1.124 + * and analyze it as boolean property (true/false). 1.125 + * Returns -1 if the argument does not contain the parameter; 1.126 + * Returns 1 if the argument contains the parameter and its value is "true"; 1.127 + * Returns 0 if the argument contains the parameter and its value is "false". 1.128 + */ 1.129 +int GetBoolParamValue(const char *paramName, const char *arg) { 1.130 + const char * paramValue = GetParamValue(paramName, arg); 1.131 + if (paramValue != NULL) { 1.132 + if (stricmp(paramValue, "true") == 0) { 1.133 + return 1; 1.134 + } 1.135 + if (stricmp(paramValue, "false") == 0) { 1.136 + return 0; 1.137 + } 1.138 + } 1.139 + return -1; 1.140 +} 1.141 +#endif /* ENABLE_AWT_PRELOAD */ 1.142 + 1.143 + 1.144 +const char * 1.145 +GetArch() 1.146 +{ 1.147 + 1.148 +#ifdef _M_AMD64 1.149 + return "amd64"; 1.150 +#elif defined(_M_IA64) 1.151 + return "ia64"; 1.152 +#else 1.153 + return "i386"; 1.154 +#endif 1.155 +} 1.156 + 1.157 +/* 1.158 + * 1.159 + */ 1.160 +void 1.161 +CreateExecutionEnvironment(int *_argc, 1.162 + char ***_argv, 1.163 + char jrepath[], 1.164 + jint so_jrepath, 1.165 + char jvmpath[], 1.166 + jint so_jvmpath, 1.167 + char **original_argv) { 1.168 +#ifndef GAMMA 1.169 + char * jvmtype; 1.170 + 1.171 + /* Find out where the JRE is that we will be using. */ 1.172 + if (!GetJREPath(jrepath, so_jrepath)) { 1.173 + ReportErrorMessage("Error: could not find Java SE Runtime Environment.", 1.174 + JNI_TRUE); 1.175 + exit(2); 1.176 + } 1.177 + 1.178 + /* Do this before we read jvm.cfg */ 1.179 + EnsureJreInstallation(jrepath); 1.180 + 1.181 + /* Find the specified JVM type */ 1.182 + if (ReadKnownVMs(jrepath, (char*)GetArch(), JNI_FALSE) < 1) { 1.183 + ReportErrorMessage("Error: no known VMs. (check for corrupt jvm.cfg file)", 1.184 + JNI_TRUE); 1.185 + exit(1); 1.186 + } 1.187 + jvmtype = CheckJvmType(_argc, _argv, JNI_FALSE); 1.188 + 1.189 + jvmpath[0] = '\0'; 1.190 + if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath)) { 1.191 + char * message=NULL; 1.192 + const char * format = "Error: no `%s' JVM at `%s'."; 1.193 + message = (char *)JLI_MemAlloc((strlen(format)+strlen(jvmtype)+ 1.194 + strlen(jvmpath)) * sizeof(char)); 1.195 + sprintf(message,format, jvmtype, jvmpath); 1.196 + ReportErrorMessage(message, JNI_TRUE); 1.197 + exit(4); 1.198 + } 1.199 + /* If we got here, jvmpath has been correctly initialized. */ 1.200 + 1.201 +#else /* ifndef GAMMA */ 1.202 + 1.203 + /* 1.204 + * gamma launcher is simpler in that it doesn't handle VM flavors, data 1.205 + * model, etc. Assuming everything is set-up correctly 1.206 + * all we need to do here is to return correct path names. See also 1.207 + * GetJVMPath() and GetApplicationHome(). 1.208 + */ 1.209 + 1.210 + { 1.211 + if (!GetJREPath(jrepath, so_jrepath) ) { 1.212 + ReportErrorMessage("Error: could not find Java SE Runtime Environment.", 1.213 + JNI_TRUE); 1.214 + exit(2); 1.215 + } 1.216 + 1.217 + if (!GetJVMPath(jrepath, NULL, jvmpath, so_jvmpath)) { 1.218 + char * message=NULL; 1.219 + const char * format = "Error: no JVM at `%s'."; 1.220 + message = (char *)JLI_MemAlloc((strlen(format)+ 1.221 + strlen(jvmpath)) * sizeof(char)); 1.222 + sprintf(message, format, jvmpath); 1.223 + ReportErrorMessage(message, JNI_TRUE); 1.224 + exit(4); 1.225 + } 1.226 + } 1.227 + 1.228 +#endif /* ifndef GAMMA */ 1.229 + 1.230 +} 1.231 + 1.232 + 1.233 +static jboolean 1.234 +LoadMSVCRT() 1.235 +{ 1.236 + // Only do this once 1.237 + static int loaded = 0; 1.238 + char crtpath[MAXPATHLEN]; 1.239 + 1.240 + if (!loaded) { 1.241 + /* 1.242 + * The Microsoft C Runtime Library needs to be loaded first. A copy is 1.243 + * assumed to be present in the "JRE path" directory. If it is not found 1.244 + * there (or "JRE path" fails to resolve), skip the explicit load and let 1.245 + * nature take its course, which is likely to be a failure to execute. 1.246 + */ 1.247 + if (GetJREPath(crtpath, MAXPATHLEN)) { 1.248 + (void)strcat(crtpath, "\\bin\\" CRT_DLL); /* Add crt dll */ 1.249 + if (_launcher_debug) { 1.250 + printf("CRT path is %s\n", crtpath); 1.251 + } 1.252 + if (_access(crtpath, 0) == 0) { 1.253 + if (LoadLibrary(crtpath) == 0) { 1.254 + ReportErrorMessage2("Error loading: %s", crtpath, JNI_TRUE); 1.255 + return JNI_FALSE; 1.256 + } 1.257 + } 1.258 + } 1.259 + loaded = 1; 1.260 + } 1.261 + return JNI_TRUE; 1.262 +} 1.263 + 1.264 +/* 1.265 + * The preJVMStart is a function in the jkernel.dll, which 1.266 + * performs the final step of synthesizing back the decomposed 1.267 + * modules (partial install) to the full JRE. Any tool which 1.268 + * uses the JRE must peform this step to ensure the complete synthesis. 1.269 + * The EnsureJreInstallation function calls preJVMStart based on 1.270 + * the conditions outlined below, noting that the operation 1.271 + * will fail silently if any of conditions are not met. 1.272 + * NOTE: this call must be made before jvm.dll is loaded, or jvm.cfg 1.273 + * is read, since jvm.cfg will be modified by the preJVMStart. 1.274 + * 1. Are we on a supported platform. 1.275 + * 2. Find the location of the JRE or the Kernel JRE. 1.276 + * 3. check existence of JREHOME/lib/bundles 1.277 + * 4. check jkernel.dll and invoke the entry-point 1.278 + */ 1.279 +typedef VOID (WINAPI *PREJVMSTART)(); 1.280 + 1.281 +static void 1.282 +EnsureJreInstallation(const char* jrepath) 1.283 +{ 1.284 + HINSTANCE handle; 1.285 + char tmpbuf[MAXPATHLEN]; 1.286 + PREJVMSTART PreJVMStart; 1.287 + struct stat s; 1.288 + 1.289 + /* 32 bit windows only please */ 1.290 + if (strcmp(GetArch(), "i386") != 0 ) { 1.291 + if (_launcher_debug) { 1.292 + printf("EnsureJreInstallation:unsupported platform\n"); 1.293 + } 1.294 + return; 1.295 + } 1.296 + /* Does our bundle directory exist ? */ 1.297 + strcpy(tmpbuf, jrepath); 1.298 + strcat(tmpbuf, "\\lib\\bundles"); 1.299 + if (stat(tmpbuf, &s) != 0) { 1.300 + if (_launcher_debug) { 1.301 + printf("EnsureJreInstallation:<%s>:not found\n", tmpbuf); 1.302 + } 1.303 + return; 1.304 + } 1.305 + /* Does our jkernel dll exist ? */ 1.306 + strcpy(tmpbuf, jrepath); 1.307 + strcat(tmpbuf, "\\bin\\jkernel.dll"); 1.308 + if (stat(tmpbuf, &s) != 0) { 1.309 + if (_launcher_debug) { 1.310 + printf("EnsureJreInstallation:<%s>:not found\n", tmpbuf); 1.311 + } 1.312 + return; 1.313 + } 1.314 + /* The Microsoft C Runtime Library needs to be loaded first. */ 1.315 + if (!LoadMSVCRT()) { 1.316 + if (_launcher_debug) { 1.317 + printf("EnsureJreInstallation:could not load C runtime DLL\n"); 1.318 + } 1.319 + return; 1.320 + } 1.321 + /* Load the jkernel.dll */ 1.322 + if ((handle = LoadLibrary(tmpbuf)) == 0) { 1.323 + if (_launcher_debug) { 1.324 + printf("EnsureJreInstallation:%s:load failed\n", tmpbuf); 1.325 + } 1.326 + return; 1.327 + } 1.328 + /* Get the function address */ 1.329 + PreJVMStart = (PREJVMSTART)GetProcAddress(handle, "preJVMStart"); 1.330 + if (PreJVMStart == NULL) { 1.331 + if (_launcher_debug) { 1.332 + printf("EnsureJreInstallation:preJVMStart:function lookup failed\n"); 1.333 + } 1.334 + FreeLibrary(handle); 1.335 + return; 1.336 + } 1.337 + PreJVMStart(); 1.338 + if (_launcher_debug) { 1.339 + printf("EnsureJreInstallation:preJVMStart:called\n"); 1.340 + } 1.341 + FreeLibrary(handle); 1.342 + return; 1.343 +} 1.344 + 1.345 +/* 1.346 + * Find path to JRE based on .exe's location or registry settings. 1.347 + */ 1.348 +jboolean 1.349 +GetJREPath(char *path, jint pathsize) 1.350 +{ 1.351 + char javadll[MAXPATHLEN]; 1.352 + struct stat s; 1.353 + 1.354 + if (GetApplicationHome(path, pathsize)) { 1.355 + /* Is JRE co-located with the application? */ 1.356 + sprintf(javadll, "%s\\bin\\" JAVA_DLL, path); 1.357 + if (stat(javadll, &s) == 0) { 1.358 + goto found; 1.359 + } 1.360 + 1.361 + /* Does this app ship a private JRE in <apphome>\jre directory? */ 1.362 + sprintf(javadll, "%s\\jre\\bin\\" JAVA_DLL, path); 1.363 + if (stat(javadll, &s) == 0) { 1.364 + strcat(path, "\\jre"); 1.365 + goto found; 1.366 + } 1.367 + } 1.368 + 1.369 +#ifndef GAMMA 1.370 + /* Look for a public JRE on this machine. */ 1.371 + if (GetPublicJREHome(path, pathsize)) { 1.372 + goto found; 1.373 + } 1.374 +#endif 1.375 + 1.376 + fprintf(stderr, "Error: could not find " JAVA_DLL "\n"); 1.377 + return JNI_FALSE; 1.378 + 1.379 + found: 1.380 + if (_launcher_debug) 1.381 + printf("JRE path is %s\n", path); 1.382 + return JNI_TRUE; 1.383 +} 1.384 + 1.385 +/* 1.386 + * Given a JRE location and a JVM type, construct what the name the 1.387 + * JVM shared library will be. Return true, if such a library 1.388 + * exists, false otherwise. 1.389 + */ 1.390 +static jboolean 1.391 +GetJVMPath(const char *jrepath, const char *jvmtype, 1.392 + char *jvmpath, jint jvmpathsize) 1.393 +{ 1.394 + struct stat s; 1.395 + 1.396 +#ifndef GAMMA 1.397 + if (strchr(jvmtype, '/') || strchr(jvmtype, '\\')) { 1.398 + sprintf(jvmpath, "%s\\" JVM_DLL, jvmtype); 1.399 + } else { 1.400 + sprintf(jvmpath, "%s\\bin\\%s\\" JVM_DLL, jrepath, jvmtype); 1.401 + } 1.402 +#else 1.403 + /* 1.404 + * For gamma launcher, JVM is either built-in or in the same directory. 1.405 + * Either way we return "<exe_path>/jvm.dll" where <exe_path> is the 1.406 + * directory where gamma launcher is located. 1.407 + */ 1.408 + 1.409 + char *p; 1.410 + GetModuleFileName(0, jvmpath, jvmpathsize); 1.411 + 1.412 + p = strrchr(jvmpath, '\\'); 1.413 + if (p) { 1.414 + /* replace executable name with libjvm.so */ 1.415 + snprintf(p + 1, jvmpathsize - (p + 1 - jvmpath), "%s", JVM_DLL); 1.416 + } else { 1.417 + /* this case shouldn't happen */ 1.418 + snprintf(jvmpath, jvmpathsize, "%s", JVM_DLL); 1.419 + } 1.420 +#endif /* ifndef GAMMA */ 1.421 + 1.422 + if (stat(jvmpath, &s) == 0) { 1.423 + return JNI_TRUE; 1.424 + } else { 1.425 + return JNI_FALSE; 1.426 + } 1.427 +} 1.428 + 1.429 +/* 1.430 + * Load a jvm from "jvmpath" and initialize the invocation functions. 1.431 + */ 1.432 +jboolean 1.433 +LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn) 1.434 +{ 1.435 +#ifdef GAMMA 1.436 + /* JVM is directly linked with gamma launcher; no Loadlibrary() */ 1.437 + ifn->CreateJavaVM = JNI_CreateJavaVM; 1.438 + ifn->GetDefaultJavaVMInitArgs = JNI_GetDefaultJavaVMInitArgs; 1.439 + return JNI_TRUE; 1.440 +#else 1.441 + HINSTANCE handle; 1.442 + 1.443 + if (_launcher_debug) { 1.444 + printf("JVM path is %s\n", jvmpath); 1.445 + } 1.446 + 1.447 + /* The Microsoft C Runtime Library needs to be loaded first. */ 1.448 + LoadMSVCRT(); 1.449 + 1.450 + /* Load the Java VM DLL */ 1.451 + if ((handle = LoadLibrary(jvmpath)) == 0) { 1.452 + ReportErrorMessage2("Error loading: %s", (char *)jvmpath, JNI_TRUE); 1.453 + return JNI_FALSE; 1.454 + } 1.455 + 1.456 + /* Now get the function addresses */ 1.457 + ifn->CreateJavaVM = 1.458 + (void *)GetProcAddress(handle, "JNI_CreateJavaVM"); 1.459 + ifn->GetDefaultJavaVMInitArgs = 1.460 + (void *)GetProcAddress(handle, "JNI_GetDefaultJavaVMInitArgs"); 1.461 + if (ifn->CreateJavaVM == 0 || ifn->GetDefaultJavaVMInitArgs == 0) { 1.462 + ReportErrorMessage2("Error: can't find JNI interfaces in: %s", 1.463 + (char *)jvmpath, JNI_TRUE); 1.464 + return JNI_FALSE; 1.465 + } 1.466 + 1.467 + return JNI_TRUE; 1.468 +#endif /* ifndef GAMMA */ 1.469 +} 1.470 + 1.471 +/* 1.472 + * If app is "c:\foo\bin\javac", then put "c:\foo" into buf. 1.473 + */ 1.474 +jboolean 1.475 +GetApplicationHome(char *buf, jint bufsize) 1.476 +{ 1.477 +#ifndef GAMMA 1.478 + char *cp; 1.479 + GetModuleFileName(0, buf, bufsize); 1.480 + *strrchr(buf, '\\') = '\0'; /* remove .exe file name */ 1.481 + if ((cp = strrchr(buf, '\\')) == 0) { 1.482 + /* This happens if the application is in a drive root, and 1.483 + * there is no bin directory. */ 1.484 + buf[0] = '\0'; 1.485 + return JNI_FALSE; 1.486 + } 1.487 + *cp = '\0'; /* remove the bin\ part */ 1.488 + return JNI_TRUE; 1.489 + 1.490 +#else /* ifndef GAMMA */ 1.491 + 1.492 + /* gamma launcher uses JAVA_HOME or ALT_JAVA_HOME environment variable to find JDK/JRE */ 1.493 + char* java_home_var = getenv("ALT_JAVA_HOME"); 1.494 + if (java_home_var == NULL) { 1.495 + java_home_var = getenv("JAVA_HOME"); 1.496 + } 1.497 + if (java_home_var == NULL) { 1.498 + printf("JAVA_HOME or ALT_JAVA_HOME must point to a valid JDK/JRE to run gamma\n"); 1.499 + return JNI_FALSE; 1.500 + } 1.501 + snprintf(buf, bufsize, "%s", java_home_var); 1.502 + return JNI_TRUE; 1.503 +#endif /* ifndef GAMMA */ 1.504 +} 1.505 + 1.506 +#ifdef JAVAW 1.507 +__declspec(dllimport) char **__initenv; 1.508 + 1.509 +int WINAPI 1.510 +WinMain(HINSTANCE inst, HINSTANCE previnst, LPSTR cmdline, int cmdshow) 1.511 +{ 1.512 + int ret; 1.513 + 1.514 + __initenv = _environ; 1.515 + ret = main(__argc, __argv); 1.516 + 1.517 + return ret; 1.518 +} 1.519 +#endif 1.520 + 1.521 +#ifndef GAMMA 1.522 + 1.523 +/* 1.524 + * Helpers to look in the registry for a public JRE. 1.525 + */ 1.526 + /* Same for 1.5.0, 1.5.1, 1.5.2 etc. */ 1.527 +#define DOTRELEASE JDK_MAJOR_VERSION "." JDK_MINOR_VERSION 1.528 +#define JRE_KEY "Software\\JavaSoft\\Java Runtime Environment" 1.529 + 1.530 +static jboolean 1.531 +GetStringFromRegistry(HKEY key, const char *name, char *buf, jint bufsize) 1.532 +{ 1.533 + DWORD type, size; 1.534 + 1.535 + if (RegQueryValueEx(key, name, 0, &type, 0, &size) == 0 1.536 + && type == REG_SZ 1.537 + && (size < (unsigned int)bufsize)) { 1.538 + if (RegQueryValueEx(key, name, 0, 0, buf, &size) == 0) { 1.539 + return JNI_TRUE; 1.540 + } 1.541 + } 1.542 + return JNI_FALSE; 1.543 +} 1.544 + 1.545 +static jboolean 1.546 +GetPublicJREHome(char *buf, jint bufsize) 1.547 +{ 1.548 + HKEY key, subkey; 1.549 + char version[MAXPATHLEN]; 1.550 + 1.551 + /* 1.552 + * Note: There is a very similar implementation of the following 1.553 + * registry reading code in the Windows java control panel (javacp.cpl). 1.554 + * If there are bugs here, a similar bug probably exists there. Hence, 1.555 + * changes here require inspection there. 1.556 + */ 1.557 + 1.558 + /* Find the current version of the JRE */ 1.559 + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, JRE_KEY, 0, KEY_READ, &key) != 0) { 1.560 + fprintf(stderr, "Error opening registry key '" JRE_KEY "'\n"); 1.561 + return JNI_FALSE; 1.562 + } 1.563 + 1.564 + if (!GetStringFromRegistry(key, "CurrentVersion", 1.565 + version, sizeof(version))) { 1.566 + fprintf(stderr, "Failed reading value of registry key:\n\t" 1.567 + JRE_KEY "\\CurrentVersion\n"); 1.568 + RegCloseKey(key); 1.569 + return JNI_FALSE; 1.570 + } 1.571 + 1.572 + if (strcmp(version, DOTRELEASE) != 0) { 1.573 + fprintf(stderr, "Registry key '" JRE_KEY "\\CurrentVersion'\nhas " 1.574 + "value '%s', but '" DOTRELEASE "' is required.\n", version); 1.575 + RegCloseKey(key); 1.576 + return JNI_FALSE; 1.577 + } 1.578 + 1.579 + /* Find directory where the current version is installed. */ 1.580 + if (RegOpenKeyEx(key, version, 0, KEY_READ, &subkey) != 0) { 1.581 + fprintf(stderr, "Error opening registry key '" 1.582 + JRE_KEY "\\%s'\n", version); 1.583 + RegCloseKey(key); 1.584 + return JNI_FALSE; 1.585 + } 1.586 + 1.587 + if (!GetStringFromRegistry(subkey, "JavaHome", buf, bufsize)) { 1.588 + fprintf(stderr, "Failed reading value of registry key:\n\t" 1.589 + JRE_KEY "\\%s\\JavaHome\n", version); 1.590 + RegCloseKey(key); 1.591 + RegCloseKey(subkey); 1.592 + return JNI_FALSE; 1.593 + } 1.594 + 1.595 + if (_launcher_debug) { 1.596 + char micro[MAXPATHLEN]; 1.597 + if (!GetStringFromRegistry(subkey, "MicroVersion", micro, 1.598 + sizeof(micro))) { 1.599 + printf("Warning: Can't read MicroVersion\n"); 1.600 + micro[0] = '\0'; 1.601 + } 1.602 + printf("Version major.minor.micro = %s.%s\n", version, micro); 1.603 + } 1.604 + 1.605 + RegCloseKey(key); 1.606 + RegCloseKey(subkey); 1.607 + return JNI_TRUE; 1.608 +} 1.609 + 1.610 +#endif /* ifndef GAMMA */ 1.611 + 1.612 +/* 1.613 + * Support for doing cheap, accurate interval timing. 1.614 + */ 1.615 +static jboolean counterAvailable = JNI_FALSE; 1.616 +static jboolean counterInitialized = JNI_FALSE; 1.617 +static LARGE_INTEGER counterFrequency; 1.618 + 1.619 +jlong CounterGet() 1.620 +{ 1.621 + LARGE_INTEGER count; 1.622 + 1.623 + if (!counterInitialized) { 1.624 + counterAvailable = QueryPerformanceFrequency(&counterFrequency); 1.625 + counterInitialized = JNI_TRUE; 1.626 + } 1.627 + if (!counterAvailable) { 1.628 + return 0; 1.629 + } 1.630 + QueryPerformanceCounter(&count); 1.631 + return (jlong)(count.QuadPart); 1.632 +} 1.633 + 1.634 +jlong Counter2Micros(jlong counts) 1.635 +{ 1.636 + if (!counterAvailable || !counterInitialized) { 1.637 + return 0; 1.638 + } 1.639 + return (counts * 1000 * 1000)/counterFrequency.QuadPart; 1.640 +} 1.641 + 1.642 +void ReportErrorMessage(char * message, jboolean always) { 1.643 +#ifdef JAVAW 1.644 + if (message != NULL) { 1.645 + MessageBox(NULL, message, "Java Virtual Machine Launcher", 1.646 + (MB_OK|MB_ICONSTOP|MB_APPLMODAL)); 1.647 + } 1.648 +#else 1.649 + if (always) { 1.650 + fprintf(stderr, "%s\n", message); 1.651 + } 1.652 +#endif 1.653 +} 1.654 + 1.655 +void ReportErrorMessage2(char * format, char * string, jboolean always) { 1.656 + /* 1.657 + * The format argument must be a printf format string with one %s 1.658 + * argument, which is passed the string argument. 1.659 + */ 1.660 +#ifdef JAVAW 1.661 + size_t size; 1.662 + char * message; 1.663 + size = strlen(format) + strlen(string); 1.664 + message = (char*)JLI_MemAlloc(size*sizeof(char)); 1.665 + sprintf(message, (const char *)format, string); 1.666 + 1.667 + if (message != NULL) { 1.668 + MessageBox(NULL, message, "Java Virtual Machine Launcher", 1.669 + (MB_OK|MB_ICONSTOP|MB_APPLMODAL)); 1.670 + JLI_MemFree(message); 1.671 + } 1.672 +#else 1.673 + if (always) { 1.674 + fprintf(stderr, (const char *)format, string); 1.675 + fprintf(stderr, "\n"); 1.676 + } 1.677 +#endif 1.678 +} 1.679 + 1.680 +/* 1.681 + * As ReportErrorMessage2 (above) except the system message (if any) 1.682 + * associated with this error is written to a second %s format specifier 1.683 + * in the format argument. 1.684 + */ 1.685 +void ReportSysErrorMessage2(char * format, char * string, jboolean always) { 1.686 + int save_errno = errno; 1.687 + DWORD errval; 1.688 + int freeit = 0; 1.689 + char *errtext = NULL; 1.690 + 1.691 + if ((errval = GetLastError()) != 0) { /* Platform SDK / DOS Error */ 1.692 + int n = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM| 1.693 + FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_ALLOCATE_BUFFER, 1.694 + NULL, errval, 0, (LPTSTR)&errtext, 0, NULL); 1.695 + if (errtext == NULL || n == 0) { /* Paranoia check */ 1.696 + errtext = ""; 1.697 + n = 0; 1.698 + } else { 1.699 + freeit = 1; 1.700 + if (n > 2) { /* Drop final CR, LF */ 1.701 + if (errtext[n - 1] == '\n') n--; 1.702 + if (errtext[n - 1] == '\r') n--; 1.703 + errtext[n] = '\0'; 1.704 + } 1.705 + } 1.706 + } else /* C runtime error that has no corresponding DOS error code */ 1.707 + errtext = strerror(save_errno); 1.708 + 1.709 +#ifdef JAVAW 1.710 + { 1.711 + size_t size; 1.712 + char * message; 1.713 + size = strlen(format) + strlen(string) + strlen(errtext); 1.714 + message = (char*)JLI_MemAlloc(size*sizeof(char)); 1.715 + sprintf(message, (const char *)format, string, errtext); 1.716 + 1.717 + if (message != NULL) { 1.718 + MessageBox(NULL, message, "Java Virtual Machine Launcher", 1.719 + (MB_OK|MB_ICONSTOP|MB_APPLMODAL)); 1.720 + JLI_MemFree(message); 1.721 + } 1.722 + } 1.723 +#else 1.724 + if (always) { 1.725 + fprintf(stderr, (const char *)format, string, errtext); 1.726 + fprintf(stderr, "\n"); 1.727 + } 1.728 +#endif 1.729 + if (freeit) 1.730 + (void)LocalFree((HLOCAL)errtext); 1.731 +} 1.732 + 1.733 +void ReportExceptionDescription(JNIEnv * env) { 1.734 +#ifdef JAVAW 1.735 + /* 1.736 + * This code should be replaced by code which opens a window with 1.737 + * the exception detail message. 1.738 + */ 1.739 + (*env)->ExceptionDescribe(env); 1.740 +#else 1.741 + (*env)->ExceptionDescribe(env); 1.742 +#endif 1.743 +} 1.744 + 1.745 + 1.746 +/* 1.747 + * Return JNI_TRUE for an option string that has no effect but should 1.748 + * _not_ be passed on to the vm; return JNI_FALSE otherwise. On 1.749 + * windows, there are no options that should be screened in this 1.750 + * manner. 1.751 + */ 1.752 +jboolean RemovableMachineDependentOption(char * option) { 1.753 +#ifdef ENABLE_AWT_PRELOAD 1.754 + if (awtPreloadD3D < 0) { 1.755 + /* Tests the command line parameter only if not set yet. */ 1.756 + if (GetBoolParamValue(PARAM_PRELOAD_D3D, option) == 1) { 1.757 + awtPreloadD3D = 1; 1.758 + } 1.759 + } 1.760 + if (awtPreloadD3D != 0) { 1.761 + /* Don't test the command line parameters if already disabled. */ 1.762 + if (GetBoolParamValue(PARAM_NODDRAW, option) == 1 1.763 + || GetBoolParamValue(PARAM_D3D, option) == 0 1.764 + || GetBoolParamValue(PARAM_OPENGL, option) == 1) 1.765 + { 1.766 + awtPreloadD3D = 0; 1.767 + } 1.768 + } 1.769 +#endif /* ENABLE_AWT_PRELOAD */ 1.770 + 1.771 + return JNI_FALSE; 1.772 +} 1.773 + 1.774 +void PrintMachineDependentOptions() { 1.775 + return; 1.776 +} 1.777 + 1.778 +#ifndef GAMMA 1.779 + 1.780 +jboolean 1.781 +ServerClassMachine() { 1.782 + jboolean result = JNI_FALSE; 1.783 +#if defined(NEVER_ACT_AS_SERVER_CLASS_MACHINE) 1.784 + result = JNI_FALSE; 1.785 +#elif defined(ALWAYS_ACT_AS_SERVER_CLASS_MACHINE) 1.786 + result = JNI_TRUE; 1.787 +#endif 1.788 + return result; 1.789 +} 1.790 + 1.791 +/* 1.792 + * Determine if there is an acceptable JRE in the registry directory top_key. 1.793 + * Upon locating the "best" one, return a fully qualified path to it. 1.794 + * "Best" is defined as the most advanced JRE meeting the constraints 1.795 + * contained in the manifest_info. If no JRE in this directory meets the 1.796 + * constraints, return NULL. 1.797 + * 1.798 + * It doesn't matter if we get an error reading the registry, or we just 1.799 + * don't find anything interesting in the directory. We just return NULL 1.800 + * in either case. 1.801 + */ 1.802 +static char * 1.803 +ProcessDir(manifest_info* info, HKEY top_key) { 1.804 + DWORD index = 0; 1.805 + HKEY ver_key; 1.806 + char name[MAXNAMELEN]; 1.807 + int len; 1.808 + char *best = NULL; 1.809 + 1.810 + /* 1.811 + * Enumerate "<top_key>/SOFTWARE/JavaSoft/Java Runtime Environment" 1.812 + * searching for the best available version. 1.813 + */ 1.814 + while (RegEnumKey(top_key, index, name, MAXNAMELEN) == ERROR_SUCCESS) { 1.815 + index++; 1.816 + if (JLI_AcceptableRelease(name, info->jre_version)) 1.817 + if ((best == NULL) || (JLI_ExactVersionId(name, best) > 0)) { 1.818 + if (best != NULL) 1.819 + JLI_MemFree(best); 1.820 + best = JLI_StringDup(name); 1.821 + } 1.822 + } 1.823 + 1.824 + /* 1.825 + * Extract "JavaHome" from the "best" registry directory and return 1.826 + * that path. If no appropriate version was located, or there is an 1.827 + * error in extracting the "JavaHome" string, return null. 1.828 + */ 1.829 + if (best == NULL) 1.830 + return (NULL); 1.831 + else { 1.832 + if (RegOpenKeyEx(top_key, best, 0, KEY_READ, &ver_key) 1.833 + != ERROR_SUCCESS) { 1.834 + JLI_MemFree(best); 1.835 + if (ver_key != NULL) 1.836 + RegCloseKey(ver_key); 1.837 + return (NULL); 1.838 + } 1.839 + JLI_MemFree(best); 1.840 + len = MAXNAMELEN; 1.841 + if (RegQueryValueEx(ver_key, "JavaHome", NULL, NULL, (LPBYTE)name, &len) 1.842 + != ERROR_SUCCESS) { 1.843 + if (ver_key != NULL) 1.844 + RegCloseKey(ver_key); 1.845 + return (NULL); 1.846 + } 1.847 + if (ver_key != NULL) 1.848 + RegCloseKey(ver_key); 1.849 + return (JLI_StringDup(name)); 1.850 + } 1.851 +} 1.852 + 1.853 +/* 1.854 + * This is the global entry point. It examines the host for the optimal 1.855 + * JRE to be used by scanning a set of registry entries. This set of entries 1.856 + * is hardwired on Windows as "Software\JavaSoft\Java Runtime Environment" 1.857 + * under the set of roots "{ HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE }". 1.858 + * 1.859 + * This routine simply opens each of these registry directories before passing 1.860 + * control onto ProcessDir(). 1.861 + */ 1.862 +char * 1.863 +LocateJRE(manifest_info* info) { 1.864 + HKEY key = NULL; 1.865 + char *path; 1.866 + int key_index; 1.867 + HKEY root_keys[2] = { HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE }; 1.868 + 1.869 + for (key_index = 0; key_index <= 1; key_index++) { 1.870 + if (RegOpenKeyEx(root_keys[key_index], JRE_KEY, 0, KEY_READ, &key) 1.871 + == ERROR_SUCCESS) 1.872 + if ((path = ProcessDir(info, key)) != NULL) { 1.873 + if (key != NULL) 1.874 + RegCloseKey(key); 1.875 + return (path); 1.876 + } 1.877 + if (key != NULL) 1.878 + RegCloseKey(key); 1.879 + } 1.880 + return NULL; 1.881 +} 1.882 + 1.883 + 1.884 +/* 1.885 + * Local helper routine to isolate a single token (option or argument) 1.886 + * from the command line. 1.887 + * 1.888 + * This routine accepts a pointer to a character pointer. The first 1.889 + * token (as defined by MSDN command-line argument syntax) is isolated 1.890 + * from that string. 1.891 + * 1.892 + * Upon return, the input character pointer pointed to by the parameter s 1.893 + * is updated to point to the remainding, unscanned, portion of the string, 1.894 + * or to a null character if the entire string has been consummed. 1.895 + * 1.896 + * This function returns a pointer to a null-terminated string which 1.897 + * contains the isolated first token, or to the null character if no 1.898 + * token could be isolated. 1.899 + * 1.900 + * Note the side effect of modifying the input string s by the insertion 1.901 + * of a null character, making it two strings. 1.902 + * 1.903 + * See "Parsing C Command-Line Arguments" in the MSDN Library for the 1.904 + * parsing rule details. The rule summary from that specification is: 1.905 + * 1.906 + * * Arguments are delimited by white space, which is either a space or a tab. 1.907 + * 1.908 + * * A string surrounded by double quotation marks is interpreted as a single 1.909 + * argument, regardless of white space contained within. A quoted string can 1.910 + * be embedded in an argument. Note that the caret (^) is not recognized as 1.911 + * an escape character or delimiter. 1.912 + * 1.913 + * * A double quotation mark preceded by a backslash, \", is interpreted as a 1.914 + * literal double quotation mark ("). 1.915 + * 1.916 + * * Backslashes are interpreted literally, unless they immediately precede a 1.917 + * double quotation mark. 1.918 + * 1.919 + * * If an even number of backslashes is followed by a double quotation mark, 1.920 + * then one backslash (\) is placed in the argv array for every pair of 1.921 + * backslashes (\\), and the double quotation mark (") is interpreted as a 1.922 + * string delimiter. 1.923 + * 1.924 + * * If an odd number of backslashes is followed by a double quotation mark, 1.925 + * then one backslash (\) is placed in the argv array for every pair of 1.926 + * backslashes (\\) and the double quotation mark is interpreted as an 1.927 + * escape sequence by the remaining backslash, causing a literal double 1.928 + * quotation mark (") to be placed in argv. 1.929 + */ 1.930 +static char* 1.931 +nextarg(char** s) { 1.932 + char *p = *s; 1.933 + char *head; 1.934 + int slashes = 0; 1.935 + int inquote = 0; 1.936 + 1.937 + /* 1.938 + * Strip leading whitespace, which MSDN defines as only space or tab. 1.939 + * (Hence, no locale specific "isspace" here.) 1.940 + */ 1.941 + while (*p != (char)0 && (*p == ' ' || *p == '\t')) 1.942 + p++; 1.943 + head = p; /* Save the start of the token to return */ 1.944 + 1.945 + /* 1.946 + * Isolate a token from the command line. 1.947 + */ 1.948 + while (*p != (char)0 && (inquote || !(*p == ' ' || *p == '\t'))) { 1.949 + if (*p == '\\' && *(p+1) == '"' && slashes % 2 == 0) 1.950 + p++; 1.951 + else if (*p == '"') 1.952 + inquote = !inquote; 1.953 + slashes = (*p++ == '\\') ? slashes + 1 : 0; 1.954 + } 1.955 + 1.956 + /* 1.957 + * If the token isolated isn't already terminated in a "char zero", 1.958 + * then replace the whitespace character with one and move to the 1.959 + * next character. 1.960 + */ 1.961 + if (*p != (char)0) 1.962 + *p++ = (char)0; 1.963 + 1.964 + /* 1.965 + * Update the parameter to point to the head of the remaining string 1.966 + * reflecting the command line and return a pointer to the leading 1.967 + * token which was isolated from the command line. 1.968 + */ 1.969 + *s = p; 1.970 + return (head); 1.971 +} 1.972 + 1.973 +/* 1.974 + * Local helper routine to return a string equivalent to the input string 1.975 + * s, but with quotes removed so the result is a string as would be found 1.976 + * in argv[]. The returned string should be freed by a call to JLI_MemFree(). 1.977 + * 1.978 + * The rules for quoting (and escaped quotes) are: 1.979 + * 1.980 + * 1 A double quotation mark preceded by a backslash, \", is interpreted as a 1.981 + * literal double quotation mark ("). 1.982 + * 1.983 + * 2 Backslashes are interpreted literally, unless they immediately precede a 1.984 + * double quotation mark. 1.985 + * 1.986 + * 3 If an even number of backslashes is followed by a double quotation mark, 1.987 + * then one backslash (\) is placed in the argv array for every pair of 1.988 + * backslashes (\\), and the double quotation mark (") is interpreted as a 1.989 + * string delimiter. 1.990 + * 1.991 + * 4 If an odd number of backslashes is followed by a double quotation mark, 1.992 + * then one backslash (\) is placed in the argv array for every pair of 1.993 + * backslashes (\\) and the double quotation mark is interpreted as an 1.994 + * escape sequence by the remaining backslash, causing a literal double 1.995 + * quotation mark (") to be placed in argv. 1.996 + */ 1.997 +static char* 1.998 +unquote(const char *s) { 1.999 + const char *p = s; /* Pointer to the tail of the original string */ 1.1000 + char *un = (char*)JLI_MemAlloc(strlen(s) + 1); /* Ptr to unquoted string */ 1.1001 + char *pun = un; /* Pointer to the tail of the unquoted string */ 1.1002 + 1.1003 + while (*p != '\0') { 1.1004 + if (*p == '"') { 1.1005 + p++; 1.1006 + } else if (*p == '\\') { 1.1007 + const char *q = p + strspn(p,"\\"); 1.1008 + if (*q == '"') 1.1009 + do { 1.1010 + *pun++ = '\\'; 1.1011 + p += 2; 1.1012 + } while (*p == '\\' && p < q); 1.1013 + else 1.1014 + while (p < q) 1.1015 + *pun++ = *p++; 1.1016 + } else { 1.1017 + *pun++ = *p++; 1.1018 + } 1.1019 + } 1.1020 + *pun = '\0'; 1.1021 + return un; 1.1022 +} 1.1023 + 1.1024 +/* 1.1025 + * Given a path to a jre to execute, this routine checks if this process 1.1026 + * is indeed that jre. If not, it exec's that jre. 1.1027 + * 1.1028 + * We want to actually check the paths rather than just the version string 1.1029 + * built into the executable, so that given version specification will yield 1.1030 + * the exact same Java environment, regardless of the version of the arbitrary 1.1031 + * launcher we start with. 1.1032 + */ 1.1033 +void 1.1034 +ExecJRE(char *jre, char **argv) { 1.1035 + int len; 1.1036 + char *progname; 1.1037 + char path[MAXPATHLEN + 1]; 1.1038 + 1.1039 + /* 1.1040 + * Determine the executable we are building (or in the rare case, running). 1.1041 + */ 1.1042 +#ifdef JAVA_ARGS /* javac, jar and friends. */ 1.1043 + progname = "java"; 1.1044 +#else /* java, oldjava, javaw and friends */ 1.1045 +#ifdef PROGNAME 1.1046 + progname = PROGNAME; 1.1047 +#else 1.1048 + { 1.1049 + char *s; 1.1050 + progname = *argv; 1.1051 + if ((s = strrchr(progname, FILE_SEPARATOR)) != 0) { 1.1052 + progname = s + 1; 1.1053 + } 1.1054 + } 1.1055 +#endif /* PROGNAME */ 1.1056 +#endif /* JAVA_ARGS */ 1.1057 + 1.1058 + /* 1.1059 + * Resolve the real path to the currently running launcher. 1.1060 + */ 1.1061 + len = GetModuleFileName(NULL, path, MAXPATHLEN + 1); 1.1062 + if (len == 0 || len > MAXPATHLEN) { 1.1063 + ReportSysErrorMessage2( 1.1064 + "Unable to resolve path to current %s executable: %s", 1.1065 + progname, JNI_TRUE); 1.1066 + exit(1); 1.1067 + } 1.1068 + 1.1069 + if (_launcher_debug) { 1.1070 + printf("ExecJRE: old: %s\n", path); 1.1071 + printf("ExecJRE: new: %s\n", jre); 1.1072 + } 1.1073 + 1.1074 + /* 1.1075 + * If the path to the selected JRE directory is a match to the initial 1.1076 + * portion of the path to the currently executing JRE, we have a winner! 1.1077 + * If so, just return. (strnicmp() is the Windows equiv. of strncasecmp().) 1.1078 + */ 1.1079 + if (strnicmp(jre, path, strlen(jre)) == 0) 1.1080 + return; /* I am the droid you were looking for */ 1.1081 + 1.1082 + /* 1.1083 + * If this isn't the selected version, exec the selected version. 1.1084 + */ 1.1085 + (void)strcat(strcat(strcpy(path, jre), "\\bin\\"), progname); 1.1086 + (void)strcat(path, ".exe"); 1.1087 + 1.1088 + /* 1.1089 + * Although Windows has an execv() entrypoint, it doesn't actually 1.1090 + * overlay a process: it can only create a new process and terminate 1.1091 + * the old process. Therefore, any processes waiting on the initial 1.1092 + * process wake up and they shouldn't. Hence, a chain of pseudo-zombie 1.1093 + * processes must be retained to maintain the proper wait semantics. 1.1094 + * Fortunately the image size of the launcher isn't too large at this 1.1095 + * time. 1.1096 + * 1.1097 + * If it weren't for this semantic flaw, the code below would be ... 1.1098 + * 1.1099 + * execv(path, argv); 1.1100 + * ReportErrorMessage2("Exec of %s failed\n", path, JNI_TRUE); 1.1101 + * exit(1); 1.1102 + * 1.1103 + * The incorrect exec semantics could be addressed by: 1.1104 + * 1.1105 + * exit((int)spawnv(_P_WAIT, path, argv)); 1.1106 + * 1.1107 + * Unfortunately, a bug in Windows spawn/exec impementation prevents 1.1108 + * this from completely working. All the Windows POSIX process creation 1.1109 + * interfaces are implemented as wrappers around the native Windows 1.1110 + * function CreateProcess(). CreateProcess() takes a single string 1.1111 + * to specify command line options and arguments, so the POSIX routine 1.1112 + * wrappers build a single string from the argv[] array and in the 1.1113 + * process, any quoting information is lost. 1.1114 + * 1.1115 + * The solution to this to get the original command line, to process it 1.1116 + * to remove the new multiple JRE options (if any) as was done for argv 1.1117 + * in the common SelectVersion() routine and finally to pass it directly 1.1118 + * to the native CreateProcess() Windows process control interface. 1.1119 + */ 1.1120 + { 1.1121 + char *cmdline; 1.1122 + char *p; 1.1123 + char *np; 1.1124 + char *ocl; 1.1125 + char *ccl; 1.1126 + char *unquoted; 1.1127 + DWORD exitCode; 1.1128 + STARTUPINFO si; 1.1129 + PROCESS_INFORMATION pi; 1.1130 + 1.1131 + /* 1.1132 + * The following code block gets and processes the original command 1.1133 + * line, replacing the argv[0] equivalent in the command line with 1.1134 + * the path to the new executable and removing the appropriate 1.1135 + * Multiple JRE support options. Note that similar logic exists 1.1136 + * in the platform independent SelectVersion routine, but is 1.1137 + * replicated here due to the syntax of CreateProcess(). 1.1138 + * 1.1139 + * The magic "+ 4" characters added to the command line length are 1.1140 + * 2 possible quotes around the path (argv[0]), a space after the 1.1141 + * path and a terminating null character. 1.1142 + */ 1.1143 + ocl = GetCommandLine(); 1.1144 + np = ccl = JLI_StringDup(ocl); 1.1145 + p = nextarg(&np); /* Discard argv[0] */ 1.1146 + cmdline = (char *)JLI_MemAlloc(strlen(path) + strlen(np) + 4); 1.1147 + if (strchr(path, (int)' ') == NULL && strchr(path, (int)'\t') == NULL) 1.1148 + cmdline = strcpy(cmdline, path); 1.1149 + else 1.1150 + cmdline = strcat(strcat(strcpy(cmdline, "\""), path), "\""); 1.1151 + 1.1152 + while (*np != (char)0) { /* While more command-line */ 1.1153 + p = nextarg(&np); 1.1154 + if (*p != (char)0) { /* If a token was isolated */ 1.1155 + unquoted = unquote(p); 1.1156 + if (*unquoted == '-') { /* Looks like an option */ 1.1157 + if (strcmp(unquoted, "-classpath") == 0 || 1.1158 + strcmp(unquoted, "-cp") == 0) { /* Unique cp syntax */ 1.1159 + cmdline = strcat(strcat(cmdline, " "), p); 1.1160 + p = nextarg(&np); 1.1161 + if (*p != (char)0) /* If a token was isolated */ 1.1162 + cmdline = strcat(strcat(cmdline, " "), p); 1.1163 + } else if (strncmp(unquoted, "-version:", 9) != 0 && 1.1164 + strcmp(unquoted, "-jre-restrict-search") != 0 && 1.1165 + strcmp(unquoted, "-no-jre-restrict-search") != 0) { 1.1166 + cmdline = strcat(strcat(cmdline, " "), p); 1.1167 + } 1.1168 + } else { /* End of options */ 1.1169 + cmdline = strcat(strcat(cmdline, " "), p); 1.1170 + cmdline = strcat(strcat(cmdline, " "), np); 1.1171 + JLI_MemFree((void *)unquoted); 1.1172 + break; 1.1173 + } 1.1174 + JLI_MemFree((void *)unquoted); 1.1175 + } 1.1176 + } 1.1177 + JLI_MemFree((void *)ccl); 1.1178 + 1.1179 + if (_launcher_debug) { 1.1180 + np = ccl = JLI_StringDup(cmdline); 1.1181 + p = nextarg(&np); 1.1182 + printf("ReExec Command: %s (%s)\n", path, p); 1.1183 + printf("ReExec Args: %s\n", np); 1.1184 + JLI_MemFree((void *)ccl); 1.1185 + } 1.1186 + (void)fflush(stdout); 1.1187 + (void)fflush(stderr); 1.1188 + 1.1189 + /* 1.1190 + * The following code is modeled after a model presented in the 1.1191 + * Microsoft Technical Article "Moving Unix Applications to 1.1192 + * Windows NT" (March 6, 1994) and "Creating Processes" on MSDN 1.1193 + * (Februrary 2005). It approximates UNIX spawn semantics with 1.1194 + * the parent waiting for termination of the child. 1.1195 + */ 1.1196 + memset(&si, 0, sizeof(si)); 1.1197 + si.cb =sizeof(STARTUPINFO); 1.1198 + memset(&pi, 0, sizeof(pi)); 1.1199 + 1.1200 + if (!CreateProcess((LPCTSTR)path, /* executable name */ 1.1201 + (LPTSTR)cmdline, /* command line */ 1.1202 + (LPSECURITY_ATTRIBUTES)NULL, /* process security attr. */ 1.1203 + (LPSECURITY_ATTRIBUTES)NULL, /* thread security attr. */ 1.1204 + (BOOL)TRUE, /* inherits system handles */ 1.1205 + (DWORD)0, /* creation flags */ 1.1206 + (LPVOID)NULL, /* environment block */ 1.1207 + (LPCTSTR)NULL, /* current directory */ 1.1208 + (LPSTARTUPINFO)&si, /* (in) startup information */ 1.1209 + (LPPROCESS_INFORMATION)&pi)) { /* (out) process information */ 1.1210 + ReportSysErrorMessage2("CreateProcess(%s, ...) failed: %s", 1.1211 + path, JNI_TRUE); 1.1212 + exit(1); 1.1213 + } 1.1214 + 1.1215 + if (WaitForSingleObject(pi.hProcess, INFINITE) != WAIT_FAILED) { 1.1216 + if (GetExitCodeProcess(pi.hProcess, &exitCode) == FALSE) 1.1217 + exitCode = 1; 1.1218 + } else { 1.1219 + ReportErrorMessage("WaitForSingleObject() failed.", JNI_TRUE); 1.1220 + exitCode = 1; 1.1221 + } 1.1222 + 1.1223 + CloseHandle(pi.hThread); 1.1224 + CloseHandle(pi.hProcess); 1.1225 + 1.1226 + exit(exitCode); 1.1227 + } 1.1228 + 1.1229 +} 1.1230 + 1.1231 +#endif /* ifndef GAMMA */ 1.1232 + 1.1233 + 1.1234 +/* 1.1235 + * Wrapper for platform dependent unsetenv function. 1.1236 + */ 1.1237 +int 1.1238 +UnsetEnv(char *name) 1.1239 +{ 1.1240 + int ret; 1.1241 + char *buf = JLI_MemAlloc(strlen(name) + 2); 1.1242 + buf = strcat(strcpy(buf, name), "="); 1.1243 + ret = _putenv(buf); 1.1244 + JLI_MemFree(buf); 1.1245 + return (ret); 1.1246 +} 1.1247 + 1.1248 +/* --- Splash Screen shared library support --- */ 1.1249 + 1.1250 +static const char* SPLASHSCREEN_SO = "\\bin\\splashscreen.dll"; 1.1251 + 1.1252 +static HMODULE hSplashLib = NULL; 1.1253 + 1.1254 +void* SplashProcAddress(const char* name) { 1.1255 + char libraryPath[MAXPATHLEN]; /* some extra space for strcat'ing SPLASHSCREEN_SO */ 1.1256 + 1.1257 + if (!GetJREPath(libraryPath, MAXPATHLEN)) { 1.1258 + return NULL; 1.1259 + } 1.1260 + if (strlen(libraryPath)+strlen(SPLASHSCREEN_SO) >= MAXPATHLEN) { 1.1261 + return NULL; 1.1262 + } 1.1263 + strcat(libraryPath, SPLASHSCREEN_SO); 1.1264 + 1.1265 + if (!hSplashLib) { 1.1266 + hSplashLib = LoadLibrary(libraryPath); 1.1267 + } 1.1268 + if (hSplashLib) { 1.1269 + return GetProcAddress(hSplashLib, name); 1.1270 + } else { 1.1271 + return NULL; 1.1272 + } 1.1273 +} 1.1274 + 1.1275 +void SplashFreeLibrary() { 1.1276 + if (hSplashLib) { 1.1277 + FreeLibrary(hSplashLib); 1.1278 + hSplashLib = NULL; 1.1279 + } 1.1280 +} 1.1281 + 1.1282 +const char * 1.1283 +jlong_format_specifier() { 1.1284 + return "%I64d"; 1.1285 +} 1.1286 + 1.1287 +/* 1.1288 + * Block current thread and continue execution in a new thread 1.1289 + */ 1.1290 +int 1.1291 +ContinueInNewThread(int (JNICALL *continuation)(void *), jlong stack_size, void * args) { 1.1292 + int rslt = 0; 1.1293 + unsigned thread_id; 1.1294 + 1.1295 +#ifndef STACK_SIZE_PARAM_IS_A_RESERVATION 1.1296 +#define STACK_SIZE_PARAM_IS_A_RESERVATION (0x10000) 1.1297 +#endif 1.1298 + 1.1299 + /* 1.1300 + * STACK_SIZE_PARAM_IS_A_RESERVATION is what we want, but it's not 1.1301 + * supported on older version of Windows. Try first with the flag; and 1.1302 + * if that fails try again without the flag. See MSDN document or HotSpot 1.1303 + * source (os_win32.cpp) for details. 1.1304 + */ 1.1305 + HANDLE thread_handle = 1.1306 + (HANDLE)_beginthreadex(NULL, 1.1307 + (unsigned)stack_size, 1.1308 + continuation, 1.1309 + args, 1.1310 + STACK_SIZE_PARAM_IS_A_RESERVATION, 1.1311 + &thread_id); 1.1312 + if (thread_handle == NULL) { 1.1313 + thread_handle = 1.1314 + (HANDLE)_beginthreadex(NULL, 1.1315 + (unsigned)stack_size, 1.1316 + continuation, 1.1317 + args, 1.1318 + 0, 1.1319 + &thread_id); 1.1320 + } 1.1321 + 1.1322 + /* AWT preloading (AFTER main thread start) */ 1.1323 +#ifdef ENABLE_AWT_PRELOAD 1.1324 + /* D3D preloading */ 1.1325 + if (awtPreloadD3D != 0) { 1.1326 + char *envValue; 1.1327 + /* D3D routines checks env.var J2D_D3D if no appropriate 1.1328 + * command line params was specified 1.1329 + */ 1.1330 + envValue = getenv("J2D_D3D"); 1.1331 + if (envValue != NULL && stricmp(envValue, "false") == 0) { 1.1332 + awtPreloadD3D = 0; 1.1333 + } 1.1334 + /* Test that AWT preloading isn't disabled by J2D_D3D_PRELOAD env.var */ 1.1335 + envValue = getenv("J2D_D3D_PRELOAD"); 1.1336 + if (envValue != NULL && stricmp(envValue, "false") == 0) { 1.1337 + awtPreloadD3D = 0; 1.1338 + } 1.1339 + if (awtPreloadD3D < 0) { 1.1340 + /* If awtPreloadD3D is still undefined (-1), test 1.1341 + * if it is turned on by J2D_D3D_PRELOAD env.var. 1.1342 + * By default it's turned OFF. 1.1343 + */ 1.1344 + awtPreloadD3D = 0; 1.1345 + if (envValue != NULL && stricmp(envValue, "true") == 0) { 1.1346 + awtPreloadD3D = 1; 1.1347 + } 1.1348 + } 1.1349 + } 1.1350 + if (awtPreloadD3D) { 1.1351 + AWTPreload(D3D_PRELOAD_FUNC); 1.1352 + } 1.1353 +#endif /* ENABLE_AWT_PRELOAD */ 1.1354 + 1.1355 + if (thread_handle) { 1.1356 + WaitForSingleObject(thread_handle, INFINITE); 1.1357 + GetExitCodeThread(thread_handle, &rslt); 1.1358 + CloseHandle(thread_handle); 1.1359 + } else { 1.1360 + rslt = continuation(args); 1.1361 + } 1.1362 + 1.1363 +#ifdef ENABLE_AWT_PRELOAD 1.1364 + if (awtPreloaded) { 1.1365 + AWTPreloadStop(); 1.1366 + } 1.1367 +#endif /* ENABLE_AWT_PRELOAD */ 1.1368 + 1.1369 + return rslt; 1.1370 +} 1.1371 + 1.1372 +/* Linux only, empty on windows. */ 1.1373 +void SetJavaLauncherPlatformProps() {} 1.1374 + 1.1375 + 1.1376 +//============================== 1.1377 +// AWT preloading 1.1378 +#ifdef ENABLE_AWT_PRELOAD 1.1379 + 1.1380 +typedef int FnPreloadStart(void); 1.1381 +typedef void FnPreloadStop(void); 1.1382 +static FnPreloadStop *fnPreloadStop = NULL; 1.1383 +static HMODULE hPreloadAwt = NULL; 1.1384 + 1.1385 +/* 1.1386 + * Starts AWT preloading 1.1387 + */ 1.1388 +int AWTPreload(const char *funcName) 1.1389 +{ 1.1390 + int result = -1; 1.1391 + 1.1392 + // load AWT library once (if several preload function should be called) 1.1393 + if (hPreloadAwt == NULL) { 1.1394 + // awt.dll is not loaded yet 1.1395 + char libraryPath[MAXPATHLEN]; 1.1396 + int jrePathLen = 0; 1.1397 + HMODULE hJava = NULL; 1.1398 + HMODULE hVerify = NULL; 1.1399 + 1.1400 + while (1) { 1.1401 + // awt.dll depends on jvm.dll & java.dll; 1.1402 + // jvm.dll is already loaded, so we need only java.dll; 1.1403 + // java.dll depends on MSVCRT lib & verify.dll. 1.1404 + if (!GetJREPath(libraryPath, MAXPATHLEN)) { 1.1405 + break; 1.1406 + } 1.1407 + 1.1408 + // save path length 1.1409 + jrePathLen = strlen(libraryPath); 1.1410 + 1.1411 + // load msvcrt 1st 1.1412 + LoadMSVCRT(); 1.1413 + 1.1414 + // load verify.dll 1.1415 + strcat(libraryPath, "\\bin\\verify.dll"); 1.1416 + hVerify = LoadLibrary(libraryPath); 1.1417 + if (hVerify == NULL) { 1.1418 + break; 1.1419 + } 1.1420 + 1.1421 + // restore jrePath 1.1422 + libraryPath[jrePathLen] = 0; 1.1423 + // load java.dll 1.1424 + strcat(libraryPath, "\\bin\\" JAVA_DLL); 1.1425 + hJava = LoadLibrary(libraryPath); 1.1426 + if (hJava == NULL) { 1.1427 + break; 1.1428 + } 1.1429 + 1.1430 + // restore jrePath 1.1431 + libraryPath[jrePathLen] = 0; 1.1432 + // load awt.dll 1.1433 + strcat(libraryPath, "\\bin\\awt.dll"); 1.1434 + hPreloadAwt = LoadLibrary(libraryPath); 1.1435 + if (hPreloadAwt == NULL) { 1.1436 + break; 1.1437 + } 1.1438 + 1.1439 + // get "preloadStop" func ptr 1.1440 + fnPreloadStop = (FnPreloadStop *)GetProcAddress(hPreloadAwt, "preloadStop"); 1.1441 + 1.1442 + break; 1.1443 + } 1.1444 + } 1.1445 + 1.1446 + if (hPreloadAwt != NULL) { 1.1447 + FnPreloadStart *fnInit = (FnPreloadStart *)GetProcAddress(hPreloadAwt, funcName); 1.1448 + if (fnInit != NULL) { 1.1449 + // don't forget to stop preloading 1.1450 + awtPreloaded = 1; 1.1451 + 1.1452 + result = fnInit(); 1.1453 + } 1.1454 + } 1.1455 + 1.1456 + return result; 1.1457 +} 1.1458 + 1.1459 +/* 1.1460 + * Terminates AWT preloading 1.1461 + */ 1.1462 +void AWTPreloadStop() { 1.1463 + if (fnPreloadStop != NULL) { 1.1464 + fnPreloadStop(); 1.1465 + } 1.1466 +} 1.1467 + 1.1468 +#endif /* ENABLE_AWT_PRELOAD */