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