changeset 59262:99fe4024af19

8244634: LoadLibraryW failed from tools/jpackage tests after JDK-8242302 Reviewed-by: herrick, almatvee
author asemenyuk
date Tue, 12 May 2020 19:34:59 -0400
parents c9f5a16d6980
children 581be80a50f1
files src/jdk.incubator.jpackage/share/native/applauncher/JvmLauncher.h src/jdk.incubator.jpackage/windows/native/applauncher/WinLauncher.cpp src/jdk.incubator.jpackage/windows/native/common/WinSysInfo.cpp src/jdk.incubator.jpackage/windows/native/common/WinSysInfo.h
diffstat 4 files changed, 96 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.incubator.jpackage/share/native/applauncher/JvmLauncher.h	Wed May 13 07:25:47 2020 +0800
+++ b/src/jdk.incubator.jpackage/share/native/applauncher/JvmLauncher.h	Tue May 12 19:34:59 2020 -0400
@@ -46,6 +46,10 @@
         return *this;
     }
 
+    tstring getPath() const {
+        return jvmPath;
+    }
+
     void launch();
 
 private:
--- a/src/jdk.incubator.jpackage/windows/native/applauncher/WinLauncher.cpp	Wed May 13 07:25:47 2020 +0800
+++ b/src/jdk.incubator.jpackage/windows/native/applauncher/WinLauncher.cpp	Tue May 12 19:34:59 2020 -0400
@@ -28,10 +28,14 @@
 #include <windows.h>
 
 #include "AppLauncher.h"
+#include "JvmLauncher.h"
 #include "Log.h"
+#include "Dll.h"
+#include "Toolbox.h"
 #include "FileUtils.h"
 #include "UniqueHandle.h"
 #include "ErrorHandling.h"
+#include "WinSysInfo.h"
 #include "WinErrorHandling.h"
 
 
@@ -41,6 +45,61 @@
 
 namespace {
 
+std::unique_ptr<Dll> loadDllWithAlteredPATH(const tstring& dllFullPath) {
+    LOG_TRACE_FUNCTION();
+
+    const tstring vanillaPathEnvVariable = SysInfo::getEnvVariable(_T("PATH"));
+
+    tstring pathEnvVariable = vanillaPathEnvVariable
+            + _T(";")
+            + FileUtils::dirname(dllFullPath);
+
+    SysInfo::setEnvVariable(_T("PATH"), pathEnvVariable);
+
+    LOG_TRACE(tstrings::any() << "New value of PATH: " << pathEnvVariable);
+
+    // Schedule restore of PATH after attempt to load the given dll
+    const auto resetPATH = runAtEndOfScope([&vanillaPathEnvVariable]() -> void {
+        SysInfo::setEnvVariable(_T("PATH"), vanillaPathEnvVariable);
+    });
+
+    return std::unique_ptr<Dll>(new Dll(dllFullPath));
+}
+
+std::unique_ptr<Dll> loadDllWithAddDllDirectory(const tstring& dllFullPath) {
+    LOG_TRACE_FUNCTION();
+
+    const tstring dirPath = FileUtils::dirname(dllFullPath);
+
+    typedef DLL_DIRECTORY_COOKIE(WINAPI *AddDllDirectoryFunc)(PCWSTR);
+
+    DllFunction<AddDllDirectoryFunc> _AddDllDirectory(
+            Dll("kernel32.dll", Dll::System()), "AddDllDirectory");
+
+    AddDllDirectoryFunc func = _AddDllDirectory;
+    DLL_DIRECTORY_COOKIE res = func(dirPath.c_str());
+    if (!res) {
+        JP_THROW(SysError(tstrings::any()
+                << "AddDllDirectory(" << dirPath << ") failed", func));
+    }
+
+    LOG_TRACE(tstrings::any() << "AddDllDirectory(" << dirPath << "): OK");
+
+    // Important: use LOAD_LIBRARY_SEARCH_DEFAULT_DIRS flag,
+    // but not LOAD_LIBRARY_SEARCH_USER_DIRS!
+    HMODULE dllHandle = LoadLibraryEx(dllFullPath.c_str(), NULL,
+            LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
+
+    LOG_TRACE(tstrings::any() << "LoadLibraryEx(" << dllFullPath
+            << ", LOAD_LIBRARY_SEARCH_DEFAULT_DIRS): " << dllHandle);
+
+    const auto freeDll = runAtEndOfScope([&dllHandle]() -> void {
+        Dll::freeLibrary(dllHandle);
+    });
+
+    return std::unique_ptr<Dll>(new Dll(dllFullPath));
+}
+
 void launchApp() {
     // [RT-31061] otherwise UI can be left in back of other windows.
     ::AllowSetForegroundWindow(ASFW_ANY);
@@ -48,13 +107,31 @@
     const tstring launcherPath = SysInfo::getProcessModulePath();
     const tstring appImageRoot = FileUtils::dirname(launcherPath);
 
-    AppLauncher()
+    std::unique_ptr<Jvm> jvm(AppLauncher()
         .setImageRoot(appImageRoot)
         .addJvmLibName(_T("bin\\jli.dll"))
         .setAppDir(FileUtils::mkpath() << appImageRoot << _T("app"))
         .setDefaultRuntimePath(FileUtils::mkpath() << appImageRoot
                 << _T("runtime"))
-        .launch();
+        .createJvmLauncher());
+
+    std::unique_ptr<Dll> jvmDll;
+    try {
+        // Try load JVM DLL.
+        jvmDll = std::unique_ptr<Dll>(new Dll(jvm->getPath()));
+    } catch (const std::exception&) {
+        // JVM DLL load failed, though it exists in file system.
+        try {
+            // Try adjust the DLL search paths with AddDllDirectory() WINAPI CALL
+            jvmDll = loadDllWithAddDllDirectory(jvm->getPath());
+        } catch (const std::exception&) {
+            // AddDllDirectory() didn't work. Try altering PATH environment
+            // variable as the last resort.
+            jvmDll = loadDllWithAlteredPATH(jvm->getPath());
+        }
+    }
+
+    jvm->launch();
 }
 
 } // namespace
--- a/src/jdk.incubator.jpackage/windows/native/common/WinSysInfo.cpp	Wed May 13 07:25:47 2020 +0800
+++ b/src/jdk.incubator.jpackage/windows/native/common/WinSysInfo.cpp	Tue May 12 19:34:59 2020 -0400
@@ -114,6 +114,16 @@
     return hmodule;
 }
 
+void setEnvVariable(const tstring& name, const tstring& value)
+{
+    if (!SetEnvironmentVariable(name.c_str(), value.c_str())) {
+        JP_THROW(SysError(tstrings::any()
+                << "SetEnvironmentVariable("
+                << name << ", " << value
+                << ") failed", SetEnvironmentVariable));
+    }
+}
+
 tstring getCurrentModulePath()
 {
     return getModulePath(getCurrentModuleHandle());
--- a/src/jdk.incubator.jpackage/windows/native/common/WinSysInfo.h	Wed May 13 07:25:47 2020 +0800
+++ b/src/jdk.incubator.jpackage/windows/native/common/WinSysInfo.h	Tue May 12 19:34:59 2020 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -43,6 +43,8 @@
     // Returns handle of the current module (exe or dll).
     // The function assumes this code is statically linked to the module.
     HMODULE getCurrentModuleHandle();
+
+    void setEnvVariable(const tstring& name, const tstring& value);
 }