如何在 Java 程序中调用 DLL 中的方法
我正在尝试使用JNA调用DLL中的方法。到目前为止,已使用
Runtime.getRuntime().load("myworkspace/test.dll");
此 dll 包含我需要访问的方法。如何在我的Java文件中执行DLL中存在的方法。我是否创建 DLL 的对象或某些内容,然后在点运算符后获取方法名称。
我正在尝试使用JNA调用DLL中的方法。到目前为止,已使用
Runtime.getRuntime().load("myworkspace/test.dll");
此 dll 包含我需要访问的方法。如何在我的Java文件中执行DLL中存在的方法。我是否创建 DLL 的对象或某些内容,然后在点运算符后获取方法名称。
从源头:
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);
}
}
加载 DLL 只是最简单的步骤。
由于从Java调用DLL的方法并非易事,因此此答案只是从DLL调用函数所必须执行的提示的摘要。整个故事将填满一本书。事实上,有几本关于JNI(Java Native Interface)的书。
要调用本机库中的函数,您必须使用 java 关键字 将 java 类中的方法声明为本机方法。此方法的声明不得具有正文。native
从 DLL 导出的函数的名称必须与以下模式匹配:where 是声明本机方法的类的名称。Java_classname_methodname
classname
methodname
例如,如果在类 MyClass 中声明一个本机方法,则 DLL 函数的名称将为:private native void sayHello()
Java_MyClass_sayHello
还要记住,该函数必须从 DLL 中导出,这些调用约定 JNIEXPORT 和 JNICALL 是在 JDK 附带的头文件 jni.h 中定义的(请参阅 include 文件夹)
要从 Java 调用的 DLL 的每个函数还必须有两个“隐藏”参数作为第一个参数。 是指向调用 JVM 的指针,它允许您回调到 JVM 中,并且是从中调用方法的对象。(JNIEnv *env, jobject obj)
env
obj
因此,在我们的示例中,DLL 方法的整个定义将是:JNIEXPORT void JNICALL Java_MyClass_sayHello(JNIEnv *, jobject);
由于 JNI 的这些限制,必须为代码指定从代码调用的 DLL。要使用 Java 中的任意 DLL,您通常必须使用 JNI 的约定创建一个自适应 DLL,该 DLL 本身加载“目标”DLL 并调用所需的函数。
要为适配器 DLL 生成正确的标头,可以使用 JDK 附带的 javah 工具。此工具将生成要从 Java 代码实现的标头。
有关更多信息,JNI 的文档将涵盖有关从本机代码与 JVM 交互的所有问题。http://docs.oracle.com/javase/7/docs/technotes/guides/jni/