src/os/windows/launcher/java_md.c

changeset 2327
cb2d0a362639
child 2369
aa6e219afbf1
     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 */

mercurial