PageRenderTime 78ms CodeModel.GetById 3ms app.highlight 65ms RepoModel.GetById 1ms app.codeStats 0ms

/src/native/windows/run/run.c

https://bitbucket.org/LANJr4D/jitsi
C | 1643 lines | 1366 code | 185 blank | 92 comment | 251 complexity | 1ace895a4a990021c5b2b8cc158d11b7 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/*
   2 * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
   3 *
   4 * Distributable under LGPL license.
   5 * See terms of license at gnu.org.
   6 */
   7
   8#include "run.h"
   9
  10#include <ctype.h> /* isspace */
  11#include <jni.h>
  12#include <psapi.h> /* GetModuleFileNameEx */
  13#include <stdint.h>
  14#include <stdio.h>
  15#include <stdlib.h>
  16#include <string.h>
  17#include <tchar.h>
  18#include <tlhelp32.h> /* CreateToolhelp32Snapshot */
  19
  20#include "registry.h"
  21#include "../setup/nls.h"
  22
  23#define JAVA_MAIN_CLASS _T("net.java.sip.communicator.launcher.SIPCommunicator")
  24
  25/**
  26 * The pipe through which the launcher is to communicate with the crash handler.
  27 */
  28static HANDLE Run_channel = INVALID_HANDLE_VALUE;
  29
  30/**
  31 * The command line that the application has received as the <tt>cmdLine</tt>
  32 * function argument of its <tt>WinMain</tt> entry point and that is currently
  33 * unparsed i.e. the parts which have already been parsed are no longer present.
  34 */
  35static LPSTR Run_cmdLine = NULL;
  36
  37/**
  38 * The indicator which determines whether the crash handler is to launch the
  39 * application.
  40 */
  41static BOOL Run_launch = TRUE;
  42
  43static DWORD Run_addPath(LPCTSTR path);
  44static DWORD Run_callStaticVoidMain(JNIEnv *jniEnv, BOOL *searchForJava);
  45static int Run_displayMessageBoxFromString(DWORD textId, DWORD_PTR *textArgs, LPCTSTR caption, UINT type);
  46static DWORD Run_equalsParentProcessExecutableFilePath(LPCTSTR executableFilePath, BOOL *equals);
  47static DWORD Run_getExecutableFilePath(LPTSTR *executableFilePath);
  48static DWORD Run_getJavaExeCommandLine(LPCTSTR javaExe, LPTSTR *commandLine);
  49static LPTSTR Run_getJavaLibraryPath();
  50static LONG Run_getJavaPathsFromRegKey(HKEY key, LPTSTR *runtimeLib, LPTSTR *javaHome);
  51static DWORD Run_getJavaVMOptionStrings(size_t head, TCHAR separator, size_t tail, LPTSTR *optionStrings, jint *optionStringCount);
  52static LPTSTR Run_getLockFilePath();
  53static DWORD Run_getParentProcessId(DWORD *ppid);
  54static DWORD Run_handleLauncherExitCode(DWORD exitCode, LPCTSTR lockFilePath, LPCTSTR executableFilePath);
  55static BOOL Run_isDirectory(LPCTSTR fileName);
  56static BOOL Run_isFile(LPCTSTR fileName);
  57static DWORD Run_openProcessAndResumeThread(DWORD processId, DWORD threadId, HANDLE *process);
  58static DWORD Run_runAsCrashHandler(LPCTSTR executableFilePath, LPSTR cmdLine);
  59static DWORD Run_runAsCrashHandlerWithPipe(LPCTSTR executableFilePath, LPSTR cmdLine, HANDLE *readPipe, HANDLE *writePipe);
  60static DWORD Run_runAsLauncher(LPCTSTR executableFilePath, LPSTR cmdLine);
  61static DWORD Run_runJava(LPCTSTR executableFilePath, LPSTR cmdLine);
  62static DWORD Run_runJavaExe(LPCTSTR javaExe, BOOL searchPath, BOOL *searchForJava);
  63static DWORD Run_runJavaFromEnvVar(LPCTSTR envVar, BOOL *searchForJava);
  64static DWORD Run_runJavaFromJavaHome(LPCTSTR javaHome, BOOL searchForRuntimeLib, BOOL *searchForJava);
  65static DWORD Run_runJavaFromRegKey(HKEY key, BOOL *searchForJava);
  66static DWORD Run_runJavaFromRuntimeLib(LPCTSTR runtimeLib, LPCTSTR javaHome, BOOL *searchForJava);
  67static LPSTR Run_skipWhitespace(LPSTR str);
  68
  69static DWORD
  70Run_addPath(LPCTSTR path)
  71{
  72    LPCTSTR envVarName = _T("PATH");
  73    TCHAR envVar[4096];
  74    DWORD envVarCapacity = sizeof(envVar) / sizeof(TCHAR);
  75    DWORD envVarLength
  76        = GetEnvironmentVariable(envVarName, envVar, envVarCapacity);
  77    DWORD error;
  78
  79    if (envVarLength)
  80    {
  81        if (envVarLength >= envVarCapacity)
  82            error = ERROR_NOT_ENOUGH_MEMORY;
  83        else
  84        {
  85            DWORD pathLength = _tcslen(path);
  86
  87            if (envVarLength + 1 + pathLength + 1 > envVarCapacity)
  88                error = ERROR_NOT_ENOUGH_MEMORY;
  89            else
  90            {
  91                LPTSTR str = envVar + envVarLength;
  92
  93                *str = _T(';');
  94                str++;
  95                _tcsncpy(str, path, pathLength);
  96                str += pathLength;
  97                *str = 0;
  98
  99                if (SetEnvironmentVariable(envVarName, envVar))
 100                    error = ERROR_SUCCESS;
 101                else
 102                    error = GetLastError();
 103            }
 104        }
 105    }
 106    else
 107        error = GetLastError();
 108    return error;
 109}
 110
 111static DWORD
 112Run_callStaticVoidMain(JNIEnv *jniEnv, BOOL *searchForJava)
 113{
 114    LPTSTR mainClassName;
 115    jclass mainClass;
 116    DWORD error;
 117
 118    mainClassName = _tcsdup(JAVA_MAIN_CLASS);
 119    if (mainClassName)
 120    {
 121        LPTSTR ch;
 122
 123        for (ch = mainClassName; *ch; ch++)
 124            if (_T('.') == *ch)
 125                *ch = _T('/');
 126        mainClass = (*jniEnv)->FindClass(jniEnv, mainClassName);
 127        free(mainClassName);
 128    }
 129    else
 130        mainClass = NULL;
 131    if (mainClass)
 132    {
 133        jmethodID mainMethodID
 134            = (*jniEnv)->GetStaticMethodID(
 135                jniEnv,
 136                mainClass,
 137                "main",
 138                "([Ljava/lang/String;)V");
 139
 140        if (mainMethodID)
 141        {
 142            jclass stringClass
 143                = (*jniEnv)->FindClass(jniEnv, "java/lang/String");
 144
 145            if (stringClass)
 146            {
 147                int argc = 0;
 148                LPWSTR *argv = NULL;
 149
 150                if (Run_cmdLine && strlen(Run_cmdLine))
 151                {
 152                    LPWSTR cmdLineW = NLS_str2wstr(Run_cmdLine);
 153
 154                    if (cmdLineW)
 155                    {
 156                        argv = CommandLineToArgvW(cmdLineW, &argc);
 157                        free(cmdLineW);
 158                        error = argv ? ERROR_SUCCESS : GetLastError();
 159                    }
 160                    else
 161                        error = ERROR_NOT_ENOUGH_MEMORY;
 162                }
 163                else
 164                    error = ERROR_SUCCESS;
 165                if (ERROR_SUCCESS == error)
 166                {
 167                    jobjectArray mainArgs
 168                        = (*jniEnv)->NewObjectArray(
 169                                jniEnv,
 170                                argc, stringClass, NULL);
 171
 172                    if (mainArgs)
 173                    {
 174                        int i;
 175
 176                        for (i = 0; (ERROR_SUCCESS == error) && (i < argc); i++)
 177                        {
 178                            LPWSTR arg = *(argv + i);
 179                            jstring mainArg
 180                                = (*jniEnv)->NewString(
 181                                        jniEnv,
 182                                        arg, wcslen(arg));
 183
 184                            if (mainArg)
 185                            {
 186                                (*jniEnv)->SetObjectArrayElement(
 187                                        jniEnv,
 188                                        mainArgs, i, mainArg);
 189                                if (JNI_TRUE
 190                                        == (*jniEnv)->ExceptionCheck(jniEnv))
 191                                    error = ERROR_FUNCTION_FAILED;
 192                            }
 193                            else
 194                                error = ERROR_NOT_ENOUGH_MEMORY;
 195                        }
 196                        if (argv)
 197                        {
 198                            LocalFree(argv);
 199                            argv = NULL;
 200                        }
 201
 202                        if (ERROR_SUCCESS == error)
 203                        {
 204                            *searchForJava = FALSE;
 205
 206                            /*
 207                             * The parent process will have to wait for and get
 208                             * the exit code of its child, not java.exe so it
 209                             * does not need telling who to wait for or get the
 210                             * exit code of.
 211                             */
 212                            if (INVALID_HANDLE_VALUE != Run_channel)
 213                            {
 214                                CloseHandle(Run_channel);
 215                                Run_channel = INVALID_HANDLE_VALUE;
 216                            }
 217
 218                            (*jniEnv)->CallStaticVoidMethod(
 219                                    jniEnv,
 220                                    mainClass, mainMethodID, mainArgs);
 221                        }
 222                    }
 223                    else
 224                        error = ERROR_NOT_ENOUGH_MEMORY;
 225
 226                    if (argv)
 227                        LocalFree(argv);
 228                }
 229            }
 230            else
 231                error = ERROR_CLASS_DOES_NOT_EXIST;
 232        }
 233        else
 234            error = ERROR_INVALID_FUNCTION;
 235    }
 236    else
 237        error = ERROR_CLASS_DOES_NOT_EXIST;
 238
 239    return error;
 240}
 241
 242static int
 243Run_displayMessageBoxFromString(
 244    DWORD textId, DWORD_PTR *textArgs,
 245    LPCTSTR caption,
 246    UINT type)
 247{
 248    TCHAR format[1024];
 249    int formatLength
 250        = LoadString(
 251                GetModuleHandle(NULL),
 252                textId,
 253                format, sizeof(format) / sizeof(TCHAR));
 254    int answer = 0;
 255
 256    if (formatLength > 0)
 257    {
 258        LPTSTR message = NULL;
 259        DWORD messageLength
 260            = FormatMessage(
 261                    FORMAT_MESSAGE_ALLOCATE_BUFFER
 262                        | FORMAT_MESSAGE_ARGUMENT_ARRAY
 263                        | FORMAT_MESSAGE_FROM_STRING,
 264                    format,
 265                    0,
 266                    LANG_USER_DEFAULT,
 267                    (LPTSTR) &message,
 268                    0,
 269                    (va_list *) textArgs);
 270
 271        if (messageLength)
 272        {
 273            answer
 274                = MessageBox(
 275                        NULL,
 276                        message,
 277                        caption,
 278                        type);
 279            LocalFree(message);
 280        }
 281    }
 282    return answer;
 283}
 284
 285static DWORD
 286Run_equalsParentProcessExecutableFilePath(
 287    LPCTSTR executableFilePath,
 288    BOOL *equals)
 289{
 290    DWORD ppid = 0;
 291    DWORD error = Run_getParentProcessId(&ppid);
 292
 293    if (ERROR_SUCCESS == error)
 294    {
 295        HANDLE parentProcess
 296            = OpenProcess(
 297                    PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
 298                    FALSE,
 299                    ppid);
 300
 301        if (parentProcess)
 302        {
 303            TCHAR parentProcessExecutableFilePath[MAX_PATH + 1];
 304            DWORD parentProcessExecutableFilePathLength
 305                = GetModuleFileNameEx(
 306                        parentProcess,
 307                        NULL,
 308                        parentProcessExecutableFilePath,
 309                        sizeof(parentProcessExecutableFilePath));
 310
 311            if (parentProcessExecutableFilePathLength)
 312            {
 313                *equals
 314                    = (_tcsnicmp(
 315                                parentProcessExecutableFilePath,
 316                                executableFilePath,
 317                                parentProcessExecutableFilePathLength)
 318                            == 0);
 319            }
 320            else
 321                error = GetLastError();
 322
 323            CloseHandle(parentProcess);
 324        }
 325        else
 326            error = GetLastError();
 327    }
 328    return error;
 329}
 330
 331static DWORD
 332Run_getExecutableFilePath(LPTSTR *executableFilePath)
 333{
 334    TCHAR str[MAX_PATH + 1];
 335    DWORD capacity = sizeof(str);
 336    DWORD length = GetModuleFileName(NULL, str, capacity);
 337    DWORD error;
 338
 339    if (length)
 340    {
 341        /* Make sure str is null terminated on Windows XP/2000. */
 342        if (length == capacity)
 343        {
 344            length--;
 345            str[length] = 0;
 346        }
 347
 348        *executableFilePath = (LPTSTR) malloc(sizeof(TCHAR) * (length + 1));
 349        if (*executableFilePath)
 350        {
 351            _tcsncpy(*executableFilePath, str, length);
 352            *((*executableFilePath) + length) = 0;
 353            error = ERROR_SUCCESS;
 354        }
 355        else
 356            error = ERROR_OUTOFMEMORY;
 357    }
 358    else
 359        error = GetLastError();
 360    return error;
 361}
 362
 363static DWORD
 364Run_getJavaExeCommandLine(LPCTSTR javaExe, LPTSTR *commandLine)
 365{
 366    LPCTSTR mainClass = JAVA_MAIN_CLASS;
 367
 368    size_t javaExeLength;
 369    size_t mainClassLength;
 370    size_t cmdLineLength;
 371    DWORD error;
 372
 373    javaExeLength = _tcslen(javaExe);
 374    mainClassLength = _tcslen(mainClass);
 375    if (Run_cmdLine)
 376    {
 377        cmdLineLength = _tcslen(Run_cmdLine);
 378        if (cmdLineLength)
 379            cmdLineLength++; /* ' ' */
 380    }
 381    else
 382        cmdLineLength = 0;
 383
 384    error
 385        = Run_getJavaVMOptionStrings(
 386            javaExeLength + 1 /* ' ' */,
 387            _T(' '),
 388            mainClassLength + cmdLineLength,
 389            commandLine,
 390            NULL);
 391    if (ERROR_SUCCESS == error)
 392    {
 393        LPTSTR str = *commandLine;
 394
 395        _tcsncpy(str, javaExe, javaExeLength);
 396        str += javaExeLength;
 397        *str = _T(' ');
 398        str++;
 399
 400        str += _tcslen(str);
 401
 402        _tcsncpy(str, mainClass, mainClassLength);
 403        str += mainClassLength;
 404        if (cmdLineLength)
 405        {
 406            *str = _T(' ');
 407            str++;
 408            cmdLineLength--;
 409            _tcsncpy(str, Run_cmdLine, cmdLineLength);
 410            str += cmdLineLength;
 411        }
 412        *str = 0;
 413    }
 414
 415    return error;
 416}
 417
 418static LPTSTR
 419Run_getJavaLibraryPath()
 420{
 421    LPCTSTR relativeJavaLibraryPath = _T("native");
 422    TCHAR javaLibraryPath[MAX_PATH + 1];
 423    DWORD javaLibraryPathCapacity
 424        = sizeof(javaLibraryPath) / sizeof(TCHAR);
 425    DWORD javaLibraryPathLength
 426        = GetFullPathName(
 427                relativeJavaLibraryPath,
 428                javaLibraryPathCapacity, javaLibraryPath,
 429                NULL);
 430    LPCTSTR dup;
 431
 432    if (javaLibraryPathLength
 433            && (javaLibraryPathLength < javaLibraryPathCapacity))
 434    {
 435        LPTSTR str = javaLibraryPath;
 436
 437        str += javaLibraryPathLength;
 438        *str = 0;
 439
 440        dup = javaLibraryPath;
 441    }
 442    else
 443        dup = relativeJavaLibraryPath;
 444    return _tcsdup(dup);
 445}
 446
 447static LONG
 448Run_getJavaPathsFromRegKey(HKEY key, LPTSTR *runtimeLib, LPTSTR *javaHome)
 449{
 450    HKEY jreKey = 0;
 451    LONG error
 452        = RegOpenKeyEx(
 453                key,
 454                _T("Software\\JavaSoft\\Java Runtime Environment"),
 455                0,
 456                KEY_QUERY_VALUE,
 457                &jreKey);
 458
 459    if (ERROR_SUCCESS == error)
 460    {
 461        LPTSTR currentVersion = NULL;
 462
 463        error
 464            = Run_getRegSzValue(jreKey, _T("CurrentVersion"), &currentVersion);
 465        if (ERROR_SUCCESS == error)
 466        {
 467            HKEY currentVersionKey = 0;
 468
 469            error
 470                = RegOpenKeyEx(
 471                        jreKey,
 472                        currentVersion,
 473                        0,
 474                        KEY_QUERY_VALUE,
 475                        &currentVersionKey);
 476            free(currentVersion);
 477            if (ERROR_SUCCESS == error)
 478            {
 479                if (ERROR_SUCCESS
 480                        != Run_getRegSzValue(
 481                                currentVersionKey,
 482                                _T("RuntimeLib"),
 483                                runtimeLib))
 484                    *runtimeLib = NULL;
 485                if (ERROR_SUCCESS
 486                        != Run_getRegSzValue(
 487                                currentVersionKey,
 488                                _T("JavaHome"),
 489                                javaHome))
 490                    *javaHome = NULL;
 491                RegCloseKey(currentVersionKey);
 492            }
 493        }
 494        RegCloseKey(jreKey);
 495    }
 496    return error;
 497}
 498
 499static DWORD
 500Run_getJavaVMOptionStrings
 501    (size_t head, TCHAR separator, size_t tail,
 502        LPTSTR *optionStrings, jint *optionStringCount)
 503{
 504    LPTSTR javaLibraryPath = Run_getJavaLibraryPath();
 505    jint _optionStringCount = 0;
 506    DWORD error;
 507
 508    if (javaLibraryPath)
 509    {
 510        LPCTSTR classpath[]
 511            = {
 512                _T("lib\\felix.jar"),
 513                _T("lib\\jdic-all.jar"),
 514                _T("lib\\jdic_stub.jar"),
 515                _T("lib\\bcprovider.jar"),
 516                _T("sc-bundles\\sc-launcher.jar"),
 517                _T("sc-bundles\\util.jar"),
 518                NULL
 519            };
 520        LPCTSTR properties[]
 521            = {
 522                _T("felix.config.properties"),
 523                _T("file:./lib/felix.client.run.properties"),
 524                _T("java.util.logging.config.file"),
 525                _T("lib/logging.properties"),
 526                _T("java.library.path"),
 527                javaLibraryPath,
 528                _T("jna.library.path"),
 529                javaLibraryPath,
 530                _T("net.java.sip.communicator.SC_HOME_DIR_NAME"),
 531                PRODUCTNAME,
 532                NULL
 533            };
 534
 535        size_t classpathLength;
 536        size_t propertiesLength;
 537        BOOL quote = separator;
 538
 539        {
 540            LPCTSTR cp;
 541            size_t i = 0;
 542
 543            classpathLength = 0;
 544            while ((cp = classpath[i++]))
 545                classpathLength += (_tcslen(cp) + 1 /* ';' */);
 546            if (classpathLength)
 547                classpathLength += 18 /* "-Djava.class.path=" */;
 548        }
 549        {
 550            LPCTSTR property;
 551            size_t i = 0;
 552
 553            propertiesLength = 0;
 554            while ((property = properties[i++]))
 555            {
 556                propertiesLength
 557                    += (2 /* "\"-D" */
 558                        + _tcslen(property)
 559                        + 1 /* '=' */
 560                        + _tcslen(properties[i++])
 561                        + 1 /* ' ' */);
 562                if (quote)
 563                    propertiesLength += 2;
 564            }
 565        }
 566
 567        *optionStrings
 568            = (LPTSTR)
 569                malloc(
 570                    sizeof(TCHAR)
 571                        * (head
 572                            + classpathLength
 573                            + propertiesLength
 574                            + 1 /* 0 */
 575                            + tail));
 576        if (*optionStrings)
 577        {
 578            LPTSTR str = (*optionStrings) + head;
 579
 580            if (classpathLength)
 581            {
 582                LPCTSTR cp;
 583                size_t i = 0;
 584
 585                _tcscpy(str, _T("-Djava.class.path="));
 586                str += 18;
 587                while ((cp = classpath[i++]))
 588                {
 589                    size_t length = _tcslen(cp);
 590
 591                    _tcsncpy(str, cp, length);
 592                    str += length;
 593                    *str = _T(';');
 594                    str++;
 595                }
 596                str--; /* Drop the last ';'. */
 597                *str = separator;
 598                str++;
 599
 600                _optionStringCount++;
 601            }
 602            if (propertiesLength)
 603            {
 604                LPCTSTR property;
 605                size_t i = 0;
 606
 607                while ((property = properties[i++]))
 608                {
 609                    size_t length;
 610                    LPCTSTR value;
 611
 612                    if (quote)
 613                        *str++ = _T('"');
 614                    _tcscpy(str, _T("-D"));
 615                    str += 2;
 616                    length = _tcslen(property);
 617                    _tcsncpy(str, property, length);
 618                    str += length;
 619                    *str++ = _T('=');
 620
 621                    value = properties[i++];
 622                    length = _tcslen(value);
 623                    _tcsncpy(str, value, length);
 624                    str += length;
 625                    if (quote)
 626                        *str++ = _T('"');
 627                    *str++ = separator;
 628
 629                    _optionStringCount++;
 630                }
 631            }
 632            *str = 0;
 633
 634            if (optionStringCount)
 635                *optionStringCount = _optionStringCount;
 636            error = ERROR_SUCCESS;
 637        }
 638        else
 639            error = ERROR_OUTOFMEMORY;
 640
 641        free(javaLibraryPath);
 642    }
 643    else
 644        error = ERROR_OUTOFMEMORY;
 645
 646    return error;
 647}
 648
 649static LPTSTR
 650Run_getLockFilePath()
 651{
 652    TCHAR appData[MAX_PATH + 1];
 653    DWORD appDataCapacity = sizeof(appData) / sizeof(TCHAR);
 654    DWORD appDataLength
 655        = GetEnvironmentVariable(
 656                _T("APPDATA"),
 657                appData, appDataCapacity);
 658    LPTSTR lockFilePath = NULL;
 659
 660    if (appDataLength && (appDataLength < appDataCapacity))
 661    {
 662        LPCTSTR productName = PRODUCTNAME;
 663        size_t productNameLength = _tcslen(productName);
 664        LPCTSTR lockFileName = _T(".lock");
 665        size_t lockFileNameLength = _tcslen(lockFileName);
 666
 667        lockFilePath
 668            = (LPTSTR)
 669                malloc(
 670                        sizeof(TCHAR)
 671                            * (appDataLength
 672                                    + 1
 673                                    + productNameLength
 674                                    + 1
 675                                    + lockFileNameLength
 676                                    + 1));
 677        if (lockFilePath)
 678        {
 679            LPTSTR str = lockFilePath;
 680
 681            _tcsncpy(str, appData, appDataLength);
 682            str += appDataLength;
 683            *str = _T('\\');
 684            str++;
 685            _tcsncpy(str, productName, productNameLength);
 686            str += productNameLength;
 687            *str = _T('\\');
 688            str++;
 689            _tcsncpy(str, lockFileName, lockFileNameLength);
 690            str += lockFileNameLength;
 691            *str = 0;
 692        }
 693    }
 694    return lockFilePath;
 695}
 696
 697static DWORD
 698Run_getParentProcessId(DWORD *ppid)
 699{
 700    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
 701    DWORD error;
 702
 703    if (INVALID_HANDLE_VALUE == snapshot)
 704        error = GetLastError();
 705    else
 706    {
 707        PROCESSENTRY32 pe32;
 708
 709        pe32.dwSize = sizeof(PROCESSENTRY32);
 710        if (Process32First(snapshot, &pe32))
 711        {
 712            DWORD pid = GetCurrentProcessId();
 713
 714            error = ERROR_FILE_NOT_FOUND;
 715            do
 716            {
 717                if (pe32.th32ProcessID == pid)
 718                {
 719                    error = ERROR_SUCCESS;
 720                    *ppid = pe32.th32ParentProcessID;
 721                    break;
 722                }
 723
 724                if (!Process32Next(snapshot, &pe32))
 725                {
 726                    error = GetLastError();
 727                    break;
 728                }
 729            }
 730            while (1);
 731        }
 732        else
 733            error = GetLastError();
 734
 735        CloseHandle(snapshot);
 736    }
 737    return error;
 738}
 739
 740static DWORD
 741Run_handleLauncherExitCode(
 742    DWORD exitCode, LPCTSTR lockFilePath,
 743    LPCTSTR executableFilePath)
 744{
 745    DWORD error = ERROR_SUCCESS;
 746
 747    if (Run_isFile(lockFilePath))
 748    {
 749        DWORD_PTR arguments[] = { (DWORD_PTR) PRODUCTNAME };
 750        int answer
 751            = Run_displayMessageBoxFromString(
 752                    IDS_CRASHANDRELAUNCH, arguments,
 753                    executableFilePath,
 754                    MB_ICONEXCLAMATION | MB_YESNO);
 755
 756        if (answer)
 757        {
 758            if (IDYES == answer)
 759                Run_launch = TRUE;
 760
 761            /*
 762             * We believe the lockFilePath is related to the reported crash
 763             * instance so we have to remove it after notifying the user in
 764             * order to not take it into account upon a possible next launch.
 765             */
 766            DeleteFile(lockFilePath);
 767        }
 768        else
 769            error = GetLastError();
 770    }
 771    return error;
 772}
 773
 774static BOOL
 775Run_isDirectory(LPCTSTR fileName)
 776{
 777    DWORD fileAttributes = GetFileAttributes(fileName);
 778
 779    return
 780        (INVALID_FILE_ATTRIBUTES != fileAttributes)
 781            && (0 != (FILE_ATTRIBUTE_DIRECTORY & fileAttributes));
 782}
 783
 784static BOOL
 785Run_isFile(LPCTSTR fileName)
 786{
 787    DWORD fileAttributes = GetFileAttributes(fileName);
 788
 789    return
 790        (INVALID_FILE_ATTRIBUTES != fileAttributes)
 791            && (0 == (FILE_ATTRIBUTE_DIRECTORY & fileAttributes));
 792}
 793
 794static DWORD
 795Run_openProcessAndResumeThread(DWORD processId, DWORD threadId, HANDLE *process)
 796{
 797    HANDLE p
 798        = OpenProcess(
 799                PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
 800                FALSE,
 801                processId);
 802    DWORD error;
 803
 804    if (p)
 805    {
 806        HANDLE t = OpenThread(THREAD_SUSPEND_RESUME, FALSE, threadId);
 807
 808        if (t)
 809        {
 810            DWORD prevSuspendCount = ResumeThread(t);
 811
 812            if (1 == prevSuspendCount)
 813            {
 814                *process = p;
 815                error = ERROR_SUCCESS;
 816            }
 817            else
 818                error = ERROR_NOT_FOUND;
 819            CloseHandle(t);
 820        }
 821        else
 822            error = GetLastError();
 823        if (ERROR_SUCCESS != error)
 824            CloseHandle(p);
 825    }
 826    else
 827        error = GetLastError();
 828    return error;
 829}
 830
 831static DWORD
 832Run_runAsCrashHandler(LPCTSTR executableFilePath, LPSTR cmdLine)
 833{
 834    SECURITY_ATTRIBUTES pipeAttributes;
 835    HANDLE readPipe = INVALID_HANDLE_VALUE;
 836    HANDLE writePipe = INVALID_HANDLE_VALUE;
 837    DWORD error;
 838
 839    ZeroMemory(&pipeAttributes, sizeof(pipeAttributes));
 840    pipeAttributes.nLength = sizeof(pipeAttributes);
 841    pipeAttributes.bInheritHandle = TRUE;
 842    if (CreatePipe(&readPipe, &writePipe, &pipeAttributes, 0))
 843    {
 844        /*
 845         * Do not let the child process inherit the readPipe because it does not
 846         * need it.
 847         */
 848        HANDLE currentProcess = GetCurrentProcess();
 849        HANDLE readPipeDuplicate = INVALID_HANDLE_VALUE;
 850
 851        if (DuplicateHandle(
 852                currentProcess, readPipe,
 853                currentProcess, &readPipeDuplicate,
 854                0,
 855                FALSE,
 856                DUPLICATE_SAME_ACCESS))
 857        {
 858            CloseHandle(readPipe);
 859            readPipe = readPipeDuplicate;
 860
 861            error
 862                = Run_runAsCrashHandlerWithPipe(
 863                        executableFilePath, cmdLine,
 864                        &readPipe, &writePipe);
 865        }
 866        else
 867            error = GetLastError();
 868
 869        if (INVALID_HANDLE_VALUE != readPipe)
 870            CloseHandle(readPipe);
 871        if (INVALID_HANDLE_VALUE != writePipe)
 872            CloseHandle(writePipe);
 873    }
 874    else
 875        error = GetLastError();
 876    return error;
 877}
 878
 879static DWORD
 880Run_runAsCrashHandlerWithPipe(
 881    LPCTSTR executableFilePath, LPSTR cmdLine,
 882    HANDLE *readPipe, HANDLE *writePipe)
 883{
 884    LPCTSTR commandLineFormat = _T("run.exe --channel=%d %s");
 885    int commandLineLength = 256 + _tcslen(cmdLine);
 886    LPTSTR commandLine
 887        = (LPTSTR) malloc(sizeof(TCHAR) * (commandLineLength + 1));
 888    DWORD error;
 889
 890    if (commandLine)
 891    {
 892        LPTSTR lockFilePath = Run_getLockFilePath();
 893        DWORD exitCode = 0;
 894
 895        commandLineLength
 896            = _sntprintf(
 897                    commandLine,
 898                    commandLineLength,
 899                    commandLineFormat,
 900                    (int) (intptr_t) (*writePipe),
 901                    cmdLine);
 902        if (commandLineLength < 0)
 903        {
 904            free(commandLine);
 905            commandLine = NULL;
 906            error = ERROR_NOT_ENOUGH_MEMORY;
 907        }
 908        else
 909        {
 910            *(commandLine + commandLineLength) = 0;
 911            error = ERROR_SUCCESS;
 912        }
 913
 914        if (ERROR_SUCCESS == error)
 915        {
 916            BOOL waitForChildProcess
 917                = !(lockFilePath && Run_isFile(lockFilePath));
 918            STARTUPINFO si;
 919            PROCESS_INFORMATION pi;
 920
 921            ZeroMemory(&si, sizeof(si));
 922            si.cb = sizeof(si);
 923            if (CreateProcess(
 924                    executableFilePath,
 925                    commandLine,
 926                    NULL,
 927                    NULL,
 928                    TRUE,
 929                    CREATE_NO_WINDOW,
 930                    NULL,
 931                    NULL,
 932                    &si,
 933                    &pi))
 934            {
 935                HANDLE childProcessToWaitFor = NULL;
 936                DWORD event;
 937
 938                /* We didn't really want to hold on to the thread. */
 939                CloseHandle(pi.hThread);
 940
 941                /*
 942                 * The command line of the child process is no longer necessary.
 943                 */
 944                free(commandLine);
 945                commandLine = NULL;
 946
 947                /*
 948                 * The child process has inherited the writePipe so close it in
 949                 * the current process in order to let it know that it is only
 950                 * waiting for the child process.
 951                 */
 952                CloseHandle(*writePipe);
 953                *writePipe = INVALID_HANDLE_VALUE;
 954
 955                /*
 956                 * Wait for the child process to tell the current process if it
 957                 * is to wait for another child process in order to get the exit
 958                 * code from it.
 959                 */
 960                if (INVALID_HANDLE_VALUE != *readPipe)
 961                {
 962                    DWORD childToWaitFor[2];
 963                    DWORD numberOfBytesRead = 0;
 964
 965                    if (ReadFile(
 966                                *readPipe,
 967                                childToWaitFor,
 968                                sizeof(childToWaitFor),
 969                                &numberOfBytesRead,
 970                                NULL)
 971                            && (numberOfBytesRead
 972                                    == sizeof(childToWaitFor))
 973                            && childToWaitFor[0]
 974                            && childToWaitFor[1])
 975                    {
 976                        error
 977                            = Run_openProcessAndResumeThread(
 978                                    childToWaitFor[0],
 979                                    childToWaitFor[1],
 980                                    &childProcessToWaitFor);
 981                    }
 982                    CloseHandle(*readPipe);
 983                    *readPipe = INVALID_HANDLE_VALUE;
 984                }
 985                if (childProcessToWaitFor)
 986                {
 987                    /*
 988                     * We'll have to wait for another process, not the one that
 989                     * we have just created ourselves.
 990                     */
 991                    CloseHandle(pi.hProcess);
 992                }
 993                else
 994                    childProcessToWaitFor = pi.hProcess;
 995
 996                if (waitForChildProcess)
 997                {
 998                    error = ERROR_SUCCESS;
 999                    do
1000                    {
1001                        event
1002                            = WaitForSingleObject(
1003                                    childProcessToWaitFor,
1004                                    INFINITE);
1005                        if (WAIT_FAILED == event)
1006                        {
1007                            error = GetLastError();
1008                            break;
1009                        }
1010                    }
1011                    while (WAIT_TIMEOUT == event);
1012
1013                    if ((ERROR_SUCCESS == error)
1014                            && !GetExitCodeProcess(
1015                                    childProcessToWaitFor,
1016                                    &exitCode))
1017                        error = GetLastError();
1018                }
1019
1020                CloseHandle(childProcessToWaitFor);
1021            }
1022            else
1023                error = GetLastError();
1024        }
1025
1026        if (commandLine)
1027            free(commandLine);
1028
1029        if (lockFilePath)
1030        {
1031            /*
1032             * Notify the user if the application has crashed and ask whether it
1033             * is to be relaunched.
1034             */
1035            if ((ERROR_SUCCESS == error) && exitCode)
1036            {
1037                error
1038                    = Run_handleLauncherExitCode(
1039                            exitCode, lockFilePath,
1040                            executableFilePath);
1041            }
1042            free(lockFilePath);
1043        }
1044    }
1045    else
1046        error = ERROR_OUTOFMEMORY;
1047    return error;
1048}
1049
1050static DWORD
1051Run_runAsLauncher(LPCTSTR executableFilePath, LPSTR cmdLine)
1052{
1053    LPSTR commandLine;
1054    DWORD error = ERROR_SUCCESS;
1055
1056    /* Parse the command line. */
1057    if (cmdLine)
1058    {
1059        size_t commandLineLength;
1060        LPCSTR channelArg = "--channel=";
1061        size_t channelArgLength = strlen(channelArg);
1062
1063        commandLine = Run_skipWhitespace(cmdLine);
1064        commandLineLength = strlen(commandLine);
1065
1066        /* Get the value of the "--channel=" command-line argument. */
1067        if ((commandLineLength > channelArgLength)
1068                && (strnicmp(commandLine, channelArg, channelArgLength) == 0))
1069        {
1070            commandLine += channelArgLength;
1071            if (!isspace(*commandLine))
1072            {
1073                HANDLE channel = (HANDLE) (intptr_t) atoi(commandLine);
1074                DWORD flags;
1075                char ch;
1076
1077                if (channel && GetHandleInformation(channel, &flags))
1078                {
1079                    /*
1080                     * Make sure channel will not be inherited by any child
1081                     * process.
1082                     */
1083                    HANDLE currentProcess = GetCurrentProcess();
1084                    HANDLE channelDuplicate = INVALID_HANDLE_VALUE;
1085
1086                    if (DuplicateHandle(
1087                            currentProcess, channel,
1088                            currentProcess, &channelDuplicate,
1089                            0,
1090                            FALSE,
1091                            DUPLICATE_SAME_ACCESS))
1092                        Run_channel = channelDuplicate;
1093                    CloseHandle(channel);
1094                }
1095
1096                /*
1097                 * Skip the value of the channelArg and the whitespace after it.
1098                 */
1099                while ((ch = *commandLine) && !isspace(ch))
1100                    commandLine++;
1101                commandLine = Run_skipWhitespace(commandLine);
1102            }
1103        }
1104    }
1105    else
1106        commandLine = cmdLine;
1107
1108    /* Run the Java process in the directory of the executable file. */
1109    if (_tcslen(executableFilePath) <= MAX_PATH)
1110    {
1111        TCHAR path[MAX_PATH];
1112        DWORD pathCapacity = sizeof(path) / sizeof(TCHAR);
1113        LPTSTR filePart = NULL;
1114        DWORD pathLength
1115            = GetFullPathName(
1116                    executableFilePath,
1117                    pathCapacity, path, &filePart);
1118
1119        if (!pathLength)
1120            error = GetLastError();
1121        else if (pathLength >= pathCapacity)
1122            error = ERROR_NOT_ENOUGH_MEMORY;
1123        else
1124        {
1125            /*
1126             * Strip the filePart because only the directory of the executable
1127             * file is necessary.
1128             */
1129            if (filePart && *filePart)
1130                *filePart = 0;
1131            if (!SetCurrentDirectory(path))
1132                error = GetLastError();
1133        }
1134    }
1135
1136    error = Run_runJava(executableFilePath, commandLine);
1137    return error;
1138}
1139
1140static DWORD
1141Run_runJava(LPCTSTR executableFilePath, LPSTR cmdLine)
1142{
1143    DWORD cdLength;
1144    DWORD error = ERROR_CALL_NOT_IMPLEMENTED;
1145    BOOL searchForJava = TRUE;
1146
1147    Run_cmdLine = cmdLine;
1148
1149    /* Try to use the private Java distributed with the application. */
1150    if ((cdLength = GetCurrentDirectory(0, NULL)))
1151    {
1152        LPTSTR cd = (LPTSTR) malloc(sizeof(TCHAR) * cdLength);
1153
1154        if (cd)
1155        {
1156            cdLength = GetCurrentDirectory(cdLength, cd);
1157            if (cdLength)
1158            {
1159                if ((ERROR_SUCCESS != error) || searchForJava)
1160                    error = Run_runJavaFromJavaHome(cd, TRUE, &searchForJava);
1161            }
1162            else
1163                error = GetLastError();
1164            free(cd);
1165        }
1166        else
1167            error = ERROR_OUTOFMEMORY;
1168    }
1169    else
1170        error = GetLastError();
1171
1172    /* Try to locate Java through the well-known enviroment variables. */
1173    if ((ERROR_SUCCESS != error) || searchForJava)
1174        error = Run_runJavaFromEnvVar(_T("JAVA_HOME"), &searchForJava);
1175    if ((ERROR_SUCCESS != error) || searchForJava)
1176        error = Run_runJavaFromEnvVar(_T("JRE_HOME"), &searchForJava);
1177    if ((ERROR_SUCCESS != error) || searchForJava)
1178        error = Run_runJavaFromEnvVar(_T("JDK_HOME"), &searchForJava);
1179
1180    /* Try to locate Java through the Windows registry. */
1181    if ((ERROR_SUCCESS != error) || searchForJava)
1182        error = Run_runJavaFromRegKey(HKEY_CURRENT_USER, &searchForJava);
1183    if ((ERROR_SUCCESS != error) || searchForJava)
1184        error = Run_runJavaFromRegKey(HKEY_LOCAL_MACHINE, &searchForJava);
1185
1186    /* Default to the Java in the PATH. */
1187    if ((ERROR_SUCCESS != error) || searchForJava)
1188        error = Run_runJavaExe(_T("javaw.exe"), TRUE, &searchForJava);
1189    if ((ERROR_SUCCESS != error) || searchForJava)
1190        error = Run_runJavaExe(_T("java.exe"), TRUE, &searchForJava);
1191
1192    /* Notify the user that Java could not be found. */
1193    if ((ERROR_SUCCESS != error) || searchForJava)
1194    {
1195        DWORD_PTR arguments[] = { (DWORD_PTR) PRODUCTNAME };
1196
1197        if (Run_displayMessageBoxFromString(
1198                IDS_JAVANOTFOUND, arguments,
1199                executableFilePath,
1200                MB_ICONSTOP | MB_OK))
1201        {
1202            /*
1203             * We have failed to locate Java but we've just notified the user
1204             * about this fact so the execution is according to plan.
1205             */
1206            error = ERROR_SUCCESS;
1207        }
1208        else
1209            error = GetLastError();
1210    }
1211
1212    return error;
1213}
1214
1215static DWORD
1216Run_runJavaExe(LPCTSTR javaExe, BOOL searchPath, BOOL *searchForJava)
1217{
1218    DWORD error;
1219
1220    if (searchPath || Run_isFile(javaExe))
1221    {
1222        LPCTSTR applicationName;
1223        LPCTSTR fileName;
1224        LPTSTR commandLine = NULL;
1225
1226        if (searchPath)
1227        {
1228            applicationName = NULL;
1229            fileName = javaExe;
1230        }
1231        else
1232        {
1233            applicationName = javaExe;
1234            fileName = _T("java.exe");
1235        }
1236        error = Run_getJavaExeCommandLine(fileName, &commandLine);
1237
1238        if (ERROR_SUCCESS == error)
1239        {
1240            DWORD creationFlags;
1241            STARTUPINFO si;
1242            PROCESS_INFORMATION pi;
1243
1244            creationFlags = CREATE_NO_WINDOW;
1245            if (INVALID_HANDLE_VALUE != Run_channel)
1246                creationFlags |= CREATE_SUSPENDED;
1247            ZeroMemory(&si, sizeof(si));
1248            si.cb = sizeof(si);
1249            if (CreateProcess(
1250                    applicationName,
1251                    commandLine,
1252                    NULL,
1253                    NULL,
1254                    TRUE,
1255                    creationFlags,
1256                    NULL,
1257                    NULL,
1258                    &si,
1259                    &pi))
1260            {
1261                *searchForJava = FALSE;
1262
1263                /*
1264                 * Tell the parent process it will have to wait for java.exe and
1265                 * get its exit code.
1266                 */
1267                if (INVALID_HANDLE_VALUE != Run_channel)
1268                {
1269                    DWORD processAndThreadIds[2];
1270                    DWORD numberOfBytesWritten;
1271
1272                    processAndThreadIds[0] = pi.dwProcessId;
1273                    processAndThreadIds[1] = pi.dwThreadId;
1274                    WriteFile(
1275                            Run_channel,
1276                            processAndThreadIds,
1277                            sizeof(processAndThreadIds),
1278                            &numberOfBytesWritten,
1279                            NULL);
1280                    FlushFileBuffers(Run_channel);
1281                    CloseHandle(Run_channel);
1282                    Run_channel = INVALID_HANDLE_VALUE;
1283                }
1284
1285                CloseHandle(pi.hProcess);
1286                CloseHandle(pi.hThread);
1287            }
1288            else
1289                error = GetLastError();
1290        }
1291
1292        if (commandLine)
1293            free(commandLine);
1294    }
1295    else
1296        error = ERROR_CALL_NOT_IMPLEMENTED;
1297    return error;
1298}
1299
1300static DWORD
1301Run_runJavaFromEnvVar(LPCTSTR envVar, BOOL *searchForJava)
1302{
1303    TCHAR envVarValue[MAX_PATH + 1];
1304    DWORD envVarValueLength
1305        = GetEnvironmentVariable(envVar, envVarValue, sizeof(envVarValue));
1306    DWORD error;
1307
1308    if (envVarValueLength)
1309    {
1310        if (envVarValueLength >= sizeof(envVarValue))
1311            error = ERROR_NOT_ENOUGH_MEMORY;
1312        else
1313            error = Run_runJavaFromJavaHome(envVarValue, TRUE, searchForJava);
1314    }
1315    else
1316        error = GetLastError();
1317    return error;
1318}
1319
1320static DWORD
1321Run_runJavaFromJavaHome(
1322    LPCTSTR javaHome, BOOL searchForRuntimeLib,
1323    BOOL *searchForJava)
1324{
1325    DWORD error;
1326
1327    if (Run_isDirectory(javaHome))
1328    {
1329        size_t javaHomeLength = _tcslen(javaHome);
1330        LPTSTR path
1331            = (LPTSTR) malloc(sizeof(TCHAR) * (javaHomeLength + 19 + 1));
1332
1333        if (path)
1334        {
1335            if (javaHomeLength >= 1)
1336            {
1337                TCHAR *ch = (TCHAR *) (javaHome + (javaHomeLength - 1));
1338
1339                if ((_T('\\') == *ch) || (_T('/') == *ch))
1340                {
1341                    *ch = 0;
1342                    javaHomeLength--;
1343                }
1344            }
1345
1346            _tcscpy(path, javaHome);
1347            error = ERROR_CALL_NOT_IMPLEMENTED;
1348
1349            if (searchForRuntimeLib)
1350            {
1351                _tcscpy(path + javaHomeLength, _T("\\bin\\client\\jvm.dll"));
1352                error
1353                    = Run_runJavaFromRuntimeLib(path, javaHome, searchForJava);
1354
1355                if ((ERROR_SUCCESS != error) || *searchForJava)
1356                {
1357                    _tcscpy(
1358                            path + javaHomeLength,
1359                            _T("\\bin\\server\\jvm.dll"));
1360                    error
1361                        = Run_runJavaFromRuntimeLib(
1362                            path,
1363                            javaHome,
1364                            searchForJava);
1365                }
1366            }
1367
1368            if ((ERROR_SUCCESS != error) || *searchForJava)
1369            {
1370                if ((javaHomeLength >= 4)
1371                        && (_tcsnicmp(
1372                                    javaHome + javaHomeLength - 4,
1373                                    _T("\\jre"),
1374                                    4)
1375                                != 0))
1376                {
1377                    _tcscpy(path + javaHomeLength, _T("\\jre"));
1378                    error
1379                        = Run_runJavaFromJavaHome(
1380                                path, searchForRuntimeLib,
1381                                searchForJava);
1382                }
1383
1384                if ((ERROR_SUCCESS != error) || *searchForJava)
1385                {
1386                    _tcscpy(path + javaHomeLength, _T("\\bin\\javaw.exe"));
1387                    error = Run_runJavaExe(path, FALSE, searchForJava);
1388
1389                    if ((ERROR_SUCCESS != error) || *searchForJava)
1390                    {
1391                        _tcscpy(path + javaHomeLength, _T("\\bin\\java.exe"));
1392                        error = Run_runJavaExe(path, FALSE, searchForJava);
1393                    }
1394                }
1395            }
1396
1397            free(path);
1398        }
1399        else
1400            error = ERROR_OUTOFMEMORY;
1401    }
1402    else
1403        error = ERROR_FILE_NOT_FOUND;
1404    return error;
1405}
1406
1407static DWORD
1408Run_runJavaFromRegKey(HKEY key, BOOL *searchForJava)
1409{
1410    DWORD error;
1411    LPTSTR runtimeLib = NULL;
1412    LPTSTR javaHome = NULL;
1413
1414    error = Run_getJavaPathsFromRegKey(key, &runtimeLib, &javaHome);
1415    if (ERROR_SUCCESS == error)
1416    {
1417        if (runtimeLib)
1418        {
1419            error
1420                = Run_runJavaFromRuntimeLib(
1421                    runtimeLib,
1422                    javaHome,
1423                    searchForJava);
1424            free(runtimeLib);
1425        }
1426        if (javaHome)
1427        {
1428            if ((ERROR_SUCCESS != error) || *searchForJava)
1429            {
1430                error
1431                    = Run_runJavaFromJavaHome(
1432                            javaHome,
1433                            NULL == runtimeLib,
1434                            searchForJava);
1435            }
1436            free(javaHome);
1437        }
1438    }
1439    return error;
1440}
1441
1442static DWORD
1443Run_runJavaFromRuntimeLib
1444    (LPCTSTR runtimeLib, LPCTSTR javaHome, BOOL *searchForJava)
1445{
1446    HMODULE hRuntimeLib;
1447    DWORD error;
1448
1449    if (Run_isFile(runtimeLib))
1450    {
1451        /*
1452         * It turns out that the bin directory in javaHome may contain
1453         * dependencies of the runtimeLib so add it to the PATH. Well, it may
1454         * not be standard but it happens to our private JRE.
1455         */
1456        if (javaHome && Run_isDirectory(javaHome))
1457        {
1458            size_t javaHomeLength = _tcslen(javaHome);
1459            LPTSTR javaHomeBin;
1460
1461            /*
1462             * Drop the last file name separator if any because we will be
1463             * adding one later on.
1464             */
1465            while (javaHomeLength >= 1)
1466            {
1467                TCHAR ch = *(javaHome + (javaHomeLength - 1));
1468
1469                if ((_T('\\') == ch) || (_T('/') == ch))
1470                    javaHomeLength--;
1471                else
1472                    break;
1473            }
1474
1475            javaHomeBin
1476                = malloc(
1477                    sizeof(TCHAR) * (javaHomeLength + 4 /* "\\bin" */ + 1));
1478            if (javaHomeBin)
1479            {
1480                LPTSTR str = javaHomeBin;
1481
1482                _tcsncpy(str, javaHome, javaHomeLength);
1483                str += javaHomeLength;
1484                _tcsncpy(str, _T("\\bin"), 4);
1485                str += 4;
1486                *str = 0;
1487
1488                if (Run_isDirectory(javaHomeBin))
1489                    Run_addPath(javaHomeBin);
1490
1491                free(javaHomeBin);
1492            }
1493        }
1494
1495        hRuntimeLib = LoadLibrary(runtimeLib);
1496    }
1497    else
1498        hRuntimeLib = NULL;
1499
1500    if (hRuntimeLib)
1501    {
1502        typedef jint (JNICALL *JNICreateJavaVMFunc)(JavaVM **, void **, void *);
1503        JNICreateJavaVMFunc jniCreateJavaVM
1504            = (JNICreateJavaVMFunc)
1505                GetProcAddress(hRuntimeLib, "JNI_CreateJavaVM");
1506
1507        if (jniCreateJavaVM)
1508        {
1509            LPTSTR optionStrings = NULL;
1510            jint optionStringCount = 0;
1511
1512            error
1513                = Run_getJavaVMOptionStrings(
1514                    0, 0, 0,
1515                    &optionStrings, &optionStringCount);
1516            if (ERROR_SUCCESS == error)
1517            {
1518                JavaVMOption *options
1519                    = calloc(optionStringCount, sizeof(JavaVMOption));
1520
1521                if (options)
1522                {
1523                    jint i;
1524                    LPTSTR optionString;
1525                    JavaVMInitArgs javaVMInitArgs;
1526                    JavaVM *javaVM;
1527                    JNIEnv *jniEnv;
1528
1529                    for (i = 0, optionString = optionStrings;
1530                            i < optionStringCount;
1531                            i++, optionString += (_tcslen(optionString) + 1))
1532                        (options + i)->optionString = optionString;
1533
1534                    javaVMInitArgs.ignoreUnrecognized = JNI_FALSE;
1535                    javaVMInitArgs.nOptions = optionStringCount;
1536                    javaVMInitArgs.options = options;
1537                    javaVMInitArgs.version = JNI_VERSION_1_2;
1538                    if (jniCreateJavaVM(
1539                            &javaVM,
1540                            (void **) &jniEnv,
1541                            &javaVMInitArgs))
1542                        error = ERROR_FUNCTION_FAILED;
1543                    else
1544                    {
1545                        free(options);
1546                        options = NULL;
1547                        free(optionStrings);
1548                        optionStrings = NULL;
1549
1550                        error = Run_callStaticVoidMain(jniEnv, searchForJava);
1551                        if (JNI_TRUE == (*jniEnv)->ExceptionCheck(jniEnv))
1552                            (*jniEnv)->ExceptionClear(jniEnv);
1553
1554                        (*javaVM)->DestroyJavaVM(javaVM);
1555                    }
1556                    if (options)
1557                        free(options);
1558                }
1559                else
1560                    error = ERROR_OUTOFMEMORY;
1561                if (optionStrings)
1562                    free(optionStrings);
1563            }
1564        }
1565        else
1566            error = GetLastError();
1567        FreeLibrary(hRuntimeLib);
1568    }
1569    else
1570        error = GetLastError();
1571    return error;
1572}
1573
1574static LPSTR
1575Run_skipWhitespace(LPSTR str)
1576{
1577    char ch;
1578
1579    while ((ch = *str) && isspace(ch))
1580        str++;
1581    return str;
1582}
1583
1584int CALLBACK
1585WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdLine, int cmdShow)
1586{
1587    LPTSTR executableFilePath = NULL;
1588    DWORD error;
1589
1590    AttachConsole(ATTACH_PARENT_PROCESS);
1591
1592    error = Run_getExecutableFilePath(&executableFilePath);
1593    if (ERROR_SUCCESS == error)
1594    {
1595        BOOL runAsLauncher = FALSE;
1596
1597        Run_equalsParentProcessExecutableFilePath(
1598                executableFilePath,
1599                &runAsLauncher);
1600        if (runAsLauncher)
1601        {
1602            error = Run_runAsLauncher(executableFilePath, cmdLine);
1603
1604            if (ERROR_SUCCESS !=

Large files files are truncated, but you can click here to view the full file