我在加载打印机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库放入文件夹项目中,错误是
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
我不知道怎么可能。如果我在没有包的情况下从命令提示符下编译并运行代码,那么它将起作用。
问题出在哪里?
谢谢
答案 0 :(得分:0)
抱歉,实际上我想写评论,但是由于我的声誉仍然很低,我必须尝试猜测答案。
您必须注意您的系统体系结构:64位dll文件在32位JRE中将失败,反之亦然。确保您的JRE体系结构与dll体系结构匹配。
要考虑的另一件事是您的工作目录。 Eclipse可能使用的工作目录与从控制台运行程序时使用的目录不同。
最后但并非最不重要的一点,请查看您的java.library.path变量。
此页面也可能有帮助:https://www.chilkatsoft.com/java-loadLibrary-Windows.asp 我涵盖了所有细节。
答案 1 :(得分:0)
来自 javadoc 中的类UnsatisfiedLinkError
...
如果Java虚拟机找不到合适的则抛出 声明为native的方法的native语言定义。
这意味着找不到函数Java_com_printer_test_JniPrinterStatus_GetStatus
。
类loadLibrary
中的方法java.lang.System
通常搜索[System]属性“ java.library.path”中列出的目录。对于Windows计算机,此属性的值通常是PATH环境变量的值。
因此,我建议在代码中打印出该属性的值,以查看其是否包含包含DLL的目录。如果不是,那么您需要通过重新定位DLL或更改PATH环境变量或使用-Djava.library.path=...
选项启动Java程序来解决此问题。之后,您需要检查本机方法的签名。 Dependency Walker是我在工作中用来完成此任务的工具。
编辑 重新阅读了您的问题后,我觉得我没有正确回答您的问题,所以让我补充一下...
Eclipse 的默认行为是将资源文件(如DLL)复制到输出文件夹。因此,如果将DLL放在文件夹src\com\printer\test
中,它将复制到文件夹bin\com\printer\test
中。我的猜测是当前的工作目录,即.
在您的“ java.library.path”中,这就是为什么当Java代码位于默认包中时它可以工作的原因。
答案 2 :(得分:0)
所需的Java类包在JNI库中进行了硬编码。就您而言,这是默认程序包。
让我扩展一下。当在JNI库中实现本机方法时,必须使用以下格式的名称创建一个公共C函数:
Java_com_mypackage_MyClass_MyMethod
换句话说,JNI库不能为任意包中的类提供方法-只能为JNI库作者所想到的包中的类提供方法。
在您的情况下,这是默认值。 C函数转到Java_JniPrinterStatus_GetStatus
。如果调用类MyPrinterStatus
或将其放入包com.foobar
中,则JNI运行时将无法将C函数与声明的Java本机方法相关联。这就是JNI的设计方式。