如何使用JAVA调用C++编写的Dll函数,Char *指针

e2214 2012-10-22 12:04:19
厂家的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,不是很熟,请指点
...全文
1329 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
abc130314 2012-10-24
  • 打赏
  • 举报
回复
java里面String是不可变的。所以把String传入再改变值是不允许的。
jstring 是 jobject
#define CHECK_EXCEPTION if((*env)->ExceptionCheck(env) == JNI_TRUE) return

int 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);
}
}
e2214 2012-10-24
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 hwndid 的回复:]

我最近在学JNA,JNA比JNI好用些,你可以试一试
[/Quote]

我是想尽量在java里保持本地方法的结构,因为方便其他人查看和调试。

JNA我也测试过,也找到了解决这个char *类型传递的方法。但是因为本地dll里的方法很多,真的很多,还涉及到回调,数据结构等等数据类型,仅仅写几个函数结构描述问题不大,但要手动给每个本地方法写对应的JNA结构描述,这个是很费事的事情,而且还容易出错。我试着用JNAerator产生所有本地方法的JNA接口,但是导入JAVA后,调用本地方法一直不成功。

在JNI环境下,是用swig自动生成所有本地方法的JNI代码,也可以在JAVA里调用成功,但是有这个参数传递的问题
小灰狼 2012-10-24
  • 打赏
  • 举报
回复
可以参考一下额以前写的博客
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 下的,但是原理没什么不一样
e2214 2012-10-24
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 的回复:]

java里面String是不可变的。所以把String传入再改变值是不允许的。
jstring 是 jobject
C/C++ code
#define CHECK_EXCEPTION if((*env)->ExceptionCheck(env) == JNI_TRUE) return

int GetMyID(char *myid)
{
char* arr = "098abc";……
[/Quote]


对java不熟,原来String是不能变的,现在知道怎么回事了
按照abc130314的回复,java 已经可以获取到 char*数据,谢谢
我百了个度 2012-10-23
  • 打赏
  • 举报
回复
我最近在学JNA,JNA比JNI好用些,你可以试一试
我百了个度 2012-10-23
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 的回复:]
引用 6 楼 的回复:

返回值用byte数组接收试一试


谢谢hwndid的回复,jni文档说明char *对应是jstring类型,在java里对应string。换成byte数组能具体说明一下吗
[/Quote]
在调用接口中声明方法的返回类型为byte数组
e2214 2012-10-23
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 的回复:]

返回值用byte数组接收试一试
[/Quote]

谢谢hwndid的回复,jni文档说明char *对应是jstring类型,在java里对应string。换成byte数组能具体说明一下吗
e2214 2012-10-23
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 的回复:]

好吧我有个问题 楼主代码看不懂啊?你为什么要


String MyID = "***";
Test.GetMyID(MyID);
System.out.println(MyID); //这个地方就出问题了,一直打印的是"***";

这样?
你这方法有返回值,你打印MyID干嘛? 又没变化。。。。我光想着自以为是你的问题去了。没注意你实际什么问题。。。这个对么?
引……
[/Quote]


dll里的原型
int GetMyID(char *myid);

这个函数的功能是获取一个字符串,myid是存放这个字符串的首地址,整个函数的返回值是int类型,表示调用有没有成功,我是需要在java里面调用这个函数,获取到这个字符串ID
e2214 2012-10-22
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 的回复:]

具体的我也记不清楚了(有快2年的时间没碰过它了),你自己多试试。
java调用dll最棘手的就是回调部分,回调的原理就是操作同一块内存区。这个问题你摸透了,剩下的就都不是问题了。
[/Quote]

现在卡在获取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要返回的数据
zxhcloth 2012-10-22
  • 打赏
  • 举报
回复
具体的我也记不清楚了(有快2年的时间没碰过它了),你自己多试试。
java调用dll最棘手的就是回调部分,回调的原理就是操作同一块内存区。这个问题你摸透了,剩下的就都不是问题了。
e2214 2012-10-22
  • 打赏
  • 举报
回复
谢谢zxhcloth的回复,我感觉像是在是对不同的内存在做处理,所以java一直获取不到真正的数据。关于Reference能不能给个简单使用例子,谢谢
zxhcloth 2012-10-22
  • 打赏
  • 举报
回复
这个涉及到传值的问题,思路就是java和C++访问同一块内存区域,你用Reference应该可以。
akemi_homura 2012-10-22
  • 打赏
  • 举报
回复
好吧我有个问题 楼主代码看不懂啊?你为什么要


String MyID = "***";
Test.GetMyID(MyID);
System.out.println(MyID); //这个地方就出问题了,一直打印的是"***";

这样?
你这方法有返回值,你打印MyID干嘛? 又没变化。。。。我光想着自以为是你的问题去了。没注意你实际什么问题。。。这个对么?
[Quote=引用 8 楼 的回复:]
好吧。我没看清楼主的问题。你那个参数传递 可以用指针么?这个可以么?求教。个人觉得不应该是传String过去然后转换为char*的么?

引用 7 楼 的回复:
这个不应该是返回String类型么?

C/C++ code

jstring stoJstring(JNIEnv* env, const char* pat)
{
jclass strClass = env->Find……
[/Quote]
akemi_homura 2012-10-22
  • 打赏
  • 举报
回复
好吧。我没看清楼主的问题。你那个参数传递 可以用指针么?这个可以么?求教。个人觉得不应该是传String过去然后转换为char*的么?
[Quote=引用 7 楼 的回复:]
这个不应该是返回String类型么?

C/C++ code

jstring stoJstring(JNIEnv* env, const char* pat)
{
jclass strClass = env->FindClass("Ljava/lang/String;");
jmethodID ctorID = env->GetMethodID(strClass, ……
[/Quote]
akemi_homura 2012-10-22
  • 打赏
  • 举报
回复
这个不应该是返回String类型么?
jstring stoJstring(JNIEnv* env, const char* pat)
{
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用的转换方法。看你有用么?
我百了个度 2012-10-22
  • 打赏
  • 举报
回复
返回值用byte数组接收试一试
e2214 2012-10-22
  • 打赏
  • 举报
回复
不要沉,寻求解决方法

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧