使用 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 的情况,我认为这是最强大的选项。
我目前正在维护一个 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 的情况,我认为这是最强大的选项。