简体   繁体   English

Ecplise Java JNI,java.lang.UnsatisfiedLinkError加载dll

[英]Ecplise Java JNI, java.lang.UnsatisfiedLinkError loading dll

I'm having a problem with loading printer dll. 我在加载打印机dll时遇到问题。 I have a dll file from the printer manufacturer (JniPrinterStatusLib.dll). 我有一个打印机制造商的dll文件(JniPrinterStatusLib.dll)。 I wrote code like printer manufacturer suggested. 我写了像打印机制造商建议的代码。 The code is: 代码是:

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");
        }
   }
}

I used Eclipse to run the code, i put the dll library in the folder project and the error is 我用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)

If i move the source from the package "com.printer.test" to default package the code works and show: 如果我将源代码“com.printer.test”移动到默认包,代码将工作并显示:

PRINTER NAME = MY PRINTER
status = -1

I don't know how it's possible. 我不知道怎么可能。 If i compile and run the code from command prompt without package it works. 如果我从命令提示符编译并运行代码而没有包它可以工作。

Where is the problem? 问题出在哪儿?

Thank you 谢谢

Sorry, actually I wanted to write a comment, but as I'm still low on reputation, I have to try and guess an answer. 对不起,实际上我想写评论,但由于我的声誉仍然很低,我不得不尝试猜测答案。

  • There should be no need to recompile the dll - it's just some native code to be invoked. 应该没有必要重新编译DLL - 它只是一些要调用的本机代码。
  • The java package of the class loading the dll should not make a difference, either. 加载dll的类的java包也不应该有所作为。

You have to take care about your system architecture: A 64-bit dll file will fail in a 32-bit JRE and vice versa. 您必须注意您的系统架构:64位DLL文件将在32位JRE中失败,反之亦然。 Make sure, your JRE architecture matches the dll architecture. 确保您的JRE架构与dll架构相匹配。

Another thing to take into account is your working directory. 另一件需要考虑的事情是你的工作目录。 Eclipse may use a working directory different from what you used when you ran you program from console. Eclipse可能使用的工作目录与从控制台运行程序时使用的工作目录不同。

Last but not least, please have a look at your java.library.path variable. 最后但并非最不重要的,请查看您的java.library.path变量。

This page might also help: https://www.chilkatsoft.com/java-loadLibrary-Windows.asp I covers all the details. 此页面也可能有所帮助: https//www.chilkatsoft.com/java-loadLibrary-Windows.asp我将介绍所有细节。

From the javadoc for class UnsatisfiedLinkError ... 来自类UnsatisfiedLinkErrorjavadoc ...

Thrown if the Java Virtual Machine cannot find an appropriate native-language definition of a method declared native. 如果Java虚拟机无法找到声明为native的方法的适当本机语言定义,则抛出该异常。

That means that function Java_com_printer_test_JniPrinterStatus_GetStatus is not found. 这意味着找不到函数Java_com_printer_test_JniPrinterStatus_GetStatus

Method loadLibrary in class java.lang.System usually searches the directories listed in the [System] property "java.library.path". java.lang.System方法loadLibrary通常搜索[System]属性“java.library.path”中列出的目录。 For Windows machines, the value of this property is generally the value of the PATH environment variable. 对于Windows机器,此属性的值通常是PATH环境变量的值。

So I suggest printing out the value of that property in your code to see whether it includes the directory containing your DLL. 因此,我建议在代码中打印出该属性的值,以查看它是否包含包含DLL的目录。 If it doesn't then you need to fix that, either by relocating the DLL or changing the PATH environment variable or launching your java program with the -Djava.library.path=... option. 如果没有,则需要通过重新定位DLL或更改PATH环境变量或使用-Djava.library.path=...选项启动java程序来解决此问题。 After that you need to check the signature of the native method. 之后,您需要检查本机方法的签名。 Dependency Walker is a tool I use at my work to accomplish this. Dependency Walker是我在工作中用来完成此任务的工具。

EDIT Having re-read your question, I feel I did not accurately address your question, so let me add... 编辑重新阅读您的问题,我觉得我没有准确地解决您的问题,所以让我补充一下......

The default behaviour of Eclipse is to copy resource files, like DLLs, to the output folder. Eclipse的默认行为是将资源文件(如DLL)复制到输出文件夹。 So if you put your DLL in folder src\\com\\printer\\test , it will get copie to folder bin\\com\\printer\\test . 因此,如果您将DLL放在文件夹src\\com\\printer\\test ,它将获得复制到bin\\com\\printer\\test文件夹。 My guess is that the current, working directory, ie . 我的猜测是当前的工作目录,即. is in your "java.library.path" which is why it works when your java code is in the default package. 在你的“java.library.path”中,这就是当你的java代码在默认包中时它可以工作的原因。

The expected package of the Java classes is hard-coded in the JNI library. 预期的Java类包在JNI库中进行了硬编码。 In your case, it's the default package. 在您的情况下,它是默认包。

Let me expand on that. 让我扩展一下。 When one implements a native method in a JNI library, one has to create a public C function with a name in the following format: 当在JNI库中实现本机方法时,必须使用以下格式的名称创建公共C函数:

Java_com_mypackage_MyClass_MyMethod

In other words, the JNI library can't provide methods for the classes in arbitrary packages - only for classes in packages that the JNI library authors had in mind. 换句话说,JNI库无法为任意包中的类提供方法 - 仅适用于JNI库作者所考虑的包中的类。

In your case, it's the default one. 在你的情况下,它是默认的。 The C function goes Java_JniPrinterStatus_GetStatus . C函数转到Java_JniPrinterStatus_GetStatus If you call your class MyPrinterStatus , or place it into package com.foobar , the JNI run-time won't be able to associate the C function with the declared Java native method. 如果调用类MyPrinterStatus ,或将其放入com.foobar包中,则JNI运行时将无法将C函数与声明的Java本机方法相关联。 That's just how JNI was designed. 这就是JNI的设计方式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM