做一个项目,第三方提供了一系列的C++函数接口。
现在我在用vc.net2005封装这些函数,即自己再定义一个c函数来调用这些接口。
例如:
(1).第三方C++函数接口为 int api_get_logfile(Struct fileinfo tfile),参数是个结构体,且套了另一个结构体:struct fileinfo{
char *fullpath;
int filesize;
int filemode;
struct disnode *tnode;
};struct disnode{
int number;
struct {
int node;
int stat;
}s[number];
};问题:这个结构体我该做一个class来对应吗?怎么写呢?里面有个结构体数组,头痛ing
我做一个JNIEXPORT jint JNICALL Java_N_api_get_logfile(JNIEnv *env, jobject, jobject)的封装函数
怎么把这个class和参数tfile这个结构体对应传递?(2)另一个接口 int api_set_cvltgr(HWND hwnd, UINT ut, LPARAM lm),这个参数对应的java类型是什么?怎么传递?(3)另一个接口 Struct fileinfo *api_get_inifile(char *name), 这个接口返回值是个结构体指针,JNI函数里怎么写啊?小弟初学JNI,java项目也是第一次,很多地方没有头绪,网上的资料都是一些最基本的类型参数,这种复杂的求达人们指教,万分感谢!
现在我在用vc.net2005封装这些函数,即自己再定义一个c函数来调用这些接口。
例如:
(1).第三方C++函数接口为 int api_get_logfile(Struct fileinfo tfile),参数是个结构体,且套了另一个结构体:struct fileinfo{
char *fullpath;
int filesize;
int filemode;
struct disnode *tnode;
};struct disnode{
int number;
struct {
int node;
int stat;
}s[number];
};问题:这个结构体我该做一个class来对应吗?怎么写呢?里面有个结构体数组,头痛ing
我做一个JNIEXPORT jint JNICALL Java_N_api_get_logfile(JNIEnv *env, jobject, jobject)的封装函数
怎么把这个class和参数tfile这个结构体对应传递?(2)另一个接口 int api_set_cvltgr(HWND hwnd, UINT ut, LPARAM lm),这个参数对应的java类型是什么?怎么传递?(3)另一个接口 Struct fileinfo *api_get_inifile(char *name), 这个接口返回值是个结构体指针,JNI函数里怎么写啊?小弟初学JNI,java项目也是第一次,很多地方没有头绪,网上的资料都是一些最基本的类型参数,这种复杂的求达人们指教,万分感谢!
解决方案 »
- 关于循环遍历取最小值问题
- 初学
- 两个32位二进制数按位与、或 操作?
- 如何在MyEclipse中导入net.MindView.uitl.Print
- JTable如何加入JCheckBox
- 有用过jgoodies的吗,或者能访问http://www.jgoodies.com/吗?
- 散分:支持《工大森林》地址:ftp://202.116.151.119
- 关于JAVA和VRML
- 各位老大:如何使用通常接受的方式显示数字,而不是显示9.631882892E7
- 给个能下载Cafe,or visAge的地方
- 设置了一个errorPage页面,但是不起作用,调试中,源码如下:
- demo1.java无法生成class 文件
例如你的结构体为fileinfo,那么你就可以建立一个FileInfo类对应他,但是在C中必须自己转化,也就是传入一个FileInfo的对象,然后对FileInfo对象的属性通过fileinfo结构体逐一复制。
又或者你不建立class与其对应,多建立几个String类型来接受结构体中的各个信息也可以。
但是java是不支持char *这种形式的字符串的,所以你必须把C中字符串表示方式转换成java的String,java中String类型在c中表示形式其实就是jstring类型,它本身是一个复杂类型(jobject类型),实际为执行内存的指针。
对于如何把char*转变成jstring,你可以查看jni相关文档,jni有很多内置函数实现这些功能。
对于复杂类型的转换,如结构体转换成jobject,需要自己手动转换。java不直接支持结构体特性,因为java的jni不是仅仅去支持C的。
//通过GetObjectClass方法得到这个对象
jclass objectClass = (env)->GetObjectClass(obj);
//通过GetFieldID方法得到这个对象的fsize属性
jfieldID fs = (env)->GetFieldID(objectClass,"filesize","I");
//再通过SetIntField()方法把这个属性和结构体一一对应赋值对吗?类似于下面这样:
(env)->SetIntField(obj,fs,40);
不过有个地方不知道具体怎么做:
如果这个FileInfo对象的有个属性是一个数组的话,通过GetFieldID()这个JNI函数怎么取得这个数组?
又怎么把这个数组和结构体内的数组对应起来呢?
最后提醒你一句,一定要记得回收内存噢。jni的字符串与数组最容易出现内存泄漏。
public class FileInfo{
public int filesize;
public int ss[] = new int[5];
}
在JNI的封装中:jclass objectClass = (env)->GetObjectClass(obj); //obj就是FileInfo类的实际对象
jfieldID fs = (env)->GetFieldID(objectClass,"filesize","I"); //可以获取到int型的filesize这个属性了
jfieldID ss = (env)->GetFieldID(objectClass,"ss","[I"); //这样是不是可以获取到int型的数组ss了?如果可以的话,怎么对这个ID ss进行实际的访问操作?
这样只是获得对象字段的句柄指针,并没有获得字段的值,要获得字段的值还需要其它操作,例如:
jint jfs=(*env)->GetObjectField(env,cl,fs);
如果获得的是jstring类型或者是数组类型还需要进行转换,转换成char[]类型或者char*类型,例如
char* str=(*env)->GetStringUTFChars(env,jstr,NULL);
如果是基本数据类型数组的话,访问其内部元素用GetXxxArrayElements(env,jarray,0);函数Xxx是类型名称,返回Xxx*类型,
如int * i=GetIntArrayElements(env,jint,0)
如果是对象型数组就是jobject jobj=GetObjectArrayElement(env,jobjectArray,jsize),jobject是数组变量,jsize是偏移量,返回值是数组中对应偏移量的值。
你应该先写一个java 调用本地文件dll的接口,
然后通过java的jni工具生成C的头文件,
然后你再去实现相应的C/C++函数。
类中有个属性是个int型的数组:int info[30]
在JNI封装函数中这样写:
//取得类对象
jclass objectClass = (env)->GetObjectClass(sobj); //sobj即传递进来的类的对象
//取得该数组属性的ID
jfieldID jarr_info = (env)->GetFieldID(objectClass,"info","[I"); //参数“[I”表示这个是int型数组
//通过ID取得具体的数组
jintArray jintarr = (jintArray)(env)->GetObjectField(obj,jarr_info); //参数obj是该封装函数自动参数(JNIEnv *env, jclass obj)中的jclass//以上部分执行没有问题,问题出在下面语句://要对数组进行操作,要取得该数组的数组指针,通过JNI的函数GetIntArrayElements()来取得:
jint *pia = (env)->GetIntArrayElements(jintarr,0); //这句出问题了我在调试时,在上述每句语句后都紧跟一句printf的输出语句,到上面这句,紧跟的输出语句没有出现,所以应该是这句语句出现了问题。
可我不明白错在哪里,请达人指点!
如果没有,就自己定一个结构体
struct fileinfo{
char *fullpath;
int filesize;
int filemode;
struct disnode *tnode;
}; struct disnode{
int number;
struct {
int node;
int stat;
}s[number];
}; for example
struct fileinfo ff;
memcopy(obj, ff);
printf("%s",ff.fullpath);
没错啊,C++里前面用(env)的话,后面就两个参数了。这个不错的,不然编译不通过的。
现在是编译通过,执行出错。
请问memcpy的参数obj是指什么?如果指的是传递进来的类对象的话,我试了,结构体内容这样赋值给类对象是不行的呀
如果你是在C++的集成环境下调试的话,你看看每一步的值是否都对了?
我现在看你的代码也看不出问题
这个obj就是传进来的FileInfo的instance
memcpy(obj, ff, sizeof(fileinfo))
用这个方法还有个问题,java和C++的类型长度不一定一样,
所以估计还是要一个一个的属性去设置
当然,如果能保证类型长度一样的话,用memcpy最方便
JNI涉及了java和C++两部分语言,目前我可以调试java部分,C部分没有办法调试,所以才在每一句JNI函数后加一个输出语句,就是为了判断哪里会出现问题的。这个东东还真是搞死人了呀。。
...
jintArray jintarr = (jintArray)(env)->GetObjectField(obj,jarr_info); //0bj->sobj
public class FileInfo{
public String name;
}JNI中://取得类对象
jclass objectClass = (env)->GetObjectClass(sobj); //sobj即传递进来的类的对象:new FileInfo()
//取得该String属性的ID
jfieldID jname = (env)->GetFieldID(objectClass,"name","Ljava/lang/String;"); //参数“Ljava/lang/String;”表示这个是String型
//取得该属性的具体值:
jstring js = (env)->GetObjectField(sobj,jname); //这里报错!错误提示说不能将jobject型转为jstring型,这个怎么办?
查网上的例子,说jstring型就是jobjcet型啊,为什么不行?
强行转换呢
jstring js = (jstring)(env)->GetObjectField(sobj,jname); //这里报错!
参数是一个类对象数组,传递进C++函数后,先将对应的结构体赋值,然后改变结构体的值,再返回给这个对象数组,最后通过java打印出该返回数组的每个属性值。结构体定义如下:struct fileinfo{
char *fullpath;
int filesize;
struct disnode *tnode;
}; struct disnode{
int number;
int stat[32];
}; java类定义如下:public class FileInfo{
public String fullpath;
public int filesize;
public DisNode dn = new DisNode();
}public class DisNode{
public int number;
public int[] stat = new int[32];
}JNI封装函数定义:JNIEXPORT jint JNICALL Java_TestJni_makefiles
(JNIEnv *env, jclass obj,jobjectArray objAry)
请问如下问题:
1.jfieldID是对象数组中的每个类对象都要提取一次,还是只要取一个对象,大家都可以用?
2.传递入的是对象数组,那对应赋值给结构体的时候,结构体也必须是数组,那循环赋值时类对象如何一一提取出来?
3.结构体值被更改后,赋值回对象数组,该数组如何返回?
以上最好有简单的例子,谢谢!
jclass objectClass = (env)->GetObjectClass(sobj); //编译通过,但执行错误
用GetObjectArrayElement函数从数组得到的object无法用GetObjectClass函数进行class类型提取,求解!
JNIEXPORT jobject JNICALL Java_com_sundy_jnidemo_ChangeMethodFromJni_getStruct
JNIEnv *env, jobject obj)
{
DisInfo d=Java_com_sundy_jnidemo_Test_GetDisInfo();
//在这里如何把d中的值给obj?
}