Eclipse Java JNI,java.lang.UnsatisfiedLinkError 加载 dll
Ecplise Java JNI, java.lang.UnsatisfiedLinkError loading dll
我在加载打印机 dll 时遇到问题。我有打印机制造商 (JniPrinterStatusLib.dll) 提供的 dll 文件。我按照打印机制造商的建议编写了代码。代码是:
package com.printer.test
public class JniPrinterStatus {
static{
System.loadLibrary("JniPrinterStatusLib");
}
public native int GetStatus(String printer);
}
package com.printer.test
public class TestSample {
public static void main(String[] args) {
int status;
String printer = "MY PRINTER";
JniPrinterStatus jps = new JniPrinterStatus();
System.out.println("PRINTER NAME = " + printer);
status = jps.GetStatus(printer);
if (status == -1) {
System.out.println("status = -1");
}
else if (status == 0) {
System.out.println("status = NORMAL");
}
else if ((status & 0x00000080) != 0) {
System.out.println("status = PRINTER_STATUS_OFFLINE");
}
else if ((status & 0x00400000) != 0) {
System.out.println("status = PRINTER_STATUS_DOOR_OPEN");
}
else if ((status & 0x00000010) != 0) {
System.out.println("status = PRINTER_STATUS_PAPER_OUT");
}
else if ((status & 0x00000800) != 0) {
System.out.println("status = PRINTER_STATUS_OUTPUT_BIN_FULL");
}
else if ((status & 0x00000040) != 0) {
System.out.println("status = PRINTER_STATUS_PAPER_PROBLEM");
}
}
}
我用Eclipse来运行代码,我把dll库放在文件夹project里面,报错
PRINTER NAME = MY PRINTER
Exception in thread "main" java.lang.UnsatisfiedLinkError: com.printer.test.JniPrinterStatus.GetStatus(Ljava/lang/String;)I
at com.printer.test.JniPrinterStatus.GetStatus(Native Method)
at com.printer.test.TestSample.main(TestSample.java:10)
如果我将源代码从包 "com.printer.test" 移至默认包,代码将运行并显示:
PRINTER NAME = MY PRINTER
status = -1
我不知道这怎么可能。如果我编译并 运行 命令提示符下的代码,而没有包,它就可以工作。
问题出在哪里?
谢谢
抱歉,其实我想写评论,但由于我的声誉仍然很低,所以我必须尝试猜测一个答案。
- 应该不需要重新编译 dll - 它只是一些要调用的本机代码。
- class加载dll的java包应该也没有什么区别。
您必须注意您的系统架构:64 位 dll 文件在 32 位 JRE 中会失败,反之亦然。确保您的 JRE 架构与 dll 架构匹配。
另一件需要考虑的事情是你的工作目录。 Eclipse 使用的工作目录可能与您 运行 从控制台编程时使用的工作目录不同。
最后但同样重要的是,请查看您的 java.library.path 变量。
此页面也可能有帮助:https://www.chilkatsoft.com/java-loadLibrary-Windows.asp
我涵盖了所有细节。
来自 javadoc class UnsatisfiedLinkError
...
Thrown if the Java Virtual Machine cannot find an appropriate
native-language definition of a method declared native.
这意味着找不到函数 Java_com_printer_test_JniPrinterStatus_GetStatus
。
classjava.lang.System
中的方法loadLibrary
通常搜索[系统]属性"java.library.path"中列出的目录。对于Windows机器,这个属性的值一般是PATH环境变量的值
所以我建议在您的代码中打印出 属性 的值,以查看它是否包含包含您的 DLL 的目录。如果不是,那么您需要通过重新定位 DLL 或更改 PATH 环境变量或使用 -Djava.library.path=...
选项启动 java 程序来修复该问题。之后,您需要检查本机方法的签名。 Dependency Walker 是我在工作中用来完成此任务的工具。
编辑
有re-read你的问题,我觉得我没有准确回答你的问题,所以让我补充...
Eclipse 的默认行为是将资源文件(如 DLL)复制到输出文件夹。因此,如果您将 DLL 放在文件夹 src\com\printer\test
中,它将复制到文件夹 bin\com\printer\test
。我的猜测是当前的工作目录,即 .
在你的 "java.library.path" 中,这就是当你的 java 代码在默认包中时它起作用的原因。
Java classes 的预期包是 JNI 库中的 hard-coded。在您的情况下,它是默认包。
让我详细说明一下。当在 JNI 库中实现本机方法时,必须创建一个 public C 函数,其名称格式如下:
Java_com_mypackage_MyClass_MyMethod
换句话说,JNI 库无法为任意包中的 classes 提供方法 - 只能为 JNI 库作者考虑的包中的 classes 提供方法。
在您的情况下,这是默认设置。 C 函数变为 Java_JniPrinterStatus_GetStatus
。如果您调用 class MyPrinterStatus
,或将其放入包 com.foobar
,JNI run-time 将无法将 C 函数与声明的 [=24= 相关联] 本机方法。这就是 JNI 的设计方式。
我在加载打印机 dll 时遇到问题。我有打印机制造商 (JniPrinterStatusLib.dll) 提供的 dll 文件。我按照打印机制造商的建议编写了代码。代码是:
package com.printer.test
public class JniPrinterStatus {
static{
System.loadLibrary("JniPrinterStatusLib");
}
public native int GetStatus(String printer);
}
package com.printer.test
public class TestSample {
public static void main(String[] args) {
int status;
String printer = "MY PRINTER";
JniPrinterStatus jps = new JniPrinterStatus();
System.out.println("PRINTER NAME = " + printer);
status = jps.GetStatus(printer);
if (status == -1) {
System.out.println("status = -1");
}
else if (status == 0) {
System.out.println("status = NORMAL");
}
else if ((status & 0x00000080) != 0) {
System.out.println("status = PRINTER_STATUS_OFFLINE");
}
else if ((status & 0x00400000) != 0) {
System.out.println("status = PRINTER_STATUS_DOOR_OPEN");
}
else if ((status & 0x00000010) != 0) {
System.out.println("status = PRINTER_STATUS_PAPER_OUT");
}
else if ((status & 0x00000800) != 0) {
System.out.println("status = PRINTER_STATUS_OUTPUT_BIN_FULL");
}
else if ((status & 0x00000040) != 0) {
System.out.println("status = PRINTER_STATUS_PAPER_PROBLEM");
}
}
}
我用Eclipse来运行代码,我把dll库放在文件夹project里面,报错
PRINTER NAME = MY PRINTER
Exception in thread "main" java.lang.UnsatisfiedLinkError: com.printer.test.JniPrinterStatus.GetStatus(Ljava/lang/String;)I
at com.printer.test.JniPrinterStatus.GetStatus(Native Method)
at com.printer.test.TestSample.main(TestSample.java:10)
如果我将源代码从包 "com.printer.test" 移至默认包,代码将运行并显示:
PRINTER NAME = MY PRINTER
status = -1
我不知道这怎么可能。如果我编译并 运行 命令提示符下的代码,而没有包,它就可以工作。
问题出在哪里?
谢谢
抱歉,其实我想写评论,但由于我的声誉仍然很低,所以我必须尝试猜测一个答案。
- 应该不需要重新编译 dll - 它只是一些要调用的本机代码。
- class加载dll的java包应该也没有什么区别。
您必须注意您的系统架构:64 位 dll 文件在 32 位 JRE 中会失败,反之亦然。确保您的 JRE 架构与 dll 架构匹配。
另一件需要考虑的事情是你的工作目录。 Eclipse 使用的工作目录可能与您 运行 从控制台编程时使用的工作目录不同。
最后但同样重要的是,请查看您的 java.library.path 变量。
此页面也可能有帮助:https://www.chilkatsoft.com/java-loadLibrary-Windows.asp 我涵盖了所有细节。
来自 javadoc class UnsatisfiedLinkError
...
Thrown if the Java Virtual Machine cannot find an appropriate native-language definition of a method declared native.
这意味着找不到函数 Java_com_printer_test_JniPrinterStatus_GetStatus
。
classjava.lang.System
中的方法loadLibrary
通常搜索[系统]属性"java.library.path"中列出的目录。对于Windows机器,这个属性的值一般是PATH环境变量的值
所以我建议在您的代码中打印出 属性 的值,以查看它是否包含包含您的 DLL 的目录。如果不是,那么您需要通过重新定位 DLL 或更改 PATH 环境变量或使用 -Djava.library.path=...
选项启动 java 程序来修复该问题。之后,您需要检查本机方法的签名。 Dependency Walker 是我在工作中用来完成此任务的工具。
编辑 有re-read你的问题,我觉得我没有准确回答你的问题,所以让我补充...
Eclipse 的默认行为是将资源文件(如 DLL)复制到输出文件夹。因此,如果您将 DLL 放在文件夹 src\com\printer\test
中,它将复制到文件夹 bin\com\printer\test
。我的猜测是当前的工作目录,即 .
在你的 "java.library.path" 中,这就是当你的 java 代码在默认包中时它起作用的原因。
Java classes 的预期包是 JNI 库中的 hard-coded。在您的情况下,它是默认包。
让我详细说明一下。当在 JNI 库中实现本机方法时,必须创建一个 public C 函数,其名称格式如下:
Java_com_mypackage_MyClass_MyMethod
换句话说,JNI 库无法为任意包中的 classes 提供方法 - 只能为 JNI 库作者考虑的包中的 classes 提供方法。
在您的情况下,这是默认设置。 C 函数变为 Java_JniPrinterStatus_GetStatus
。如果您调用 class MyPrinterStatus
,或将其放入包 com.foobar
,JNI run-time 将无法将 C 函数与声明的 [=24= 相关联] 本机方法。这就是 JNI 的设计方式。