1 /* 2 * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string> 29 #include <windows.h> 30 31 //#define _DEBUG 32 33 #ifdef _DEBUG 34 #include <iostream> 35 #include <sstream> 36 #endif 37 38 using namespace std; 39 40 #define MAX_KEY_LENGTH 255 41 #define MAX_VALUE_NAME 16383 42 43 bool from_string(int &result, string &str) { 44 const char *p = str.c_str(); 45 int res = 0; 46 for (int index = 0;; index++) { 47 char c = str[index]; 48 if (c == 0 && index > 0) { 49 result = res; 50 return true; 51 } 52 if (c < '0' || c > '9') 53 return false; 54 res = res * 10 + (c - '0'); 55 } 56 } 57 58 void PrintCSBackupAPIErrorMessage(DWORD dwErr) { 59 60 char wszMsgBuff[512]; // Buffer for text. 61 62 DWORD dwChars; // Number of chars returned. 63 64 // Try to get the message from the system errors. 65 dwChars = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | 66 FORMAT_MESSAGE_IGNORE_INSERTS, 67 NULL, 68 dwErr, 69 0, 70 wszMsgBuff, 71 512, 72 NULL); 73 74 if (0 == dwChars) { 75 // The error code did not exist in the system errors. 76 // Try ntdsbmsg.dll for the error code. 77 78 HINSTANCE hInst; 79 80 // Load the library. 81 hInst = LoadLibraryA("ntdsbmsg.dll"); 82 if (NULL == hInst) { 83 #ifdef _DEBUG 84 cerr << "cannot load ntdsbmsg.dll\n"; 85 #endif 86 return; 87 } 88 89 // Try getting message text from ntdsbmsg. 90 dwChars = FormatMessageA(FORMAT_MESSAGE_FROM_HMODULE | 91 FORMAT_MESSAGE_IGNORE_INSERTS, 92 hInst, 93 dwErr, 94 0, 95 wszMsgBuff, 96 512, 97 NULL); 98 99 // Free the library. 100 FreeLibrary(hInst); 101 } 102 103 // Display the error message, or generic text if not found. 104 #ifdef _DEBUG 105 cerr << "Error value: " << dwErr << " Message: " << ((dwChars > 0) ? wszMsgBuff : "Error message not found.") << endl; 106 #endif 107 } 108 109 class JavaVersion { 110 public: 111 int v1; 112 int v2; 113 int v3; 114 std::wstring home; 115 std::wstring path; 116 117 JavaVersion(int pv1, int pv2, int pv3) { 118 v1 = pv1; 119 v2 = pv2; 120 v3 = pv3; 121 } 122 123 bool operator>(const JavaVersion &other) const { 124 if (v1 > other.v1) 125 return true; 126 if (v1 == other.v1) { 127 if (v2 > other.v2) 128 return true; 129 if (v2 == other.v2) 130 return v3 > other.v3; 131 } 132 return false; 133 } 134 135 bool operator>=(const JavaVersion &other) const { 136 if (v1 > other.v1) 137 return true; 138 if (v1 == other.v1) { 139 if (v2 > other.v2) 140 return true; 141 if (v2 == other.v2) 142 return v3 >= other.v3; 143 } 144 return false; 145 } 146 147 bool operator<(const JavaVersion &other) const { 148 if (v1 < other.v1) 149 return true; 150 if (v1 == other.v1) { 151 if (v2 < other.v2) 152 return true; 153 if (v2 == other.v2) 154 return v3 < other.v3; 155 } 156 return false; 157 } 158 }; 159 160 class EnvironmentVariable { 161 private: 162 std::wstring FValue; 163 164 public: 165 EnvironmentVariable(std::wstring Name) { 166 wchar_t* value; 167 size_t requiredSize; 168 169 _wgetenv_s(&requiredSize, NULL, 0, Name.data()); 170 171 if (requiredSize != 0) { 172 value = (wchar_t*)malloc(requiredSize * sizeof(wchar_t)); 173 if (value) 174 { 175 // Get the value of the LIB environment variable. 176 _wgetenv_s(&requiredSize, value, requiredSize, Name.data()); 177 FValue = value; 178 } 179 } 180 } 181 182 std::wstring get() { 183 return FValue; 184 } 185 186 bool exists() { 187 return !FValue.empty(); 188 } 189 }; 190 191 bool checkJavaHome(HKEY key, const char * sKey, const char * jv, JavaVersion *version) { 192 char p[MAX_KEY_LENGTH]; 193 HKEY hKey; 194 bool result = false; 195 int res; 196 197 strcpy_s(p, MAX_KEY_LENGTH, sKey); 198 strcat_s(p, MAX_KEY_LENGTH - strlen(p), "\\"); 199 strcat_s(p, MAX_KEY_LENGTH - strlen(p), jv); 200 201 if (RegOpenKeyExA(key, 202 p, 203 0, 204 KEY_READ, 205 &hKey) == ERROR_SUCCESS 206 ) { 207 DWORD ot = REG_SZ; 208 DWORD size = 255; 209 wchar_t data[MAX_PATH] = { 0 }; 210 if ((res = RegQueryValueEx(hKey, L"JavaHome", NULL, &ot, (BYTE *)data, &size)) == ERROR_SUCCESS) { 211 version->home = data; 212 std::wstring ldata = std::wstring(data) + L"\\bin\\java.exe"; 213 version->path = data; 214 result = GetFileAttributes(data) != 0xFFFFFFFF; 215 } 216 else { 217 PrintCSBackupAPIErrorMessage(res); 218 result = false; 219 } 220 RegCloseKey(hKey); 221 } 222 else { 223 #ifdef _DEBUG 224 cerr << "Can not open registry key" << endl; 225 #endif 226 result = false; 227 } 228 229 return result; 230 } 231 232 JavaVersion * parseName(const char * jName) { 233 string s(jName); 234 235 if (s.length() == 0) { 236 return NULL; 237 } 238 239 string n; 240 string::size_type pos; 241 242 pos = s.find_first_of("."); 243 if (pos != string::npos) { 244 n = s.substr(0, pos); 245 s = s.substr(pos + 1); 246 } 247 else { 248 n = s; 249 s = ""; 250 } 251 252 int v1 = 0; 253 254 if (n.length() > 0) { 255 if (!from_string(v1, n)) 256 return NULL; 257 } 258 259 260 pos = s.find_first_of("."); 261 if (pos != string::npos) { 262 n = s.substr(0, pos); 263 s = s.substr(pos + 1); 264 } 265 else { 266 n = s; 267 s = ""; 268 } 269 270 int v2 = 0; 271 272 if (n.length() > 0) { 273 if (!from_string(v2, n)) 274 return NULL; 275 } 276 277 278 unsigned int nn = s.length(); 279 for (unsigned int i = 0; i < s.length(); i++) { 280 string c = s.substr(i, 1); 281 int tmp; 282 if (!from_string(tmp, c)) { 283 nn = i; 284 break; 285 } 286 } 287 288 n = s.substr(0, nn); 289 if (nn < s.length()) { 290 s = s.substr(nn + 1); 291 } 292 else s = ""; 293 294 int v3 = 0; 295 296 if (n.length() > 0) { 297 if (!from_string(v3, n)) 298 v3 = 0; 299 } 300 301 int v4 = 0; 302 303 //update version 304 if (s.length() > 0) { 305 nn = s.length(); 306 for (unsigned int i = 0; i < s.length(); i++) { 307 string c = s.substr(i, 1); 308 int tmp; 309 if (!from_string(tmp, c)) { 310 nn = i; 311 break; 312 } 313 } 314 315 n = s.substr(0, nn); 316 317 if (n.length() > 0) { 318 if (!from_string(v4, n)) 319 v4 = 0; 320 } 321 } 322 323 return new JavaVersion(v2, v3, v4); 324 } 325 326 JavaVersion * GetMaxVersion(HKEY key, const char * sKey) { 327 HKEY hKey; 328 JavaVersion * result = NULL; 329 330 if (RegOpenKeyExA(key, 331 sKey, 332 0, 333 KEY_READ, 334 &hKey) == ERROR_SUCCESS 335 ) { 336 DWORD retCode; 337 char achClass[MAX_PATH]; // buffer for class name 338 DWORD cchClassName = MAX_PATH; // size of class string 339 340 341 DWORD cchValue = MAX_VALUE_NAME; 342 DWORD cSubKeys = 0; // number of subkeys 343 DWORD cbMaxSubKey; // longest subkey size 344 DWORD cchMaxClass; // longest class string 345 DWORD cValues; // number of values for key 346 DWORD cchMaxValue; // longest value name 347 DWORD cbMaxValueData; // longest value data 348 DWORD cbSecurityDescriptor; // size of security descriptor 349 FILETIME ftLastWriteTime; // last write time 350 351 retCode = RegQueryInfoKeyA( 352 hKey, // key handle 353 achClass, // buffer for class name 354 &cchClassName, // size of class string 355 NULL, // reserved 356 &cSubKeys, // number of subkeys 357 &cbMaxSubKey, // longest subkey size 358 &cchMaxClass, // longest class string 359 &cValues, // number of values for this key 360 &cchMaxValue, // longest value name 361 &cbMaxValueData, // longest value data 362 &cbSecurityDescriptor, // security descriptor 363 &ftLastWriteTime); // last write time 364 365 if (cSubKeys) { 366 for (unsigned int i = 0; i < cSubKeys; i++) { 367 char achKey[MAX_KEY_LENGTH]; // buffer for subkey name 368 DWORD cbName = MAX_KEY_LENGTH; 369 retCode = RegEnumKeyExA(hKey, i, 370 achKey, 371 &cbName, 372 NULL, 373 NULL, 374 NULL, 375 &ftLastWriteTime); 376 377 if (retCode == ERROR_SUCCESS) { 378 #ifdef _DEBUG 379 cout << achKey << endl; 380 #endif 381 JavaVersion * nv = parseName(achKey); 382 383 bool isHome = checkJavaHome(key, sKey, achKey, nv); 384 #ifdef _DEBUG 385 wcout << nv->home << " " << isHome << endl; 386 #endif 387 388 if (isHome) 389 if (result == NULL) { 390 result = nv; 391 #ifdef _DEBUG 392 cout << "NEW" << endl; 393 #endif 394 } 395 else { 396 if (nv != NULL) { 397 if (*nv > *result) { 398 #ifdef _DEBUG 399 cout << "REPLACE" << endl; 400 #endif 401 delete result; 402 result = nv; 403 } 404 else { 405 #ifdef _DEBUG 406 cout << "NO" << endl; 407 #endif 408 delete nv; 409 } 410 } 411 } 412 } 413 } 414 } 415 416 RegCloseKey(hKey); 417 } 418 419 return result; 420 } 421 // ***************************************************************************** 422 423 int fileExists(const std::wstring& path) { 424 WIN32_FIND_DATA ffd; 425 HANDLE hFind; 426 427 hFind = FindFirstFile(path.data(), &ffd); 428 if (hFind == INVALID_HANDLE_VALUE) 429 return FALSE; 430 431 FindClose(hFind); 432 return (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0; 433 } 434 435 bool hasEnding(std::wstring const &fullString, std::wstring const &ending) { 436 if (fullString.length() >= ending.length()) { 437 return (0 == fullString.compare(fullString.length() - ending.length(), ending.length(), ending)); 438 } 439 else { 440 return false; 441 } 442 } 443 444 #define TRAILING_PATHSEPARATOR '\\' 445 446 std::wstring ExtractFilePath(std::wstring Path) { 447 std::wstring result; 448 size_t slash = Path.find_last_of(TRAILING_PATHSEPARATOR); 449 if (slash != std::wstring::npos) 450 result = Path.substr(0, slash); 451 return result; 452 } 453 454 std::wstring GetCurrentExecutableName() { 455 TCHAR FileName[MAX_PATH]; 456 GetModuleFileName(NULL, FileName, MAX_PATH); 457 return FileName; 458 } 459 460 int wmain(int argc, wchar_t* argv[]) { 461 wchar_t buf[MAX_PATH]; 462 GetModuleFileName(NULL, buf, MAX_PATH); 463 std::wstring javafxhome = buf; 464 465 javafxhome.erase(javafxhome.rfind(L"\\")); 466 467 std::wstring fxlib = javafxhome + L"\\..\\lib\\"; 468 469 EnvironmentVariable java_home(L"JAVA_HOME"); 470 std::wstring javacmd; 471 std::wstring javahome; 472 473 if (java_home.exists()) { 474 javahome = java_home.get(); 475 javacmd = javahome + L"\\bin\\java.exe"; 476 std::wstring javaccmd = javahome + L"\\bin\\javac.exe"; 477 if (!fileExists(javacmd) || !fileExists(javaccmd)) { 478 javacmd = L""; 479 javahome = L""; 480 } 481 } 482 else { 483 std::wstring exe = GetCurrentExecutableName(); 484 javacmd = ExtractFilePath(exe) + L"\\java.exe"; 485 } 486 487 if (javacmd.length() <= 0) { 488 JavaVersion * jv2 = GetMaxVersion(HKEY_LOCAL_MACHINE, "SOFTWARE\\JavaSoft\\Java Development Kit"); 489 if (jv2 != NULL) { 490 javacmd = jv2->path; 491 javahome = jv2->home; 492 } 493 else { 494 javacmd = L"java.exe"; 495 } 496 } 497 498 std::wstring cmd = L"\"" + javacmd + L"\""; 499 if (javahome.length() > 0) { 500 SetEnvironmentVariable(L"JAVA_HOME", javahome.c_str()); 501 } 502 503 std::wstring memory = L"-Xmx512M"; 504 std::wstring debug = L""; 505 std::wstring args = L""; 506 507 for (int i = 1; i < argc; i++) { 508 std::wstring argument = argv[i]; 509 std::wstring debug_arg = L"-J-Xdebug:"; 510 511 if (argument.find(L"-J-Xmx", 0) == 0) { 512 memory = argument.substr(2, argument.length() - 2); 513 } 514 else if (argument.find(debug_arg, 0) == 0) { 515 std::wstring address = argument.substr(debug_arg.length(), argument.length() - debug_arg.length()); 516 debug = L"-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=" + address; 517 } 518 else { 519 args = args + L" \"" + argv[i] + L"\""; 520 } 521 } 522 523 524 cmd += debug + 525 L" " + memory + 526 L" -Djavafx.home=" + javafxhome + 527 L" -classpath " + fxlib + L"ant-javafx.jar" + 528 L" com.sun.javafx.tools.packager.Main" + 529 L" " + args; 530 531 #ifdef _DEBUG 532 printf ("%s", cmd.c_str()); 533 #endif 534 535 STARTUPINFO start; 536 PROCESS_INFORMATION pi; 537 memset(&start, 0, sizeof (start)); 538 start.cb = sizeof(start); 539 540 if (!CreateProcess(NULL, (wchar_t *) cmd.data(), 541 NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &start, &pi)) { 542 #ifdef _DEBUG 543 fprintf(stderr, "Cannot start java.exe"); 544 #endif 545 return EXIT_FAILURE; 546 } 547 548 WaitForSingleObject(pi.hProcess, INFINITE); 549 unsigned long exitCode; 550 GetExitCodeProcess(pi.hProcess, &exitCode); 551 552 CloseHandle(pi.hProcess); 553 CloseHandle(pi.hThread); 554 555 return exitCode; 556 }