JNI问题:在Java中调用使用第三方DLL的dll
我想要使用epanet.dll,所以为了调用它我必须创建我的桥dll。JNI问题:在Java中调用使用第三方DLL的dll
我创建的Java类
public class Epanet {
//Native method declaration
native int ENopen(String fileInput, String fileOutput, String optBinFileOut);
native int ENsaveinpfile(String file);
native int ENclose();
native int ENsolveH();
native int ENsaveH();
native int ENopenH();
//native int ENrunQ(long *);
//Load the library
static {
System.loadLibrary("epanet2");
}
}
然后JAVAH德.h文件中创建
/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
/* Header for class Epanet */
#ifndef _Included_Epanet
#define _Included_Epanet
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jint JNICALL Java_Epanet_ENopen (JNIEnv *, jobject, jstring, jstring, jstring);
JNIEXPORT jint JNICALL Java_Epanet_ENsaveinpfile (JNIEnv *, jobject, jstring);
JNIEXPORT jint JNICALL Java_Epanet_ENclose (JNIEnv *, jobject);
JNIEXPORT jint JNICALL Java_Epanet_ENsolveH (JNIEnv *, jobject);
.....
.....
#ifdef __cplusplus
}
#endif
#endif
然后我创建的应该叫epanet2 DLL .c文件
#include "jni.h"
#include <stdio.h>
#include "myDll.h"
#include "epanet2.h"
JNIEXPORT jint JNICALL Java_Epanet_ENopen
(JNIEnv *env, jobject obj, jstring fichIn, jstring fichOut, jstring fichBin){
const char *CStringFichIn = (*env)->GetStringUTFChars(env,fichIn,NULL);
const char *CStringFichOut = (*env)->GetStringUTFChars(env,fichOut,NULL);
const char *CStringFichBin = (*env)->GetStringUTFChars(env,fichBin,NULL);
int result;
result = ENepanet (CStringFichIn, CStringFichOut, CStringFichBin, NULL);
(*env)->ReleaseStringUTFChars(env, fichIn, CStringFichIn);
(*env)->ReleaseStringUTFChars(env, fichOut, CStringFichOut);
(*env)->ReleaseStringUTFChars(env, fichBin, CStringFichBin);
return result;
}
JNIEXPORT jint JNICALL Java_Epanet_ENsaveinpfile
(JNIEnv *env, jobject object, jstring fichOut){
const char *CStringFichOut;
int result;
CStringFichOut = (*env)->GetStringUTFChars(env,fichOut,NULL);
result = ENsaveinpfile (CStringFichOut);
return result;
}
JNIEXPORT jint JNICALL Java_Epanet_ENclose
(JNIEnv *env, jobject object){
int result;
result = ENclose();
return result;
}
JNIEXPORT jint JNICALL Java_Epanet_ENsolveH
(JNIEnv *env, jobject object){
int result;
result = ENsolveH();
return result;
}
JNIEXPORT jint JNICALL Java_Epanet_ENsaveH
(JNIEnv *env, jobject object){
int result;
result = ENsaveH();
return result;
}
JNIEXPORT jint JNICALL Java_Epanet_ENopenH
(JNIEnv *env, jobject obj){
int result;
result = ENopenH();
return result;
}
而且然后编译。 Visual C++创建我的dll。我在system32中复制了这两个DLL。然后我尝试使用我的dll。
public class NewClass {
private native void ENopen(String f1, String f2, String f3);
public static void main(String[] args) {
System.out.println("started");
new NewClass().ENopen("C:\\Red2.inp", "C:\\salaida.txt", "");
System.out.println("finished");
}
static {
System.loadLibrary("myDll");
}
}
我得到这个错误:
started
Exception in thread "main" java.lang.UnsatisfiedLinkError: NewClass.epanet(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String)V
at NewClass.epanet(Native Method)
at NewClass.main(NewClass.java:18) Java Result: 1
如果我删除我得到的错误说,它不能找到库,以便有问题的地方图书馆。我必须说,一个朋友给了我他的DLL,但它不适合我。我犯了同样的错误。
任何猜测? 另一个问题是如何调用这个本地方法// native int ENrunQ(long *); ?
那么这就是你给我建议(主要为第二个评论):
我EPANET类加载我的DLL,而不是EPANET DLL(第三方之一)。
public class Epanet {
//Native method declaration
native int ENopen(String fileInput, String fileOutput, String optBinFileOut);
native int ENsaveinpfile(String file);
native int ENclose();
native int ENsolveH();
native int ENsaveH();
native int ENopenH();
//native int ENrunQ(long *);
//Load the library
static {
System.loadLibrary("myDll");
}
}
而我的测试类不应该加载它。实际上,它不应该加载Epanet课程。
public class NewClass {
public static void main(String[] args) {
System.out.println("started");
new Epanet().ENopen("C:\\Red2.inp", "C:\\salida.txt", "");
System.out.println("finished");
}
}
然后我包装DLL应该是这样的:
#include "jni.h"
#include <stdio.h>
#include "myDll.h"
#include "epanet2.h"
JNIEXPORT jint JNICALL Java_Epanet_ENopen
(JNIEnv *env, jobject obj, jstring fichIn, jstring fichOut, jstring fichBin){
const char *CStringFichIn = (*env)->GetStringUTFChars(env,fichIn,NULL);
const char *CStringFichOut = (*env)->GetStringUTFChars(env,fichOut,NULL);
const char *CStringFichBin = (*env)->GetStringUTFChars(env,fichBin,NULL);
int result;
result = ENopen (CStringFichIn, CStringFichOut, CStringFichBin);
(*env)->ReleaseStringUTFChars(env, fichIn, CStringFichIn);
(*env)->ReleaseStringUTFChars(env, fichOut, CStringFichOut);
(*env)->ReleaseStringUTFChars(env, fichBin, CStringFichBin);
return result;
}
还是更喜欢这样的:
#include "jni.h"
#include <stdio.h>
#include <windows.h>
#include "myDll.h"
#include "epanet2.h"
typedef int (* FPTR)(char *, char *, char*);
JNIEXPORT jint JNICALL Java_Epanet_ENopen
(JNIEnv *env, jobject obj, jstring fichIn, jstring fichOut, jstring fichBin){
HMODULE dllHandle = LoadLibrary("epanet2.dll"); // cargar librería
const char *CStringFichIn = (char *)(*env)->GetStringUTFChars(env,fichIn,NULL);
const char *CStringFichOut = (char *) (*env)->GetStringUTFChars(env,fichOut,NULL);
const char *CStringFichBin = (char *)(*env)->GetStringUTFChars(env,fichBin,NULL);
int result;
FPTR ENopen = (FPTR) GetProcAddress(dllHandle, "ENopen");
result = ENopen (CStringFichIn, CStringFichOut, CStringFichBin);
(*env)->ReleaseStringUTFChars(env, fichIn, CStringFichIn);
(*env)->ReleaseStringUTFChars(env, fichOut, CStringFichOut);
(*env)->ReleaseStringUTFChars(env, fichBin, CStringFichBin);
FreeLibrary(dllHandle); // descargar librería
return result;
}
而且,你知道如何调用这个函数?
native int ENrunQ(long *);
我不知道怎么弄长*在MYDLL因为字符串 - >的jstring或者int - > jint但长* - >?或者int * - >?
我的两分钱:
的包装DLL包含了本地方法的实现在你Epanet
类,而不是本地方法你在你的测试代码(注意堆栈跟踪类名)调用。我想你应该使用new Epanet().ENopen("C:\\Red2.inp", "C:\\salaida.txt", "");
来代替。
此外,Epanet
的静态初始化程序应该加载您的DLL,而不是包装的库(如果您的包装程序构建正确,操作系统会照顾它)。
您已经提供了两个Java类的源,并且只提供了一个本地实现。这会让我们更难理解。摆脱NewClass。
你想让你的Epanet Java类在System.loadLibrary()
调用中加载它的本机包装,然后你的包装DLL将自动加载epanet.dll。
在传递一个长*到你的本地代码方面,你不能。创建java-c包装类的技巧是你不能直接调用原始方法!你可以通过一个简单的长时间,但随后对长期所做的任何更改都将丢失。所以你可以将一个可变的java对象传递给你的包装调用,并且改变它或者更简单地使本地方法改变Epanet类的某些状态。
我建议您尝试Dependency Walker以查看是否有其他可能需要的DLL(例如,您可能会错过Microsoft C运行时)。
T这里有个问题。我从头开始重建了所有东西,并且工作正常。我也检查了依赖关系,我的DLL依赖于epanet.dll。 – Alberto 2010-11-22 19:55:48
http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html
I don't know how do get long* in mydll because string -> jstring or int -> jint but long* -> ??? or int* -> ???? that long* -> jlongArray (and int* ->jintArray)
例如: 接受长[]在Java本地方法声明中,JNI,你会看到在jlongArray这样的说法位置。使用GetDoubleArrayElements()将jlongArray转换为jlong *(请参阅doc的链接),jlong是64位(http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/types.html),您可以使用它。
同布尔,INT,Java对象(见变化文档)....
之前先更新 Exception in thread "main" java.lang.UnsatisfiedLinkError: NewClass.epanet(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String)V
我猜你已经犯的错误在编译和/或管理
public class NewClass {
private native void ENopen(String f1, String f2, String f3);
原因:错误应该已经
java.lang.UnsatisfiedLinkError中:的NewClass。 (即使在更新之后),它们并不是方法名称“NewClass.epanet”。这个方法名称为“NewClass.epanet”。
你有检查,你没有错误的DLL躺在你的bin文件夹? – dacwe 2010-11-21 12:33:44
为什么你有两个'loadLibrary(..)'调用?你只有一个界面! – dacwe 2010-11-21 12:37:43
我不知道如何检查是否有错误的DLL。一切正常。 – Alberto 2010-11-21 16:59:31