head.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452
  1. /*
  2. Launch4j (http://launch4j.sourceforge.net/)
  3. Cross-platform Java application wrapper for creating Windows native executables.
  4. Copyright (c) 2004, 2019 Grzegorz Kowal,
  5. Ian Roberts (jdk preference patch)
  6. Sylvain Mina (single instance patch)
  7. Permission is hereby granted, free of charge, to any person obtaining a copy
  8. of this software and associated documentation files (the "Software"), to deal
  9. in the Software without restriction, including without limitation the rights
  10. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. copies of the Software, and to permit persons to whom the Software is
  12. furnished to do so, subject to the following conditions:
  13. The above copyright notice and this permission notice shall be included in
  14. all copies or substantial portions of the Software.
  15. Except as contained in this notice, the name(s) of the above copyright holders
  16. shall not be used in advertising or otherwise to promote the sale, use or other
  17. dealings in this Software without prior written authorization.
  18. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. THE SOFTWARE.
  25. */
  26. #include "resource.h"
  27. #include "head.h"
  28. HMODULE hModule;
  29. FILE* hLog;
  30. BOOL debugAll = FALSE;
  31. BOOL console = FALSE;
  32. BOOL wow64 = FALSE;
  33. BOOL jniHeader = FALSE;
  34. char oldPwd[_MAX_PATH];
  35. PROCESS_INFORMATION processInformation;
  36. DWORD processPriority;
  37. struct
  38. {
  39. char title[STR];
  40. char msg[BIG_STR];
  41. char url[256];
  42. } error;
  43. struct
  44. {
  45. int foundJava;
  46. BOOL requiresJdk;
  47. BOOL requires64Bit;
  48. BOOL corruptedJreFound;
  49. char originalJavaMinVer[STR];
  50. char originalJavaMaxVer[STR];
  51. char javaMinVer[STR];
  52. char javaMaxVer[STR];
  53. char foundJavaVer[STR];
  54. char foundJavaHome[_MAX_PATH];
  55. } search;
  56. struct
  57. {
  58. char mainClass[_MAX_PATH];
  59. char cmd[_MAX_PATH];
  60. char args[MAX_ARGS];
  61. } launcher;
  62. BOOL initGlobals(BOOL jni)
  63. {
  64. jniHeader = jni;
  65. hModule = GetModuleHandle(NULL);
  66. if (hModule == NULL)
  67. {
  68. return FALSE;
  69. }
  70. strcpy(error.title, LAUNCH4j);
  71. search.foundJava = JAVA_NOT_FOUND;
  72. search.requiresJdk = FALSE;
  73. search.requires64Bit = FALSE;
  74. search.corruptedJreFound = FALSE;
  75. return TRUE;
  76. }
  77. FILE* openLogFile(const char* exePath, const int pathLen)
  78. {
  79. char path[_MAX_PATH] = {0};
  80. strncpy(path, exePath, pathLen);
  81. strcat(path, "\\launch4j.log");
  82. return fopen(path, "a");
  83. }
  84. void closeLogFile()
  85. {
  86. if (hLog != NULL)
  87. {
  88. fclose(hLog);
  89. }
  90. }
  91. BOOL initializeLogging(const char *lpCmdLine, const char* exePath, const int pathLen)
  92. {
  93. char varValue[MAX_VAR_SIZE] = {0};
  94. GetEnvironmentVariable(LAUNCH4j, varValue, MAX_VAR_SIZE);
  95. if (strstr(lpCmdLine, "--l4j-debug") != NULL
  96. || strstr(varValue, "debug") != NULL)
  97. {
  98. hLog = openLogFile(exePath, pathLen);
  99. if (hLog == NULL)
  100. {
  101. return FALSE;
  102. }
  103. debugAll = strstr(lpCmdLine, "--l4j-debug-all") != NULL
  104. || strstr(varValue, "debug-all") != NULL;
  105. }
  106. debug("\n\nVersion:\t%s\n", VERSION);
  107. debug("CmdLine:\t%s %s\n", exePath, lpCmdLine);
  108. return TRUE;
  109. }
  110. void setWow64Flag()
  111. {
  112. LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(
  113. GetModuleHandle(TEXT("kernel32")), "IsWow64Process");
  114. if (fnIsWow64Process != NULL)
  115. {
  116. fnIsWow64Process(GetCurrentProcess(), &wow64);
  117. }
  118. debug("WOW64:\t\t%s\n", wow64 ? "Yes" : "No");
  119. }
  120. void setConsoleFlag()
  121. {
  122. console = TRUE;
  123. }
  124. void msgBox(const char* text)
  125. {
  126. if (console)
  127. {
  128. if (*error.title)
  129. {
  130. printf("%s: %s\n", error.title, text);
  131. }
  132. else
  133. {
  134. printf("%s\n", text);
  135. }
  136. }
  137. else
  138. {
  139. MessageBox(NULL, text, error.title, MB_OK);
  140. }
  141. }
  142. void signalError()
  143. {
  144. DWORD err = GetLastError();
  145. debug("Error msg:\t%s\n", error.msg);
  146. if (err)
  147. {
  148. LPVOID lpMsgBuf;
  149. FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
  150. | FORMAT_MESSAGE_FROM_SYSTEM
  151. | FORMAT_MESSAGE_IGNORE_INSERTS,
  152. NULL,
  153. err,
  154. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  155. (LPTSTR) &lpMsgBuf,
  156. 0,
  157. NULL);
  158. debug(ERROR_FORMAT, (LPCTSTR) lpMsgBuf);
  159. strcat(error.msg, "\n\n");
  160. strcat(error.msg, (LPCTSTR) lpMsgBuf);
  161. LocalFree(lpMsgBuf);
  162. }
  163. msgBox(error.msg);
  164. if (*error.url)
  165. {
  166. debug("Open URL:\t%s\n", error.url);
  167. ShellExecute(NULL, "open", error.url, NULL, NULL, SW_SHOWNORMAL);
  168. }
  169. closeLogFile();
  170. }
  171. BOOL loadString(const int resID, char* buffer)
  172. {
  173. HRSRC hResource;
  174. HGLOBAL hResourceLoaded;
  175. LPBYTE lpBuffer;
  176. debugAll("Resource %d:\t", resID);
  177. hResource = FindResourceEx(hModule, RT_RCDATA, MAKEINTRESOURCE(resID),
  178. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT));
  179. if (NULL != hResource)
  180. {
  181. hResourceLoaded = LoadResource(hModule, hResource);
  182. if (NULL != hResourceLoaded)
  183. {
  184. lpBuffer = (LPBYTE) LockResource(hResourceLoaded);
  185. if (NULL != lpBuffer)
  186. {
  187. int x = 0;
  188. do
  189. {
  190. buffer[x] = (char) lpBuffer[x];
  191. } while (buffer[x++] != 0);
  192. debugAll("%s\n", buffer);
  193. return TRUE;
  194. }
  195. }
  196. }
  197. else
  198. {
  199. SetLastError(0);
  200. buffer[0] = 0;
  201. }
  202. debugAll("<NULL>\n");
  203. return FALSE;
  204. }
  205. BOOL loadBool(const int resID)
  206. {
  207. char boolStr[20] = {0};
  208. loadString(resID, boolStr);
  209. return strcmp(boolStr, TRUE_STR) == 0;
  210. }
  211. int loadInt(const int resID)
  212. {
  213. char intStr[20] = {0};
  214. loadString(resID, intStr);
  215. return atoi(intStr);
  216. }
  217. BOOL regQueryValue(const char* regPath, unsigned char* buffer,
  218. unsigned long bufferLength)
  219. {
  220. HKEY hRootKey;
  221. char* key;
  222. char* value;
  223. if (strstr(regPath, HKEY_CLASSES_ROOT_STR) == regPath)
  224. {
  225. hRootKey = HKEY_CLASSES_ROOT;
  226. }
  227. else if (strstr(regPath, HKEY_CURRENT_USER_STR) == regPath)
  228. {
  229. hRootKey = HKEY_CURRENT_USER;
  230. }
  231. else if (strstr(regPath, HKEY_LOCAL_MACHINE_STR) == regPath)
  232. {
  233. hRootKey = HKEY_LOCAL_MACHINE;
  234. }
  235. else if (strstr(regPath, HKEY_USERS_STR) == regPath)
  236. {
  237. hRootKey = HKEY_USERS;
  238. }
  239. else if (strstr(regPath, HKEY_CURRENT_CONFIG_STR) == regPath)
  240. {
  241. hRootKey = HKEY_CURRENT_CONFIG;
  242. }
  243. else
  244. {
  245. return FALSE;
  246. }
  247. key = strchr(regPath, '\\') + 1;
  248. value = strrchr(regPath, '\\') + 1;
  249. *(value - 1) = 0;
  250. HKEY hKey;
  251. unsigned long datatype;
  252. BOOL result = FALSE;
  253. if ((wow64 && RegOpenKeyEx(hRootKey,
  254. key,
  255. 0,
  256. KEY_READ | KEY_WOW64_64KEY,
  257. &hKey) == ERROR_SUCCESS)
  258. || RegOpenKeyEx(hRootKey,
  259. key,
  260. 0,
  261. KEY_READ,
  262. &hKey) == ERROR_SUCCESS)
  263. {
  264. result = RegQueryValueEx(hKey, value, NULL, &datatype, buffer, &bufferLength)
  265. == ERROR_SUCCESS;
  266. RegCloseKey(hKey);
  267. }
  268. *(value - 1) = '\\';
  269. return result;
  270. }
  271. int findNextVersionPart(const char* startAt)
  272. {
  273. if (startAt == NULL || strlen(startAt) == 0)
  274. {
  275. return 0;
  276. }
  277. char* firstSeparatorA = strchr(startAt, '.');
  278. char* firstSeparatorB = strchr(startAt, '_');
  279. char* firstSeparator;
  280. if (firstSeparatorA == NULL)
  281. {
  282. firstSeparator = firstSeparatorB;
  283. }
  284. else if (firstSeparatorB == NULL)
  285. {
  286. firstSeparator = firstSeparatorA;
  287. }
  288. else
  289. {
  290. firstSeparator = min(firstSeparatorA, firstSeparatorB);
  291. }
  292. if (firstSeparator == NULL)
  293. {
  294. return strlen(startAt);
  295. }
  296. return firstSeparator - startAt;
  297. }
  298. /**
  299. * This method will take java version from `originalVersion` string and convert/format it
  300. * into `version` string that can be used for string comparison with other versions.
  301. *
  302. * Due to different version schemas <=8 vs. >=9 it will "normalize" versions to 1 format
  303. * so we can directly compare old and new versions.
  304. */
  305. void formatJavaVersion(char* version, const char* originalVersion)
  306. {
  307. strcpy(version, "");
  308. if (originalVersion == NULL || strlen(originalVersion) == 0)
  309. {
  310. return;
  311. }
  312. int partsAdded = 0;
  313. int i;
  314. char* pos = (char*) originalVersion;
  315. int curPartLen;
  316. while ((curPartLen = findNextVersionPart(pos)) > 0)
  317. {
  318. char number[curPartLen + 1];
  319. memset(number, 0, curPartLen + 1);
  320. strncpy(number, pos, curPartLen);
  321. if (partsAdded == 0 && (curPartLen != 1 || number[0] != '1'))
  322. {
  323. // NOTE: When it's java 9+ we'll add "1" as the first part of the version
  324. strcpy(version, "1");
  325. partsAdded++;
  326. }
  327. if (partsAdded < 3)
  328. {
  329. if (partsAdded > 0)
  330. {
  331. strcat(version, ".");
  332. }
  333. for (i = 0;
  334. (partsAdded > 0)
  335. && (i < JRE_VER_MAX_DIGITS_PER_PART - strlen(number));
  336. i++)
  337. {
  338. strcat(version, "0");
  339. }
  340. strcat(version, number);
  341. }
  342. else if (partsAdded == 3)
  343. {
  344. // add as an update
  345. strcat(version, "_");
  346. for (i = 0; i < JRE_VER_MAX_DIGITS_PER_PART - strlen(number); i++)
  347. {
  348. strcat(version, "0");
  349. }
  350. strcat(version, number);
  351. }
  352. else if (partsAdded >= 4)
  353. {
  354. debug("Warning:\tformatJavaVersion() too many parts added.\n");
  355. break;
  356. }
  357. partsAdded++;
  358. pos += curPartLen + 1;
  359. if (pos >= originalVersion + strlen(originalVersion))
  360. {
  361. break;
  362. }
  363. }
  364. for (i = partsAdded; i < 3; i++)
  365. {
  366. strcat(version, ".");
  367. int j;
  368. for (j = 0; j < JRE_VER_MAX_DIGITS_PER_PART; j++)
  369. {
  370. strcat(version, "0");
  371. }
  372. }
  373. }
  374. void regSearch(const char* keyName, const int searchType)
  375. {
  376. HKEY hKey;
  377. const DWORD wow64KeyMask = searchType & KEY_WOW64_64KEY;
  378. debug("%s-bit search:\t%s...\n", wow64KeyMask ? "64" : "32", keyName);
  379. if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  380. keyName,
  381. 0,
  382. KEY_READ | wow64KeyMask,
  383. &hKey) == ERROR_SUCCESS)
  384. {
  385. return;
  386. }
  387. DWORD x = 0;
  388. unsigned long versionSize = _MAX_PATH;
  389. FILETIME time;
  390. char fullKeyName[_MAX_PATH] = {0};
  391. char originalVersion[_MAX_PATH] = {0};
  392. char version[_MAX_PATH] = {0};
  393. while (RegEnumKeyEx(
  394. hKey, // handle to key to enumerate
  395. x++, // index of subkey to enumerate
  396. originalVersion,// address of buffer for subkey name
  397. &versionSize, // address for size of subkey buffer
  398. NULL, // reserved
  399. NULL, // address of buffer for class string
  400. NULL, // address for size of class buffer
  401. &time) == ERROR_SUCCESS)
  402. {
  403. strcpy(fullKeyName, keyName);
  404. appendPath(fullKeyName, originalVersion);
  405. debug("Check:\t\t%s\n", fullKeyName);
  406. formatJavaVersion(version, originalVersion);
  407. if (isJavaVersionGood(version, wow64KeyMask)
  408. && isRegistryJavaHomeValid(fullKeyName, searchType))
  409. {
  410. strcpy(search.foundJavaVer, version);
  411. search.foundJava = searchType;
  412. debug("Match:\t\t%s\n", version);
  413. break;
  414. }
  415. debug("Ignore:\t\t%s\n", version);
  416. versionSize = _MAX_PATH;
  417. }
  418. RegCloseKey(hKey);
  419. }
  420. BOOL isRegistryJavaHomeValid(const char* keyName, const int searchType)
  421. {
  422. BOOL valid = FALSE;
  423. HKEY hKey;
  424. char path[_MAX_PATH] = {0};
  425. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  426. keyName,
  427. 0,
  428. KEY_READ | (searchType & KEY_WOW64_64KEY),
  429. &hKey) == ERROR_SUCCESS)
  430. {
  431. unsigned char buffer[_MAX_PATH] = {0};
  432. unsigned long bufferlength = _MAX_PATH;
  433. unsigned long datatype;
  434. if (RegQueryValueEx(hKey, "JavaHome", NULL, &datatype, buffer,
  435. &bufferlength) == ERROR_SUCCESS)
  436. {
  437. int i = 0;
  438. do
  439. {
  440. path[i] = buffer[i];
  441. } while (path[i++] != 0);
  442. valid = isLauncherPathValid(path);
  443. }
  444. RegCloseKey(hKey);
  445. }
  446. if (valid)
  447. {
  448. strcpy(search.foundJavaHome, path);
  449. }
  450. else
  451. {
  452. search.corruptedJreFound = TRUE;
  453. }
  454. return valid;
  455. }
  456. BOOL isLauncherPathValid(const char* path)
  457. {
  458. struct _stat statBuf;
  459. char launcherPath[_MAX_PATH] = {0};
  460. char javacPath[_MAX_PATH] = {0};
  461. BOOL result = FALSE;
  462. if (*path)
  463. {
  464. strcpy(launcherPath, path);
  465. appendLauncher(launcherPath);
  466. result = _stat(launcherPath, &statBuf) == 0;
  467. debug("Check launcher:\t%s %s\n", launcherPath, result ? "(OK)" : "(not found)");
  468. if (result && search.requiresJdk)
  469. {
  470. strcpy(javacPath, path);
  471. appendPath(javacPath, "bin\\javac.exe");
  472. result = _stat(javacPath, &statBuf) == 0;
  473. debug("Check javac:\t%s %s\n", javacPath, result ? "(OK)" : "(not found)");
  474. }
  475. if (!result)
  476. {
  477. // Don't display additional info in the error popup.
  478. SetLastError(0);
  479. }
  480. }
  481. return result;
  482. }
  483. void regSearchWow(const char* keyName)
  484. {
  485. if (search.foundJava != JAVA_NOT_FOUND)
  486. {
  487. return;
  488. }
  489. if (wow64 && !jniHeader)
  490. {
  491. regSearch(keyName, JAVA_FOUND | KEY_WOW64_64KEY);
  492. if ((search.foundJava & KEY_WOW64_64KEY) != JAVA_NOT_FOUND)
  493. {
  494. return;
  495. }
  496. }
  497. if (!search.requires64Bit)
  498. {
  499. regSearch(keyName, JAVA_FOUND);
  500. }
  501. }
  502. BOOL findRegistryJavaHome(char* path)
  503. {
  504. debugAll("findRegistryJavaHome()\n");
  505. if (!search.requiresJdk)
  506. {
  507. regSearchWow("SOFTWARE\\JavaSoft\\Java Runtime Environment");
  508. }
  509. regSearchWow("SOFTWARE\\JavaSoft\\Java Development Kit");
  510. // Java 9 support
  511. if (!search.requiresJdk)
  512. {
  513. regSearchWow("SOFTWARE\\JavaSoft\\JRE");
  514. }
  515. regSearchWow("SOFTWARE\\JavaSoft\\JDK");
  516. // IBM Java 1.8
  517. if (search.foundJava == JAVA_NOT_FOUND)
  518. {
  519. if (!search.requiresJdk)
  520. {
  521. regSearchWow("SOFTWARE\\IBM\\Java Runtime Environment");
  522. }
  523. regSearchWow("SOFTWARE\\IBM\\Java Development Kit");
  524. }
  525. // IBM Java 1.7 and earlier
  526. if (search.foundJava == JAVA_NOT_FOUND)
  527. {
  528. if (!search.requiresJdk)
  529. {
  530. regSearchWow("SOFTWARE\\IBM\\Java2 Runtime Environment");
  531. }
  532. regSearchWow("SOFTWARE\\IBM\\Java Development Kit");
  533. }
  534. if (search.foundJava != JAVA_NOT_FOUND)
  535. {
  536. strcpy(path, search.foundJavaHome);
  537. debug("Runtime used:\t%s (%s-bit)\n", search.foundJavaVer,
  538. (search.foundJava & KEY_WOW64_64KEY) != JAVA_NOT_FOUND ? "64" : "32");
  539. return TRUE;
  540. }
  541. return FALSE;
  542. }
  543. /*
  544. * Extract the executable name, returns path length.
  545. */
  546. int getExePath(char* exePath)
  547. {
  548. if (GetModuleFileName(hModule, exePath, _MAX_PATH) == 0)
  549. {
  550. return -1;
  551. }
  552. return strrchr(exePath, '\\') - exePath;
  553. }
  554. void appendPath(char* basepath, const char* path)
  555. {
  556. if (basepath[strlen(basepath) - 1] != '\\')
  557. {
  558. strcat(basepath, "\\");
  559. }
  560. strcat(basepath, path);
  561. }
  562. void appendLauncher(char* jrePath)
  563. {
  564. if (console)
  565. {
  566. appendPath(jrePath, "bin\\java.exe");
  567. }
  568. else
  569. {
  570. appendPath(jrePath, "bin\\javaw.exe");
  571. }
  572. }
  573. void appendAppClasspath(char* dst, const char* src)
  574. {
  575. strcat(dst, src);
  576. strcat(dst, ";");
  577. }
  578. /*
  579. * Expand environment %variables%
  580. */
  581. BOOL expandVars(char *dst, const char *src, const char *exePath, const int pathLen)
  582. {
  583. char varName[STR] = {0};
  584. char varValue[MAX_VAR_SIZE] = {0};
  585. while (strlen(src) > 0)
  586. {
  587. char *start = strchr(src, '%');
  588. if (start != NULL)
  589. {
  590. char *end = strchr(start + 1, '%');
  591. if (end == NULL)
  592. {
  593. return FALSE;
  594. }
  595. // Copy content up to %VAR%
  596. strncat(dst, src, start - src);
  597. // Insert value of %VAR%
  598. *varName = 0;
  599. strncat(varName, start + 1, end - start - 1);
  600. // Remember value start for logging
  601. char *currentVarValue = dst + strlen(dst);
  602. if (strcmp(varName, "EXEDIR") == 0)
  603. {
  604. strncat(dst, exePath, pathLen);
  605. }
  606. else if (strcmp(varName, "EXEFILE") == 0)
  607. {
  608. strcat(dst, exePath);
  609. }
  610. else if (strcmp(varName, "PWD") == 0)
  611. {
  612. GetCurrentDirectory(_MAX_PATH, dst + strlen(dst));
  613. }
  614. else if (strcmp(varName, "OLDPWD") == 0)
  615. {
  616. strcat(dst, oldPwd);
  617. }
  618. else if (strcmp(varName, "JREHOMEDIR") == 0)
  619. {
  620. strcat(dst, search.foundJavaHome);
  621. }
  622. else if (strstr(varName, HKEY_STR) == varName)
  623. {
  624. regQueryValue(varName, dst + strlen(dst), BIG_STR);
  625. }
  626. else if (strcmp(varName, "") == 0)
  627. {
  628. strcat(dst, "%");
  629. }
  630. else if (GetEnvironmentVariable(varName, varValue, MAX_VAR_SIZE) > 0)
  631. {
  632. strcat(dst, varValue);
  633. }
  634. debug("Substitute:\t%s = %s\n", varName, currentVarValue);
  635. src = end + 1;
  636. }
  637. else
  638. {
  639. // Copy remaining content
  640. strcat(dst, src);
  641. break;
  642. }
  643. }
  644. return TRUE;
  645. }
  646. void appendHeapSizes(char *dst)
  647. {
  648. MEMORYSTATUSEX statex;
  649. statex.dwLength = sizeof(statex);
  650. GlobalMemoryStatusEx(&statex);
  651. appendHeapSize(dst, INITIAL_HEAP_SIZE, INITIAL_HEAP_PERCENT,
  652. statex.ullAvailPhys, "-Xms");
  653. appendHeapSize(dst, MAX_HEAP_SIZE, MAX_HEAP_PERCENT,
  654. statex.ullAvailPhys, "-Xmx");
  655. }
  656. void appendHeapSize(char *dst, const int megabytesID, const int percentID,
  657. const DWORDLONG availableMemory, const char *option)
  658. {
  659. const int mb = 1048576; // 1 MB
  660. const int mbLimit32 = 1024; // Max heap size in MB on 32-bit JREs
  661. const int megabytes = loadInt(megabytesID);
  662. const int percent = loadInt(percentID);
  663. const int availableMb = availableMemory * percent / (100 * mb); // 100% * 1 MB
  664. int heapSizeMb = availableMb > megabytes ? availableMb : megabytes;
  665. if (heapSizeMb > 0)
  666. {
  667. if (!(search.foundJava & KEY_WOW64_64KEY) && heapSizeMb > mbLimit32)
  668. {
  669. debug("Heap limit:\tReduced %d MB heap size to 32-bit maximum %d MB\n",
  670. heapSizeMb, mbLimit32);
  671. heapSizeMb = mbLimit32;
  672. }
  673. debug("Heap %s:\tRequested %d MB / %d%%, Available: %d MB, Heap size: %d MB\n",
  674. option, megabytes, percent, (int)(availableMemory / mb), heapSizeMb);
  675. strcat(dst, option);
  676. _itoa(heapSizeMb, dst + strlen(dst), 10); // 10 -- radix
  677. strcat(dst, "m ");
  678. }
  679. }
  680. void setJvmOptions(char *jvmOptions, const char *exePath)
  681. {
  682. if (loadString(JVM_OPTIONS, jvmOptions))
  683. {
  684. strcat(jvmOptions, " ");
  685. }
  686. /*
  687. * Load additional JVM options from .l4j.ini file
  688. * Options are separated by spaces or CRLF
  689. * # starts an inline comment
  690. */
  691. char iniFilePath[_MAX_PATH] = {0};
  692. strncpy(iniFilePath, exePath, strlen(exePath) - 3);
  693. strcat(iniFilePath, "l4j.ini");
  694. long hFile;
  695. if ((hFile = _open(iniFilePath, _O_RDONLY)) != -1)
  696. {
  697. debug("Loading:\t%s\n", iniFilePath);
  698. const int jvmOptLen = strlen(jvmOptions);
  699. char* src = jvmOptions + jvmOptLen;
  700. char* dst = src;
  701. const int len = _read(hFile, src, MAX_ARGS - jvmOptLen - BIG_STR);
  702. BOOL copy = TRUE;
  703. int i;
  704. for (i = 0; i < len; i++, src++)
  705. {
  706. if (*src == '#')
  707. {
  708. copy = FALSE;
  709. }
  710. else if (*src == 13 || *src == 10)
  711. {
  712. copy = TRUE;
  713. if (dst > jvmOptions && *(dst - 1) != ' ')
  714. {
  715. *dst++ = ' ';
  716. }
  717. }
  718. else if (copy)
  719. {
  720. *dst++ = *src;
  721. }
  722. }
  723. *dst = 0;
  724. if (len > 0 && *(dst - 1) != ' ')
  725. {
  726. strcat(jvmOptions, " ");
  727. }
  728. _close(hFile);
  729. }
  730. }
  731. BOOL createMutex()
  732. {
  733. char mutexName[STR] = {0};
  734. loadString(MUTEX_NAME, mutexName);
  735. if (*mutexName)
  736. {
  737. debug("Create mutex:\t%s\n", mutexName);
  738. SECURITY_ATTRIBUTES security;
  739. security.nLength = sizeof(SECURITY_ATTRIBUTES);
  740. security.bInheritHandle = TRUE;
  741. security.lpSecurityDescriptor = NULL;
  742. CreateMutexA(&security, FALSE, mutexName);
  743. if (GetLastError() == ERROR_ALREADY_EXISTS)
  744. {
  745. debug(ERROR_FORMAT, "Instance already exists.");
  746. return FALSE;
  747. }
  748. }
  749. return TRUE;
  750. }
  751. void setWorkingDirectory(const char *exePath, const int pathLen)
  752. {
  753. char workingDir[_MAX_PATH] = {0};
  754. char tmpPath[_MAX_PATH] = {0};
  755. GetCurrentDirectory(_MAX_PATH, oldPwd);
  756. if (loadString(CHDIR, tmpPath))
  757. {
  758. strncpy(workingDir, exePath, pathLen);
  759. appendPath(workingDir, tmpPath);
  760. _chdir(workingDir);
  761. debug("Working dir:\t%s\n", workingDir);
  762. }
  763. }
  764. void removeChar(char *src, const char toRemove)
  765. {
  766. char* dst = src;
  767. do
  768. {
  769. if (*src != toRemove)
  770. {
  771. *dst++ = *src;
  772. }
  773. } while (*src++ != 0);
  774. }
  775. BOOL pathJreSearch(const char *exePath, const int pathLen)
  776. {
  777. debugAll("pathJreSearch()\n");
  778. char jrePathSpec[_MAX_PATH] = {0};
  779. if (!wow64 && search.requires64Bit)
  780. {
  781. debug("JRE:\t\tCannot use 64-bit runtime on 32-bit OS.\n");
  782. return FALSE;
  783. }
  784. if (loadString(JRE_PATH, jrePathSpec))
  785. {
  786. char jrePath[MAX_ARGS] = {0};
  787. expandVars(jrePath, jrePathSpec, exePath, pathLen);
  788. debug("JRE paths:\t%s\n", jrePath);
  789. char* path = strtok(jrePath, ";");
  790. while (path != NULL)
  791. {
  792. char pathNoBin[_MAX_PATH] = {0};
  793. char *lastBackslash = strrchr(path, '\\');
  794. char *lastSlash = strrchr(path, '/');
  795. if (lastBackslash != NULL && strcasecmp(lastBackslash, "\\bin") == 0)
  796. {
  797. strncpy(pathNoBin, path, lastBackslash - path);
  798. }
  799. else if (lastSlash != NULL && strcasecmp(lastSlash, "/bin") == 0)
  800. {
  801. strncpy(pathNoBin, path, lastSlash - path);
  802. }
  803. else
  804. {
  805. strcpy(pathNoBin, path);
  806. }
  807. removeChar(pathNoBin, '"');
  808. if (*pathNoBin == '\\' || (*pathNoBin != '\0' && *(pathNoBin + 1) == ':'))
  809. {
  810. // Absolute
  811. strcpy(launcher.cmd, pathNoBin);
  812. }
  813. else
  814. {
  815. // Relative
  816. strncpy(launcher.cmd, exePath, pathLen);
  817. launcher.cmd[pathLen] = 0;
  818. appendPath(launcher.cmd, pathNoBin);
  819. }
  820. BOOL is64Bit;
  821. if (isLauncherPathValid(launcher.cmd) && isPathJavaVersionGood(launcher.cmd, &is64Bit))
  822. {
  823. search.foundJava = is64Bit ? JAVA_FOUND | KEY_WOW64_64KEY : JAVA_FOUND;
  824. strcpy(search.foundJavaHome, launcher.cmd);
  825. return TRUE;
  826. }
  827. path = strtok(NULL, ";");
  828. }
  829. }
  830. return FALSE;
  831. }
  832. BOOL registryJreSearch()
  833. {
  834. debugAll("registryJreSearch()\n");
  835. return *search.javaMinVer && findRegistryJavaHome(launcher.cmd);
  836. }
  837. void createJreSearchError()
  838. {
  839. if (*search.javaMinVer)
  840. {
  841. loadString(JRE_VERSION_ERR, error.msg);
  842. strcat(error.msg, " ");
  843. strcat(error.msg, search.originalJavaMinVer);
  844. if (*search.javaMaxVer)
  845. {
  846. strcat(error.msg, " - ");
  847. strcat(error.msg, search.originalJavaMaxVer);
  848. }
  849. if (search.requires64Bit)
  850. {
  851. strcat(error.msg, " (64-bit)");
  852. }
  853. if (search.corruptedJreFound)
  854. {
  855. char launcherErrMsg[BIG_STR] = {0};
  856. if (loadString(LAUNCHER_ERR, launcherErrMsg))
  857. {
  858. strcat(error.msg, "\n");
  859. strcat(error.msg, launcherErrMsg);
  860. }
  861. }
  862. loadString(DOWNLOAD_URL, error.url);
  863. }
  864. else
  865. {
  866. loadString(JRE_NOT_FOUND_ERR, error.msg);
  867. }
  868. }
  869. BOOL jreSearch(const char *exePath, const int pathLen)
  870. {
  871. debugAll("jreSearch()\n");
  872. BOOL result = TRUE;
  873. search.requiresJdk = loadBool(REQUIRES_JDK);
  874. debug("Requires JDK:\t%s\n", search.requiresJdk ? "Yes" : "No");
  875. search.requires64Bit = loadBool(REQUIRES_64_BIT);
  876. debug("Requires 64-Bit: %s\n", search.requires64Bit ? "Yes" : "No");
  877. loadString(JAVA_MIN_VER, search.originalJavaMinVer);
  878. formatJavaVersion(search.javaMinVer, search.originalJavaMinVer);
  879. debug("Java min ver:\t%s\n", search.javaMinVer);
  880. loadString(JAVA_MAX_VER, search.originalJavaMaxVer);
  881. formatJavaVersion(search.javaMaxVer, search.originalJavaMaxVer);
  882. debug("Java max ver:\t%s\n", search.javaMaxVer);
  883. if (!pathJreSearch(exePath, pathLen))
  884. {
  885. result = registryJreSearch();
  886. }
  887. if (!result)
  888. {
  889. createJreSearchError();
  890. }
  891. return result;
  892. }
  893. /*
  894. * Append a path to the Path environment variable
  895. */
  896. BOOL appendToPathVar(const char* path)
  897. {
  898. char chBuf[MAX_VAR_SIZE] = {0};
  899. const int pathSize = GetEnvironmentVariable("Path", chBuf, MAX_VAR_SIZE);
  900. if (MAX_VAR_SIZE - pathSize - 1 < strlen(path))
  901. {
  902. return FALSE;
  903. }
  904. strcat(chBuf, ";");
  905. strcat(chBuf, path);
  906. return SetEnvironmentVariable("Path", chBuf);
  907. }
  908. BOOL appendJreBinToPathVar()
  909. {
  910. // Append a path to the Path environment variable
  911. char jreBinPath[_MAX_PATH] = {0};
  912. strcpy(jreBinPath, launcher.cmd);
  913. strcat(jreBinPath, "\\bin");
  914. if (!appendToPathVar(jreBinPath))
  915. {
  916. debug(ERROR_FORMAT, "appendToPathVar failed.");
  917. return FALSE;
  918. }
  919. return TRUE;
  920. }
  921. void setEnvironmentVariables(const char *exePath, const int pathLen)
  922. {
  923. char tmp[MAX_ARGS] = {0};
  924. char envVars[MAX_VAR_SIZE] = {0};
  925. loadString(ENV_VARIABLES, envVars);
  926. char *var = strtok(envVars, "\t");
  927. while (var != NULL)
  928. {
  929. char *varValue = strchr(var, '=');
  930. *varValue++ = 0;
  931. *tmp = 0;
  932. expandVars(tmp, varValue, exePath, pathLen);
  933. debug("Set var:\t%s = %s\n", var, tmp);
  934. SetEnvironmentVariable(var, tmp);
  935. var = strtok(NULL, "\t");
  936. }
  937. }
  938. void setMainClassAndClassPath(const char *exePath, const int pathLen)
  939. {
  940. char classPath[MAX_ARGS] = {0};
  941. char expandedClassPath[MAX_ARGS] = {0};
  942. char jar[_MAX_PATH] = {0};
  943. char fullFileName[_MAX_PATH] = {0};
  944. const BOOL wrapper = loadBool(WRAPPER);
  945. loadString(JAR, jar);
  946. if (loadString(MAIN_CLASS, launcher.mainClass))
  947. {
  948. debug("Main class:\t%s\n", launcher.mainClass);
  949. if (!loadString(CLASSPATH, classPath))
  950. {
  951. debug("Info:\t\tClasspath not defined.\n");
  952. }
  953. expandVars(expandedClassPath, classPath, exePath, pathLen);
  954. strcat(launcher.args, "-classpath \"");
  955. if (wrapper)
  956. {
  957. appendAppClasspath(launcher.args, exePath);
  958. }
  959. else if (*jar)
  960. {
  961. appendAppClasspath(launcher.args, jar);
  962. }
  963. // Deal with wildcards or >> strcat(launcherArgs, exp); <<
  964. char* cp = strtok(expandedClassPath, ";");
  965. while(cp != NULL)
  966. {
  967. debug("Add classpath:\t%s\n", cp);
  968. if (strpbrk(cp, "*?") != NULL)
  969. {
  970. char* lastBackslash = strrchr(cp, '\\');
  971. int pathLen = lastBackslash != NULL ? lastBackslash - cp + 1 : 0;
  972. *fullFileName = 0;
  973. strncpy(fullFileName, cp, pathLen);
  974. char* fileName = fullFileName + pathLen;
  975. *fileName = 0;
  976. struct _finddata_t c_file;
  977. long hFile;
  978. if ((hFile = _findfirst(cp, &c_file)) != -1L)
  979. {
  980. do
  981. {
  982. strcpy(fileName, c_file.name);
  983. appendAppClasspath(launcher.args, fullFileName);
  984. debug(" \" :\t%s\n", fullFileName);
  985. } while (_findnext(hFile, &c_file) == 0);
  986. }
  987. _findclose(hFile);
  988. }
  989. else
  990. {
  991. appendAppClasspath(launcher.args, cp);
  992. }
  993. cp = strtok(NULL, ";");
  994. }
  995. *(launcher.args + strlen(launcher.args) - 1) = 0;
  996. strcat(launcher.args, "\" ");
  997. strcat(launcher.args, launcher.mainClass);
  998. }
  999. else if (wrapper)
  1000. {
  1001. strcat(launcher.args, "-jar \"");
  1002. strcat(launcher.args, exePath);
  1003. strcat(launcher.args, "\"");
  1004. }
  1005. else
  1006. {
  1007. strcat(launcher.args, "-jar \"");
  1008. strncat(launcher.args, exePath, pathLen);
  1009. appendPath(launcher.args, jar);
  1010. strcat(launcher.args, "\"");
  1011. }
  1012. }
  1013. void setCommandLineArgs(const char *lpCmdLine)
  1014. {
  1015. char tmp[MAX_ARGS] = {0};
  1016. // Constant command line arguments
  1017. if (loadString(CMD_LINE, tmp))
  1018. {
  1019. strcat(launcher.args, " ");
  1020. strcat(launcher.args, tmp);
  1021. }
  1022. // Command line arguments
  1023. if (*lpCmdLine)
  1024. {
  1025. strcpy(tmp, lpCmdLine);
  1026. char* dst;
  1027. while ((dst = strstr(tmp, "--l4j-")) != NULL)
  1028. {
  1029. char* src = strchr(dst, ' ');
  1030. if (src == NULL || *(src + 1) == 0)
  1031. {
  1032. *dst = 0;
  1033. }
  1034. else
  1035. {
  1036. strcpy(dst, src + 1);
  1037. }
  1038. }
  1039. if (*tmp)
  1040. {
  1041. strcat(launcher.args, " ");
  1042. strcat(launcher.args, tmp);
  1043. }
  1044. }
  1045. }
  1046. int prepare(const char *lpCmdLine, BOOL jni)
  1047. {
  1048. if (!initGlobals(jni))
  1049. {
  1050. return FALSE;
  1051. }
  1052. // Get executable path
  1053. char exePath[_MAX_PATH] = {0};
  1054. int pathLen = getExePath(exePath);
  1055. if (pathLen == -1)
  1056. {
  1057. return FALSE;
  1058. }
  1059. if (!initializeLogging(lpCmdLine, exePath, pathLen))
  1060. {
  1061. return FALSE;
  1062. }
  1063. debug("JNI:\t\t%s\n", jniHeader ? "Yes" : "No");
  1064. setWow64Flag();
  1065. // Set default error message, title and optional support web site url.
  1066. loadString(ERR_TITLE, error.title);
  1067. loadString(SUPPORT_URL, error.url);
  1068. if (!loadString(STARTUP_ERR, error.msg))
  1069. {
  1070. debug(ERROR_FORMAT, "Startup error message not defined.");
  1071. return FALSE;
  1072. }
  1073. // Single instance
  1074. if (!createMutex())
  1075. {
  1076. return ERROR_ALREADY_EXISTS;
  1077. }
  1078. setWorkingDirectory(exePath, pathLen);
  1079. if (!jreSearch(exePath, pathLen))
  1080. {
  1081. return FALSE;
  1082. }
  1083. if (!appendJreBinToPathVar())
  1084. {
  1085. return FALSE;
  1086. }
  1087. setEnvironmentVariables(exePath, pathLen);
  1088. processPriority = loadInt(PRIORITY_CLASS);
  1089. appendLauncher(launcher.cmd);
  1090. appendHeapSizes(launcher.args);
  1091. char jvmOptions[MAX_ARGS] = {0};
  1092. setJvmOptions(jvmOptions, exePath);
  1093. expandVars(launcher.args, jvmOptions, exePath, pathLen);
  1094. setMainClassAndClassPath(exePath, pathLen);
  1095. setCommandLineArgs(lpCmdLine);
  1096. debug("Launcher:\t%s\n", launcher.cmd);
  1097. debug("Launcher args:\t%s\n", launcher.args);
  1098. debug("Args length:\t%d/32768 chars\n", strlen(launcher.args));
  1099. return TRUE;
  1100. }
  1101. void closeProcessHandles()
  1102. {
  1103. CloseHandle(processInformation.hThread);
  1104. CloseHandle(processInformation.hProcess);
  1105. }
  1106. BOOL execute(const BOOL wait, DWORD *dwExitCode)
  1107. {
  1108. STARTUPINFO si;
  1109. memset(&processInformation, 0, sizeof(processInformation));
  1110. memset(&si, 0, sizeof(si));
  1111. si.cb = sizeof(si);
  1112. char cmdline[MAX_ARGS] = {0};
  1113. strcpy(cmdline, "\"");
  1114. strcat(cmdline, launcher.cmd);
  1115. strcat(cmdline, "\" ");
  1116. strcat(cmdline, launcher.args);
  1117. if (CreateProcess(NULL, cmdline, NULL, NULL,
  1118. TRUE, processPriority, NULL, NULL, &si, &processInformation))
  1119. {
  1120. if (wait)
  1121. {
  1122. WaitForSingleObject(processInformation.hProcess, INFINITE);
  1123. GetExitCodeProcess(processInformation.hProcess, dwExitCode);
  1124. closeProcessHandles();
  1125. }
  1126. else
  1127. {
  1128. *dwExitCode = 0;
  1129. }
  1130. return TRUE;
  1131. }
  1132. *dwExitCode = -1;
  1133. return FALSE;
  1134. }
  1135. const char* getJavaHome()
  1136. {
  1137. return search.foundJavaHome;
  1138. }
  1139. const char* getMainClass()
  1140. {
  1141. return launcher.mainClass;
  1142. }
  1143. const char* getLauncherArgs()
  1144. {
  1145. return launcher.args;
  1146. }
  1147. /* read java version output and save version string in version */
  1148. void getVersionFromOutput(HANDLE outputRd, char *version, int versionLen, BOOL *is64Bit)
  1149. {
  1150. CHAR chBuf[BIG_STR] = {0}, *bptr = chBuf;
  1151. DWORD dwRead, remain = sizeof(chBuf);
  1152. BOOL bSuccess = FALSE;
  1153. while (remain > 0) {
  1154. bSuccess = ReadFile(outputRd, bptr, remain, &dwRead, NULL);
  1155. if (! bSuccess || dwRead == 0) break;
  1156. bptr += dwRead;
  1157. remain -= dwRead;
  1158. }
  1159. debugAll("Java version output: %s\n", chBuf);
  1160. *version = '\0';
  1161. const char *verStartPtr = strchr(chBuf, '"');
  1162. if (verStartPtr == NULL)
  1163. {
  1164. debug("Cannot get version string: cannot find quote\n");
  1165. return;
  1166. }
  1167. const char *verEndPtr = strchr(++verStartPtr, '"');
  1168. if (verEndPtr == NULL)
  1169. {
  1170. debug("Cannot get version string: missing end quote\n");
  1171. return;
  1172. }
  1173. size_t len = verEndPtr - verStartPtr;
  1174. if (len >= versionLen) {
  1175. debug("Cannot get version string: data too large\n");
  1176. return;
  1177. }
  1178. memcpy(version, verStartPtr, len);
  1179. version[len] = '\0';
  1180. *is64Bit = strstr(chBuf, "64-Bit") != NULL || strstr(chBuf, "64-bit") != NULL;
  1181. }
  1182. /* create a child process with cmdline and set stderr/stdout to outputWr */
  1183. BOOL CreateChildProcess(char *cmdline, HANDLE outputWr)
  1184. {
  1185. PROCESS_INFORMATION piProcInfo;
  1186. STARTUPINFO siStartInfo;
  1187. BOOL bSuccess = FALSE;
  1188. ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
  1189. ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
  1190. siStartInfo.cb = sizeof(STARTUPINFO);
  1191. siStartInfo.hStdError = outputWr;
  1192. siStartInfo.hStdOutput = outputWr;
  1193. siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
  1194. debugAll("Create process: %s\n", cmdline);
  1195. bSuccess = CreateProcess(NULL, cmdline, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &siStartInfo, &piProcInfo);
  1196. if (!bSuccess)
  1197. {
  1198. debug("Cannot create process %s\n", cmdline);
  1199. }
  1200. else
  1201. {
  1202. CloseHandle(piProcInfo.hProcess);
  1203. CloseHandle(piProcInfo.hThread);
  1204. }
  1205. CloseHandle(outputWr);
  1206. return bSuccess;
  1207. }
  1208. BOOL isJavaVersionGood(const char *version, BOOL is64Bit)
  1209. {
  1210. BOOL result = (!*search.javaMinVer || strcmp(version, search.javaMinVer) >= 0)
  1211. && (!*search.javaMaxVer || strcmp(version, search.javaMaxVer) <= 0)
  1212. && (!search.requires64Bit || is64Bit)
  1213. && (!jniHeader || !is64Bit);
  1214. debug("Version string: %s / %s-Bit (%s)\n", version, is64Bit ? "64" : "32", result ? "OK" : "Ignore");
  1215. return result;
  1216. }
  1217. /*
  1218. * Run <path>/bin/java(w) -version. Return TRUE if version is good.
  1219. */
  1220. BOOL isPathJavaVersionGood(const char *path, BOOL *is64Bit)
  1221. {
  1222. SECURITY_ATTRIBUTES saAttr;
  1223. HANDLE outputRd = NULL;
  1224. HANDLE outputWr = NULL;
  1225. debugAll("Check Java Version: %s min=%s max=%s\n", path, search.javaMinVer, search.javaMaxVer);
  1226. saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
  1227. saAttr.bInheritHandle = TRUE;
  1228. saAttr.lpSecurityDescriptor = NULL;
  1229. // Create a pipe for the child process's STDOUT.
  1230. if (!CreatePipe(&outputRd, &outputWr, &saAttr, 0))
  1231. {
  1232. debug("Cannot create pipe\n");
  1233. return FALSE;
  1234. }
  1235. // Ensure the read handle to the pipe for STDOUT is not inherited.
  1236. if (!SetHandleInformation(outputRd, HANDLE_FLAG_INHERIT, 0))
  1237. {
  1238. debug("Cannot set handle information\n");
  1239. CloseHandle(outputRd);
  1240. CloseHandle(outputWr);
  1241. return FALSE;
  1242. }
  1243. // create child process
  1244. char cmdline[MAX_ARGS] = {0};
  1245. char launcherPath[_MAX_PATH] = {0};
  1246. strcpy(launcherPath, path);
  1247. appendLauncher(launcherPath);
  1248. snprintf(cmdline, MAX_ARGS, "\"%s\" -version", launcherPath);
  1249. if (!CreateChildProcess(cmdline, outputWr))
  1250. {
  1251. debug("Cannot run java(w) -version\n");
  1252. CloseHandle(outputRd);
  1253. return FALSE;
  1254. }
  1255. char version[STR] = {0}, formattedVersion[STR] = {0};
  1256. getVersionFromOutput(outputRd, version, sizeof(version), is64Bit);
  1257. CloseHandle(outputRd);
  1258. if (*version != '\0')
  1259. {
  1260. formatJavaVersion(formattedVersion, version);
  1261. return isJavaVersionGood(formattedVersion, *is64Bit);
  1262. }
  1263. return FALSE;
  1264. }