使用 loadLibrary 加载 dll

Loading dll using loadLibrary

我目前正在维护一个 Java 通信库,它包装了一些 dll 通过 JNI 提供的功能。在某些时候,在 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 Server0\Tools\Binn\;
C:\Program Files (x86)\Windows Kits.1\Windows Performance Toolkit\;
C:\Program Files (x86)\Microsoft SDKs\TypeScript.0\;
C:\texlive14\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");

我试图在运行时使用 here and here 给出的答案中建议的 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%.

时,一般过程完美运行

显然,loadLibrary() Documentation 成功地愚弄了我一点。在 UnsatisfiedLinkError 的情况下,它表示

UnsatisfiedLinkError - if the library does not exist.

因此,我显然假设 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 的情况,我认为这是最强大的选项。