Ecplise Java JNI, java.lang.UnsatisfiedLinkError loading dll

0

I'm having a problem with loading printer dll. I have a dll file from the printer manufacturer (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

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:

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

java
eclipse
java-native-interface
asked on Stack Overflow May 9, 2019 by Soul85 • edited May 10, 2019 by Soul85

3 Answers

0

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.
  • The java package of the class loading the dll should not make a difference, either.

You have to take care about your system architecture: A 64-bit dll file will fail in a 32-bit JRE and vice versa. Make sure, your JRE architecture matches the dll architecture.

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.

Last but not least, please have a look at your java.library.path variable.

This page might also help: https://www.chilkatsoft.com/java-loadLibrary-Windows.asp I covers all the details.

answered on Stack Overflow May 10, 2019 by Jochen Reinhardt
0

From the javadoc for class UnsatisfiedLinkError...

Thrown if the Java Virtual Machine cannot find an appropriate native-language definition of a method declared native.

That means that function Java_com_printer_test_JniPrinterStatus_GetStatus is not found.

Method loadLibrary in class java.lang.System usually searches the directories listed in the [System] property "java.library.path". For Windows machines, the value of this property is generally the value of the PATH environment variable.

So I suggest printing out the value of that property in your code to see whether it includes the directory containing your 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. 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.

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. So if you put your DLL in folder src\com\printer\test, it will get copie to folder bin\com\printer\test. My guess is that the current, working directory, i.e. . is in your "java.library.path" which is why it works when your java code is in the default package.

answered on Stack Overflow May 10, 2019 by Abra • edited May 10, 2019 by Abra
0

The expected package of the Java classes is hard-coded in the JNI library. 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:

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.

In your case, it's the default one. The C function goes 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. That's just how JNI was designed.

answered on Stack Overflow May 10, 2019 by Seva Alekseyev

User contributions licensed under CC BY-SA 3.0