src/jdk.jpackage/windows/native/jpackage/jpackage.cpp
branchJDK-8200758-branch
changeset 57151 38d0b67617e3
parent 57150 fa68c2ab636d
child 57152 225a4ac5bd57
equal deleted inserted replaced
57150:fa68c2ab636d 57151:38d0b67617e3
     1 /*
       
     2  * Copyright (c) 2011, 2019, 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 #ifdef DEBUG
       
    35 #include <iostream>
       
    36 #include <sstream>
       
    37 #endif
       
    38 
       
    39 using namespace std;
       
    40 
       
    41 #define MAX_KEY_LENGTH 255
       
    42 #define MAX_VALUE_NAME 16383
       
    43 #define TRAILING_PATHSEPARATOR '\\'
       
    44 
       
    45 bool from_string(int &result, string &str) {
       
    46     const char *p = str.c_str();
       
    47     int res = 0;
       
    48     for (int index = 0;; index++) {
       
    49         char c = str[index];
       
    50         if (c == 0 && index > 0) {
       
    51             result = res;
       
    52             return true;
       
    53         }
       
    54         if (c < '0' || c > '9')
       
    55             return false;
       
    56         res = res * 10 + (c - '0');
       
    57     }
       
    58 }
       
    59 
       
    60 void PrintCSBackupAPIErrorMessage(DWORD dwErr) {
       
    61 
       
    62     char wszMsgBuff[512]; // Buffer for text.
       
    63 
       
    64     DWORD dwChars; // Number of chars returned.
       
    65 
       
    66     // Try to get the message from the system errors.
       
    67     dwChars = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
       
    68             FORMAT_MESSAGE_IGNORE_INSERTS,
       
    69             NULL,
       
    70             dwErr,
       
    71             0,
       
    72             wszMsgBuff,
       
    73             512,
       
    74             NULL);
       
    75 
       
    76     if (0 == dwChars) {
       
    77         // The error code did not exist in the system errors.
       
    78         // Try ntdsbmsg.dll for the error code.
       
    79         HINSTANCE hInst;
       
    80 
       
    81         // Load the library.
       
    82         hInst = LoadLibraryA("ntdsbmsg.dll");
       
    83         if (NULL == hInst) {
       
    84 #ifdef DEBUG
       
    85             cerr << "cannot load ntdsbmsg.dll\n";
       
    86 #endif
       
    87             return;
       
    88         }
       
    89 
       
    90         // Try getting message text from ntdsbmsg.
       
    91         dwChars = FormatMessageA(FORMAT_MESSAGE_FROM_HMODULE |
       
    92                 FORMAT_MESSAGE_IGNORE_INSERTS,
       
    93                 hInst,
       
    94                 dwErr,
       
    95                 0,
       
    96                 wszMsgBuff,
       
    97                 512,
       
    98                 NULL);
       
    99 
       
   100         // Free the library.
       
   101         FreeLibrary(hInst);
       
   102     }
       
   103 
       
   104     // Display the error message, or generic text if not found.
       
   105 #ifdef DEBUG
       
   106     cerr << "Error value: " << dwErr << " Message: " << ((dwChars > 0) ? wszMsgBuff : "Error message not found.") << endl;
       
   107 #endif
       
   108 }
       
   109 
       
   110 class JavaVersion {
       
   111 public:
       
   112     int v1;
       
   113     int v2;
       
   114     int v3;
       
   115     std::wstring home;
       
   116     std::wstring path;
       
   117 
       
   118     JavaVersion(int pv1, int pv2, int pv3) {
       
   119         v1 = pv1;
       
   120         v2 = pv2;
       
   121         v3 = pv3;
       
   122     }
       
   123 
       
   124     bool operator>(const JavaVersion &other) const {
       
   125         if (v1 > other.v1)
       
   126             return true;
       
   127         if (v1 == other.v1) {
       
   128             if (v2 > other.v2)
       
   129                 return true;
       
   130             if (v2 == other.v2)
       
   131                 return v3 > other.v3;
       
   132         }
       
   133         return false;
       
   134     }
       
   135 
       
   136     bool operator>=(const JavaVersion &other) const {
       
   137         if (v1 > other.v1)
       
   138             return true;
       
   139         if (v1 == other.v1) {
       
   140             if (v2 > other.v2)
       
   141                 return true;
       
   142             if (v2 == other.v2)
       
   143                 return v3 >= other.v3;
       
   144         }
       
   145         return false;
       
   146     }
       
   147 
       
   148     bool operator<(const JavaVersion &other) const {
       
   149         if (v1 < other.v1)
       
   150             return true;
       
   151         if (v1 == other.v1) {
       
   152             if (v2 < other.v2)
       
   153                 return true;
       
   154             if (v2 == other.v2)
       
   155                 return v3 < other.v3;
       
   156         }
       
   157         return false;
       
   158     }
       
   159 };
       
   160 
       
   161 class EnvironmentVariable {
       
   162 private:
       
   163     std::wstring FValue;
       
   164 
       
   165 public:
       
   166     EnvironmentVariable(std::wstring Name) {
       
   167         wchar_t* value;
       
   168         size_t requiredSize;
       
   169 
       
   170         _wgetenv_s(&requiredSize, NULL, 0, Name.data());
       
   171 
       
   172         if (requiredSize != 0) {
       
   173             value = (wchar_t*)malloc(requiredSize * sizeof(wchar_t));
       
   174             if (value)
       
   175             {
       
   176                 // Get the value of the LIB environment variable.
       
   177                 _wgetenv_s(&requiredSize, value, requiredSize, Name.data());
       
   178                 FValue = value;
       
   179             }
       
   180         }
       
   181     }
       
   182 
       
   183     std::wstring get() {
       
   184         return FValue;
       
   185     }
       
   186 
       
   187     bool exists() {
       
   188         return !FValue.empty();
       
   189     }
       
   190 };
       
   191 
       
   192 bool checkJavaHome(HKEY key, const char * sKey, const char * jv,
       
   193         JavaVersion *version) {
       
   194     char p[MAX_KEY_LENGTH];
       
   195     HKEY hKey;
       
   196     bool result = false;
       
   197     int res;
       
   198 
       
   199     strcpy_s(p, MAX_KEY_LENGTH, sKey);
       
   200     strcat_s(p, MAX_KEY_LENGTH - strlen(p), "\\");
       
   201     strcat_s(p, MAX_KEY_LENGTH - strlen(p), jv);
       
   202 
       
   203     if (RegOpenKeyExA(key,
       
   204             p,
       
   205             0,
       
   206             KEY_READ,
       
   207             &hKey) == ERROR_SUCCESS
       
   208             ) {
       
   209         DWORD ot = REG_SZ;
       
   210         DWORD size = 255;
       
   211         wchar_t data[MAX_PATH] = { 0 };
       
   212         if ((res = RegQueryValueEx(hKey, L"JavaHome", NULL, &ot,
       
   213                 (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     size_t nn = s.length();
       
   282     for (size_t 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 (size_t 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 int fileExists(const std::wstring& path) {
       
   426     WIN32_FIND_DATA ffd;
       
   427     HANDLE hFind;
       
   428 
       
   429     hFind = FindFirstFile(path.data(), &ffd);
       
   430     if (hFind == INVALID_HANDLE_VALUE)
       
   431         return FALSE;
       
   432 
       
   433     FindClose(hFind);
       
   434     return (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0;
       
   435 }
       
   436 
       
   437 bool hasEnding(std::wstring const &fullString, std::wstring const &ending) {
       
   438     if (fullString.length() >= ending.length()) {
       
   439         return (0 == fullString.compare(fullString.length() - ending.length(),
       
   440                                                         ending.length(), ending));
       
   441     }
       
   442     else {
       
   443         return false;
       
   444     }
       
   445 }
       
   446 
       
   447 std::wstring ExtractFilePath(std::wstring Path) {
       
   448     std::wstring result;
       
   449     size_t slash = Path.find_last_of(TRAILING_PATHSEPARATOR);
       
   450     if (slash != std::wstring::npos)
       
   451         result = Path.substr(0, slash);
       
   452     return result;
       
   453 }
       
   454 
       
   455 std::wstring GetCurrentExecutableName() {
       
   456     TCHAR FileName[MAX_PATH];
       
   457     GetModuleFileName(NULL, FileName, MAX_PATH);
       
   458     return FileName;
       
   459 }
       
   460 
       
   461 int wmain(int argc, wchar_t* argv[]) {
       
   462     wchar_t buf[MAX_PATH];
       
   463     GetModuleFileName(NULL, buf, MAX_PATH);
       
   464 
       
   465     std::wstring javacmd;
       
   466     std::wstring javahome;
       
   467 
       
   468     std::wstring exe = GetCurrentExecutableName();
       
   469 
       
   470     if (exe.length() <= 0) {
       
   471         JavaVersion * jv2 = GetMaxVersion(HKEY_LOCAL_MACHINE,
       
   472                 "SOFTWARE\\JavaSoft\\JDK");
       
   473         if (jv2 != NULL) {
       
   474             javahome = jv2->home;
       
   475             javacmd = javahome + L"\\bin\\" + L"\\java.exe";
       
   476         }
       
   477         else {
       
   478             javacmd = L"java.exe";
       
   479         }
       
   480     } else {
       
   481         javacmd = ExtractFilePath(exe) + L"\\java.exe";
       
   482     }
       
   483 
       
   484     std::wstring cmd = L"\"" + javacmd + L"\"";
       
   485     if (javahome.length() > 0) {
       
   486         SetEnvironmentVariable(L"JAVA_HOME", javahome.c_str());
       
   487     }
       
   488 
       
   489     std::wstring memory = L"-Xmx512M";
       
   490     std::wstring debug = L"";
       
   491     std::wstring args = L"";
       
   492 
       
   493     for (int i = 1; i < argc; i++) {
       
   494         std::wstring argument = argv[i];
       
   495         std::wstring debug_arg = L"-J-Xdebug:";
       
   496         std::wstring icon_swap_arg = L"--icon-swap";
       
   497         std::wstring version_swap_arg = L"--version-swap";
       
   498 
       
   499         if (argument.find(L"-J-Xmx", 0) == 0) {
       
   500             memory = argument.substr(2, argument.length() - 2);
       
   501         }
       
   502         else if (argument.find(debug_arg, 0) == 0) {
       
   503             std::wstring address = argument.substr(debug_arg.length(),
       
   504                                 argument.length() - debug_arg.length());
       
   505             debug = L"-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=" + address;
       
   506         }
       
   507         else if (argument.find(icon_swap_arg, 0) == 0) {
       
   508             if (argc != 4) {
       
   509                 fwprintf(stderr, TEXT("Usage: jpackage.exe --icon-swap [Icon File Name] [Executable File Name]\n"));
       
   510                 return 1;
       
   511             }
       
   512 
       
   513             wprintf(L"Icon File Name: %s\n", argv[i + 1]);
       
   514             wprintf(L"Executable File Name: %s\n", argv[i + 2]);
       
   515 
       
   516             if (ChangeIcon(argv[i + 1], argv[i + 2]) == true) {
       
   517                 return 0;
       
   518             }
       
   519             else {
       
   520                 fwprintf(stderr, TEXT("failed\n"));
       
   521                 return 1;
       
   522             }
       
   523         }
       
   524         else if (argument.find(version_swap_arg, 0) == 0) {
       
   525             if (argc != 4) {
       
   526                 fwprintf(stderr, TEXT("Usage: jpackage.exe --version-swap [Property File Name] [Executable File Name]\n"));
       
   527                 return 1;
       
   528             }
       
   529 
       
   530             fwprintf(stdout, TEXT("Resource File Name: %s\n"), argv[i + 1]);
       
   531             fwprintf(stdout, TEXT("Executable File Name: %s\n"), argv[i + 2]);
       
   532 
       
   533             VersionInfoSwap vs(argv[i + 1], argv[i + 2]);
       
   534 
       
   535             if (vs.PatchExecutable()) {
       
   536                 return 0;
       
   537             }
       
   538             else {
       
   539                 fwprintf(stderr, TEXT("failed\n"));
       
   540                 return 1;
       
   541             }
       
   542         }
       
   543         else {
       
   544             args = args + L" \"" + argv[i] + L"\"";
       
   545         }
       
   546     }
       
   547 
       
   548 
       
   549     cmd += debug + L" " + memory +
       
   550                 L" -m jdk.jpackage/jdk.jpackage.main.Main" +
       
   551                 L" " + args;
       
   552 
       
   553 #ifdef DEBUG
       
   554     fwprintf (stdout, TEXT("%s\n"), cmd.c_str());
       
   555 #endif
       
   556 
       
   557     STARTUPINFO start;
       
   558     PROCESS_INFORMATION pi;
       
   559     memset(&start, 0, sizeof (start));
       
   560     start.cb = sizeof(start);
       
   561 
       
   562     if (!CreateProcess(NULL, (wchar_t *) cmd.data(),
       
   563             NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &start, &pi)) {
       
   564 #ifdef DEBUG
       
   565         fprintf(stderr, "Cannot start java.exe");
       
   566 #endif
       
   567         return EXIT_FAILURE;
       
   568     }
       
   569 
       
   570     WaitForSingleObject(pi.hProcess, INFINITE);
       
   571     unsigned long exitCode;
       
   572     GetExitCodeProcess(pi.hProcess, &exitCode);
       
   573 
       
   574     CloseHandle(pi.hProcess);
       
   575     CloseHandle(pi.hThread);
       
   576 
       
   577     return exitCode;
       
   578 }