厂家的DLL函数的原型:char * GetErrMsgA(void);
int GetMyID(char *myid);
我的思路是这样的:使用Swig,JNI对厂家的dll进行封装,然后用Vc 6.0编译产生Java可以直接使用的dll(Test.dll),最后在JAVA里调用厂家DLL里面的函数。当函数有Char * 类型的参数,遇到了问题JAVA中的代码:
System.loadLibrary("Test"); //Test.dll就是新编译产生的dll
String ErrMsg = "###";
ErrMsg = Test.GetErrMsgA();
System.out.println(ErrMsg); //这个正常,可以打印出dll返回的ErrMsg数据
String MyID = "***";
Test.GetMyID(MyID);
System.out.println(MyID); //这个地方就出问题了,一直打印的是"***";
现在可以肯定,已经成功调用厂家动态库里面的GetMyID函数,并且在厂家他们自己的日志里也能看到对应的记录和MyID,问题在于JAVA获取不到这个MyID,如何解决?
测试了其它dll里的函数,如果有参数是Char *类型,都有这个问题,如果函数返回值是Char *,那一切正常。刚开始使用JAVA,不是很熟,请指点
int GetMyID(char *myid);
我的思路是这样的:使用Swig,JNI对厂家的dll进行封装,然后用Vc 6.0编译产生Java可以直接使用的dll(Test.dll),最后在JAVA里调用厂家DLL里面的函数。当函数有Char * 类型的参数,遇到了问题JAVA中的代码:
System.loadLibrary("Test"); //Test.dll就是新编译产生的dll
String ErrMsg = "###";
ErrMsg = Test.GetErrMsgA();
System.out.println(ErrMsg); //这个正常,可以打印出dll返回的ErrMsg数据
String MyID = "***";
Test.GetMyID(MyID);
System.out.println(MyID); //这个地方就出问题了,一直打印的是"***";
现在可以肯定,已经成功调用厂家动态库里面的GetMyID函数,并且在厂家他们自己的日志里也能看到对应的记录和MyID,问题在于JAVA获取不到这个MyID,如何解决?
测试了其它dll里的函数,如果有参数是Char *类型,都有这个问题,如果函数返回值是Char *,那一切正常。刚开始使用JAVA,不是很熟,请指点
java调用dll最棘手的就是回调部分,回调的原理就是操作同一块内存区。这个问题你摸透了,剩下的就都不是问题了。
现在卡在获取char *这块了,等这个弄完了后面也要用到回调的。因为char * GetErrMsgA(void);这个函数的返回数据用JAVA可以获取,我试着改写JNI代码,把int GetMyID(char *myid)里面的char *myid在JNI里面就直接返回给JAVA,而不是返回int,这样JAVA也是可以获取到myid数据的,但有两个缺点:
1:JAVA里使用的函数结构和原型不一致 Test.GetMyID(MyID)变成返回String,而不是原来的int
2:如果dll里有函数同时返回多个Char *,也比较麻烦。比如int GetInfo(char *myid,char * mySerial,char * logStr );其中myid,mySerial,logStr 都是dll要返回的数据
{
jclass strClass = env->FindClass("Ljava/lang/String;");
jmethodID ctorID = env->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");
jbyteArray bytes = env->NewByteArray(strlen(pat));
env->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*)pat);
jstring encoding = env->NewStringUTF("utf-8");
return (jstring)env->NewObject(strClass, ctorID, bytes, encoding);
}
我学习JNI用的转换方法。看你有用么?
String MyID = "***";
Test.GetMyID(MyID);
System.out.println(MyID); //这个地方就出问题了,一直打印的是"***";这样?
你这方法有返回值,你打印MyID干嘛? 又没变化。我光想着自以为是你的问题去了。没注意你实际什么问题这个对么?
int GetMyID(char *myid);这个函数的功能是获取一个字符串,myid是存放这个字符串的首地址,整个函数的返回值是int类型,表示调用有没有成功,我是需要在java里面调用这个函数,获取到这个字符串ID
谢谢hwndid的回复,jni文档说明char *对应是jstring类型,在java里对应string。换成byte数组能具体说明一下吗
我是想尽量在java里保持本地方法的结构,因为方便其他人查看和调试。JNA我也测试过,也找到了解决这个char *类型传递的方法。但是因为本地dll里的方法很多,真的很多,还涉及到回调,数据结构等等数据类型,仅仅写几个函数结构描述问题不大,但要手动给每个本地方法写对应的JNA结构描述,这个是很费事的事情,而且还容易出错。我试着用JNAerator产生所有本地方法的JNA接口,但是导入JAVA后,调用本地方法一直不成功。在JNI环境下,是用swig自动生成所有本地方法的JNI代码,也可以在JAVA里调用成功,但是有这个参数传递的问题
jstring 是 jobject
#define CHECK_EXCEPTION if((*env)->ExceptionCheck(env) == JNI_TRUE) returnint GetMyID(char *myid)
{
char* arr = "098abc";
while (*arr)
{
*(myid++) = *(arr++);
}
*myid = 0;
}JNIEXPORT jint JNICALL Java_JNITest_GetMyID
(JNIEnv *env, jobject this, jobject buff)
{
JNIEnv _env = *env;
jint len = _env->GetArrayLength(env, buff);
CHECK_EXCEPTION 0;
jbyte p[len];
int r = GetMyID(p);
if (!r)
{
_env->SetByteArrayRegion(env, buff, 0, len, p);
CHECK_EXCEPTION 0;
}
return r;
}
public native int GetMyID(byte[] buff); public static void main(String[] args) throws Exception {
JNITest t = new JNITest();
byte[] buff = new byte[1000];
if (t.GetMyID(buff) == 0) {
String str = null;
for (int i = 0; i < buff.length; i++) {
if (buff[i] == 0) {
str = new String(buff, 0, i);
break;
}
}
System.out.println(str);
}
}
按照abc130314的回复,java 已经可以获取到 char*数据,谢谢
http://blog.csdn.net/hemowolf/article/details/6924856
http://blog.csdn.net/hemowolf/article/details/6925155
http://blog.csdn.net/hemowolf/article/details/6925155虽然是在 linux 下的,但是原理没什么不一样