How to call a method in DLL in a Java program

107,078

Solution 1

From the source:

package jnahelloworldtest;

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.NativeLong;
import com.sun.jna.Platform;
import com.sun.jna.*;

/** Simple example of native library declaration and usage. */
public class Main {
    public interface simpleDLL extends Library {
        simpleDLL INSTANCE = (simpleDLL) Native.loadLibrary(
            (Platform.isWindows() ? "simpleDLL" : "simpleDLLLinuxPort"), simpleDLL.class);
        // it's possible to check the platform on which program runs, for example purposes we assume that there's a linux port of the library (it's not attached to the downloadable project)
        byte giveVoidPtrGetChar(Pointer param); // char giveVoidPtrGetChar(void* param);
        int giveVoidPtrGetInt(Pointer param);   //int giveVoidPtrGetInt(void* param);
        int giveIntGetInt(int a);               // int giveIntGetInt(int a);
        void simpleCall();                      // void simpleCall();
    }

    public static void main(String[] args) {

        simpleDLL sdll = simpleDLL.INSTANCE;

        sdll.simpleCall();  // call of void function

        int a = 3;
        int result1 = sdll.giveIntGetInt(a);  // calling function with int parameter&result
        System.out.println("giveIntGetInt("+a+"): " + result1);

        String testStr = "ToBeOrNotToBe";
        Memory mTest = new Memory(testStr.length()+1);  // '+1' remember about extra byte for \0 character!
        mTest.setString(0, testStr);
        String testReturn = mTest.getString(0); // you can see that String got properly stored in Memory object
        System.out.println("String in Memory:"+testReturn);

        Memory intMem = new Memory(4);  // allocating space
        intMem.setInt(0, 666); // setting allocated memory to an integer
        Pointer intPointer = intMem.getPointer(0);

        int int1 = sdll.giveVoidPtrGetInt(Pointer.NULL); // passing null, getting default result
        System.out.println("giveVoidPtrGetInt(null):" + int1); 
        int int2 = sdll.giveVoidPtrGetInt(intMem); // passing int stored in Memory object, getting it back
       //int int2 = sdll.giveVoidPtrGetInt(intPointer);  causes JVM crash, use memory object directly!
        System.out.println("giveVoidPtrGetInt(666):" + int2);

        byte char1 = sdll.giveVoidPtrGetChar(Pointer.NULL);  // passing null, getting default result
        byte char2 = sdll.giveVoidPtrGetChar(mTest);        // passing string stored in Memory object, getting first letter

        System.out.println("giveVoidPtrGetChar(null):" + (char)char1);
        System.out.println("giveVoidPtrGetChar('ToBeOrNotToBe'):" + (char)char2);

    }
}

Solution 2

Loading the DLL is only the easiest step.

As it is not really trivial to call a method of a DLL from Java this answer is only a summary of hints what you have to do to call a function from a DLL. The whole story would fill a book. And in fact there are several books about JNI (Java Native Interface).

To call a function in a native library you have to declare a method in your java class as native with the java keyword native. The declaration of this method must not have a body.

The name of the function exported from your DLL must match the following pattern: Java_classname_methodname where classname is the name of the class where you declared the native method methodname.

For example if you declare a native method private native void sayHello() in your class MyClass the name of the DLL's function would be: Java_MyClass_sayHello

Also keep in mind that the function must be exported from the DLL with the correct calling conventions JNIEXPORT and JNICALL which are defined in the header file jni.h that comes with your JDK (see include folder)

Every function of a DLL to be called from Java also must have two "hidden" arguments as first parameters (JNIEnv *env, jobject obj). env is a pointer to the calling JVM which allows you callback into the JVM and obj is the object from which the method was called.

So the whole definition of the DLL's method in our example would be: JNIEXPORT void JNICALL Java_MyClass_sayHello(JNIEnv *, jobject);

Due to these restrictions of JNI a DLL called from your code must be specifially made for your code. To use an arbitrary DLL from Java you usually have to create an adapting DLL with the conventions of JNI that itself loads the "target" DLL and calls the required functions.

To generate the correct headers for your adapter DLL you can use the tool javah shipped with the JDK. This tool will generate the headers to be implemented from your Java code.

For further information the documentation of JNI will cover all questions about interaction with the JVM from native code. http://docs.oracle.com/javase/7/docs/technotes/guides/jni/

Share:
107,078
Vivek
Author by

Vivek

Updated on September 30, 2020

Comments

  • Vivek
    Vivek over 3 years

    I am trying to call a method in a DLL using JNA. So far have loaded the DLL using

    Runtime.getRuntime().load("myworkspace/test.dll");
    

    This dll contaings a method that I need to access. How can I execute the method present in DLL in my Java file. Do I create an object or something of the DLL and then get the method name after the dot operator.

  • Tom Blodget
    Tom Blodget almost 10 years
    The question is about JNA. (JNA uses JNI under the covers.)
  • Lealo
    Lealo over 6 years
    Is there like an api for handling dll in java - for instance where you can loop through all the possible command (methods) to see what the dll contains?
  • Ejaz
    Ejaz over 5 years
    if we have the methods created inside a class in my .dll file, then how do we access these methods