【问题标题】:Loading dll using loadLibrary使用 loadLibrary 加载 dll
【发布时间】:2015-05-04 15:21:32
【问题描述】:

我目前正在维护一个 Java 通信库,它通过 JNI 包装了一些 dll 提供的功能。在某些时候,在 Java 中,我需要加载 JNI 包装器来转发我的请求并最终调用本机库。目前,这是通过调用来完成的

System.loadLibrary("MyLibrary");

here 所述,如果它位于java.library.path 内的某个位置,则应该始终找到MyLibrary。目前,我的java.library.path 似乎包含一些 Java 特定文件夹以及 %PATH% 环境变量中指定的所有目录:

C:\Program Files\Java\jdk1.8.0_45\bin;
C:\Windows\Sun\Java\bin;
C:\Windows\system32;
C:\Windows;
C:\Program Files\ImageMagick-6.9.0-Q16; 
C:\ProgramData\Oracle\Java\javapath;   
C:\Windows\system32;
C:\Windows;
C:\Windows\System32\Wbem;
C:\Windows\System32\WindowsPowerShell\v1.0\;
C:\Program Files\Microsoft SQL Server\110\Tools\Binn\;
C:\Program Files (x86)\Windows Kits\8.1\Windows Performance Toolkit\;
C:\Program Files (x86)\Microsoft SDKs\TypeScript\1.0\;
C:\texlive\2014\bin\win32;
C:\MyFolder\Common32;
C:\MyFolder\Common64;
C:\Program Files (x86)\Microsoft Team Foundation Server 2012 Power Tools\;
C:\Program Files (x86)\Microsoft Team Foundation Server 2012 Power Tools\Best Practices Analyzer\;.

我现在的问题是,即使将MyLibrary 放在C:\MyFolder\Common64; 中,上面的loadLibrary 调用也会产生UnsatisfiedLinkError,我似乎无法理解为什么。但是,当我将它放入 System32 文件夹时,或者如果我在绝对指定路径时调用 load 时会发现它:

System.load("C:\\MyFolder\\Common64\\MyLibrary.dll");

我尝试使用herehere 给出的答案中建议的sys_path 技巧在运行时弄乱java.library.path。以下工作完美无缺:

System.setProperty("java.library.path", "C:\\MyFolder\\Common64\\" );

Field fieldSysPath = ClassLoader.class.getDeclaredField( "sys_paths" );
fieldSysPath.setAccessible( true );
fieldSysPath.set( null, null ); 

System.loadLibrary("MyLibrary");

因此,如果我将整个 java.library.path 属性替换为自定义路径,则 dll 将成功加载。但是,这不是所需的行为,因为我想通过将正确的目录添加到 %PATH% 来动态查找 dll。此外,像这样将我的自定义路径添加到java.library.path

String curJavaLibraryPath = System.getProperty("java.library.path");
System.setProperty("java.library.path", curJavaLibraryPath + ";C:\\MyFolder\\Common64\\" );     

也不行。

目前我正在尝试在 Win7 64 位机器上进行这项工作。如果相关的话,我的 dll 也被编译为 x64。


当我在 x86 模式下编译我的 Java 库并将相应的 JNI dll 复制到 C:\MyFolder\Common32\ 并将该目录添加到 %PATH% 时,一般过程可以完美运行。

【问题讨论】:

  • jdk 或 jre 是否在 64 位运行应用程序?你试过把dll放在C:\Windows\SysWOW64目录下吗?
  • 当我将 dll 放在 System32 文件夹中时,加载 dll 已经可以工作了(在 x64 系统上,这是放置 x64 库的地方)。但是,我希望通过让用户将其放在任何他/她想要的位置,然后将具有相应文件夹的条目添加到 PATH 来动态找到 dll
  • 是的,我知道-D 标志以及通过IDE 设置java.library.path。但这对我没有帮助,因为我只想依赖 %PATH% 变量。我只是想不通,为什么即使它已经在正确的路径中,它也不会加载 dll。
  • 您到底想做什么?将文件放在 %PATH% 中还是从自定义目录加载?如果要将其放在“默认”Windows %PATH% 上,则必须将 dll 放入通过在命令提示符处调用 echo %PATH% 列出的文件夹之一。如果要从自定义目录加载它,则必须使用 System.load("Path to dll") 加载它,而 not 使用 System.loadLibrary() 加载它。或者你必须修改你的 %PATH% 变量,但这有时需要重启你的机器。

标签: java java-native-interface 64-bit environment-variables


【解决方案1】:

显然,loadLibrary() Documentation 有点愚弄了我。如果是UnsatisfiedLinkError,它会声明

UnsatisfiedLinkError - 如果库不存在。

因此,我显然认为loadLibrary() 在任何时候都无法看到我指定的库。但是,情况并非如此,因为此异常也可能意味着它发现相应的库存在错误(与 VM 不兼容)位。

据我了解,要找出您确切拥有的UnsatisfiedLinkError,唯一可以做的检查是分解异常包含的错误消息。我最终做的是:

try
{
    System.setProperty(JAVA_LIBPATH_PROPNAME, libpath);  
    ForceReloadLibraryPath();
    System.loadLibrary("AdsToJava");        
}
catch (UnsatisfiedLinkError ex)
{
    // We simply did not find the dll
    if (ex.getMessage().equals("no MyLibrary in java.library.path")) {

        // Just alert that nothing was found

    } else if ( (ex.getMessage().endsWith("Can't load IA 32-bit .dll on a AMD 64-bit platform")) || 
                (ex.getMessage().endsWith("Can't load AMD 64-bit .dll on a IA 32-bit platform")) ) {

        // Extract the path at which the dll whith the wrong bitness was found 
        // and remove it from the search path and try again
    }
}

您显然也可以在调用 loadLibrary 之前预先检查搜索路径,但由于此方法也适用于用户在整个搜索路径中复制 dll 的情况,我认为这是最强大的选项。

【讨论】:

  • 什么是 ForceReloadLibraryPath?
  • 对不起,伙计。这么多年过去了,我也不记得了,我仍然无法访问该项目。您是否已经尝试不打那个电话了?
  • ForceReloadLibraryPath 可能正在处理 ClassLoader 中的一些缓存私有信息。请参阅stackoverflow.com/questions/15409223/… 了解可能的方法(取决于目标 JVM 版本)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-24
  • 2018-08-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多