PageRenderTime 71ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

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