在公司项目中遇到这么一个难题
客户有一个基板,这个基板通过数据线可以连接到电脑上,装上驱动就可以调用基板提供的函数.
但是程序是java开发的,所以就需要通过java调用基板函数,但是基板函数允许C++调用不支持java,所以就用到java调用C++
基板函数按照返回值大致分为两种
1.调用后直接返回数字,一般属于命令型函数,比如打开电源,返回0表示打开成功
2.调用后返回数组,比如需要获取采集的数据
第一种类型比较容易,用JNA、JNI都可以实现。因为只返回一个int,java比较容易接收。
第二种返回数组,因为C++有指针,当时机器函数返回的是一个内存地址,这个时候如果直接调用java是无法访问内存地址的。
因此需要转换。
当初也尝试过将返回的数组转为用逗号分割的字符串,但是长度超过300就会类似内存溢出的错误,所以最后放弃这种方式。
重点说一下第二种情况的解决方法
JAVA的代码
public class OASSInterface {
//方法
public native int[] SDFArray(String jsonStr,int[] iarr);
public native int getButtonStatus();
//加载dll
static{
File directory = new File(OASSInterface.class.getResource("/").getPath());
System.load(directory+ "\\Interface.dll");
}
}
//直接调用即可
int[] resultArr = oASSInterface.SDFArray(jsonStr, arr,)
C++代码
最后C++要生成的是一个DLL文件
JNIEXPORT jintArray JNICALL Java_css_OASSInterface_SDFArray(JNIEnv *env, jobject obj, jstring jsonstr, jintArray arr){
jstring jReturn;
Json::Reader reader;
Json::Value json_object;
const char* json_document = (char*)env->GetStringUTFChars(jsonstr,0);
if (!reader.parse(json_document, json_object))
return 0;
//json解析获取其中的值
int nTotalChannel=json_object["nTotalChannel"].asInt();
//声明数组,这是最后机器返回的数值
long long nNetIntensity[100] = {};
//re是自定义错误编码,nStandDataAcq方式是项目的业务函数
int re = nStandDataAcq(nTotalChannel*2 nNetIntensity);
//最后要返回的数组
jintArray intArray= env->NewIntArray(nTotalChannel+1);
jboolean* pb;
//就是将nNetIntensity里面的值放到pint里面
//由于有些业务逻辑,我删除了部分代码,for循环就是放值,不要照抄代码
jint* pint=new jint[nTotalChannel+1];
for(int k=0;k<nTotalChannel;k++){
pint[k] = -999;
}
for(int j=0;j<nTotalChannel;j++){
pint[j]=nNetIntensity[j];
}
//std::cout << nNetIntensity[i] << std::endl;
pint[nTotalChannel] = re;
env->ReleaseIntArrayElements(intArray,pint,JNI_COMMIT);//JNI_COMMIT=1
delete []pint; //如果使用GetIntArrayElements()得到该指针则不可以!!!否则Java直接崩溃了
return intArray;
}
int nStandDataAcq(int nTotalChannel,long long*nNetIntensity){
//项目业务逻辑
...
}
只是贴的部分代码,直接粘贴下来不能运行!
有几点需要说明一下
1.方法名 Java_css_OASSInterface_SDFArray 不可以随意命名,java开头,css是包名,OASSInterface是类名,SDFArray是方法名.
2.因为参数过多所以使用json作为参数传递,如果参数不多可以不使用json
3.C++的数组不能直接返回,需要转成jintArray
jni入门教程(里面包含如何创建C++程序)
http://www.runoob.com/w3cnote/jni-getting-started-tutorials.html
JNI详解
https://blog.youkuaiyun.com/hui12581/article/details/44832651
java调用C++会出现很多坑
一开始直接调用C++,出现C++返回指针地址,java无法读取问题
随后又改为返回字符串,出现字符串过长内存溢出问题
改为int数组解决问题后,换了版本高的基板后发现,第一次调用函数没有问题,第二次调用就卡主问题.
但是用C++直接运行没有问题,最后发现使用Win7系统不行,但是使用Win10就没有问题.项目结束也没有找到具体原因
开发过程中也出现好多问题,加上C++开发经验少,解决过程也是比较痛苦。出现问题请不要轻易放弃,网上有很多资料,当你解决了就会发现其实问题不是多么的复杂