JNI 调用dll

来源:互联网 发布:linux 目录权限 编辑:程序博客网 时间:2024/05/16 11:27

用C++调用delphi,生成dll,然后用java调用C++生成的dll

        前一段时间在写dll供java调用,在dll中又调用了delphi语言写的dll,由于第一次写dll调用,并且将弃置多年的C++重新拾起真是苦难重重啊。各种百度,各种交流群,期间有好多好心人帮忙,真是感动的不得了,最后终于搞定了。


由于delphi写的dll是厂商提供的,而且文档很不规范,简直可以用TCL(太!次!了!)来形容,至少得给我一个调用他们自己的dll的头文件吧,不好意思,没有,好吧那就一个一个试吧,这个非人的过程真是再也不想经历了,由于他们写这个的工程师也不了解C++所以问了也不知道,还有有度娘和谷(google)老师。


步骤如下:

1.编写java文件,声明外部调用函数。

public native String[]getAllSjjxCodeParameter(String a,String b,String c,String d,String e,String f,String g,String h,String i,String j,String eleCode);public native String[]getAllCommandCodeParameter(String a,String b,String c,String d,String e,String f,String g,String h,String i,String j);

2.用java自带的javah 来将编译后的.class文件编译成.h文件。

/* DO NOT EDIT THIS FILE - it is machine generated */#include "jni.h"/* Header for class com_Meter_Meter */#ifndef _Included_com_Meter_Meter#define _Included_com_Meter_Meter#ifdef __cplusplusextern "C" {#endif/* * Class:     com_Meter_Meter * Method:    getAllSjjxCodeParameter * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String; */JNIEXPORT jobjectArray JNICALL Java_com_Meter_Meter_getAllSjjxCodeParameter  (JNIEnv *, jobject, jstring, jstring, jstring, jstring, jstring, jstring, jstring, jstring, jstring, jstring, jstring);/* * Class:     com_Meter_Meter * Method:    getAllCommandCodeParameter * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String; */JNIEXPORT jobjectArray JNICALL Java_com_Meter_Meter_getAllCommandCodeParameter  (JNIEnv *, jobject, jstring, jstring, jstring, jstring, jstring, jstring, jstring, jstring, jstring, jstring);#ifdef __cplusplus}#endif#endif

3.实现头文件中的这两方法

#include<iostream>#include <windows.h>#include<string>#include <stdlib.h>#include"com_Meter_Meter.h"using namespace std;/* * Class:     com_Meter_Meter * Method:    getAllSjjxCodeParameter * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String; */JNIEXPORT jobjectArray JNICALL Java_com_Meter_Meter_getAllSjjxCodeParameter(JNIEnv *env, jobject, jstring a, jstring b, jstring c , jstring d , jstring e , jstring f , jstring g , jstring h , jstring i , jstring j ,jstring h2){jstring js[]  = {a,b,c,d,e,f,g,h,i,j,h2};//存储参数char * pa[11];//将jstrin转换成char*for(int t = 0; t < 11 ;t++){if(js[t] == NULL){pa[t] = '\0';continue;}char* rtn = NULL;  jclass clsstring = env->FindClass("java/lang/String");  jstring strencode = env->NewStringUTF("utf-8");  jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");  jbyteArray barr = (jbyteArray)env->CallObjectMethod(js[t], mid, strencode);  jsize alen = env->GetArrayLength(barr);  jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);  if (alen > 0){  rtn = (char*)malloc(alen + 1);  memcpy(rtn, ba, alen);  rtn[alen] = 0;  }  env->ReleaseByteArrayElements(barr, ba, 0);  pa[t] = rtn; }struct ReadPara{//在类里面定义个结构体  char *dbh;//电表号  char *kzz;//控制字  char *bsf;//标识符  char *dbdqmy;//电表当前密钥  char *sjs;//随机数  char *rzsc;//认证时长  char *czcs;//充值次数  char *cdsj;//购电量  char *szdata;//需要发送设置的数据  char *dbmm;//电表密码    };ReadPara para;para.dbh= pa[ 0 ];    para.kzz= pa[ 1 ];    para.bsf= pa[ 2 ];    para.dbdqmy = pa[ 3 ];para.sjs= pa[ 4 ];para.rzsc= pa[ 5 ];para.czcs= pa[ 6 ];para.cdsj= pa[ 7 ];para.szdata = pa[ 8 ];para.dbmm= pa[ 9 ];typedef  void  (_stdcall* SJJX)(ReadPara rp,char *,char **,char **,char ** ,char **);//定义一个抄表数据解析函数指针(指针函数)HINSTANCE hdll;hdll=LoadLibrary("YCGD.dll");//加载dllif(hdll==NULL){cout<<"动态库加载失败............."<<endl; FreeLibrary(hdll); }SJJX  sjjx = (SJJX)GetProcAddress(hdll,"SJJX");//根据函数名找到dll中的方法入口地址。char **textCommend1 = new char *[32]; *textCommend1 = new char[32]; *textCommend1 = '\0';  char **textCommend2 = new char *[32]; *textCommend2 = new char[32]; *textCommend1 = '\0'; char **textCommend3 = new char *[32]; *textCommend3 = new char[32]; *textCommend1 = '\0';  char **textCommend4 = new char *[32]; *textCommend4 = new char[32]; *textCommend1 = '\0'; if(pa[ 4 ]!=NULL)cout<<"sjs:       \t"<<pa[ 4 ]<<endl;    cout<<"Meter Code:\t"<<pa[10]<<endl; sjjx(para,pa[10],textCommend1,textCommend2, textCommend3,textCommend4);//调用函数jclass objClass = (env)->FindClass("java/lang/String");jsize size = 4;jobjectArray texts= (env)->NewObjectArray(size, objClass, 0);//需要判断textCommend1,textCommend2,textCommend3,textCommend4他们是否有值char **textCommends[4] ;textCommends[0] = textCommend1;textCommends[1] = textCommend2;textCommends[2] = textCommend3;textCommends[3] = textCommend4;char *str = *textCommends[0];//将char*转换成jstring,然后再放到数组中for(int it = 0 ; it < 2;it++){str = *textCommends[it]; jstring rtn = 0; int slen = strlen(str);   unsigned int * buffer = 0;  if( slen == 0 )          rtn = (env)->NewStringUTF(str);    else  {   int length = MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, NULL, 0 );  buffer = (unsigned int *)malloc( length*2 + 1 );   if( MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, (LPWSTR)buffer, length ) >0 )   rtn = (env)->NewString(  (jchar*)buffer, length ); }   if( buffer )   free( buffer ); (env)->SetObjectArrayElement( texts, it, rtn);//必须放入jstring}return texts;}/* * Class:     com_Meter_Meter * Method:    getAllCommandCodeParameter * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String; */JNIEXPORT jobjectArray JNICALL Java_com_Meter_Meter_getAllCommandCodeParameter (JNIEnv *env, jobject, jstring a, jstring b, jstring c , jstring d , jstring e , jstring f , jstring g , jstring h , jstring i , jstring j){jstring js[]  = {a,b,c,d,e,f,g,h,i,j};char * pa[10];for(int t = 0; t < 10 ;t++){if(js[t] == NULL){pa[t] = '\0';continue;}char* rtn = NULL;  jclass clsstring = env->FindClass("java/lang/String");  jstring strencode = env->NewStringUTF("utf-8");  jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");  jbyteArray barr = (jbyteArray)env->CallObjectMethod(js[t], mid, strencode);  jsize alen = env->GetArrayLength(barr);  jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);  if (alen > 0){  rtn = (char*)malloc(alen + 1);  memcpy(rtn, ba, alen);  rtn[alen] = 0;  }  env->ReleaseByteArrayElements(barr, ba, 0);  pa[t] = rtn; //cout<<"rtn\t"<<pa[t]<<endl;}struct ReadPara{//在类里面定义个结构体  char *dbh;//电表号  char *kzz;//控制字  char *bsf;//标识符  char *dbdqmy;//电表当前密钥  char *sjs;//随机数  char *rzsc;//认证时长  char *czcs;//充值次数  char *cdsj;//购电量  char *szdata;//需要发送设置的数据  char *dbmm;//电表密码    };ReadPara para;para.dbh= pa[ 0 ];    para.kzz= pa[ 1 ];    para.bsf= pa[ 2 ];    para.dbdqmy = pa[ 3 ];para.sjs= pa[ 4 ];para.rzsc= pa[ 5 ];para.czcs= pa[ 6 ];para.cdsj= pa[ 7 ];para.szdata = pa[ 8 ];para.dbmm= pa[ 9 ];//cout<<"para.dbh\t"<<para.dbh<<endl;typedef bool (_stdcall*  GetCommand)(ReadPara rp,int *a,char **b);HINSTANCE hdll;hdll=LoadLibrary("YCGD.dll");//加载dll,需要将YCGD.dll,borlndmm.dll// cout<<"hdll:\t"<<hdll<<endl;if(hdll==NULL){ FreeLibrary(hdll); cout<<"HINSTANCE:\tkong....."<<endl;} GetCommand gcmd = (GetCommand)GetProcAddress(hdll,"GetCommand"); if(gcmd == NULL){cout<<"GetCommand:\tkong....."<<endl; } int errorCommand = -1; char **textCommend= new char *[32]; *textCommend = new char[32]; *textCommend = "\0"; bool gcmdBool = gcmd(para,&errorCommand,textCommend);jclass objClass = (env)->FindClass("java/lang/String");jsize size = 2;jobjectArray texts= (env)->NewObjectArray(size, objClass, 0);//需要判断textCommend1,textCommend2,textCommend3,textCommend4他们是否有值char **textCommends[2] ;textCommends[0] = textCommend;char *strings = (char *)malloc((4)*sizeof(char));itoa(errorCommand,strings,10); char *str = *textCommends[0];for(int it = 0 ; it < 2;it++){if(it ==0){str = *textCommends[it];}else{str = strings;} jstring rtn = 0; int slen = strlen(str);   unsigned int * buffer = 0;  if( slen == 0 )  rtn = (env)->NewStringUTF(str);   else{   int length = MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, NULL, 0 );  buffer = (unsigned int *)malloc( length*2 + 1 );   if( MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, (LPWSTR)buffer, length ) >0 )   rtn = (env)->NewString(  (jchar*)buffer, length ); }   if( buffer )   free( buffer ); (env)->SetObjectArrayElement( texts, it, rtn);//必须放入jstring}return texts;}

4.生成dll,在java中调用

package com.Meter;public class Meter {public native String[]getAllSjjxCodeParameter(String a,String b,String c,String d,String e,String f,String g,String h,String i,String j,String eleCode);public native String[]getAllCommandCodeParameter(String a,String b,String c,String d,String e,String f,String g,String h,String i,String j);public static void main(String[] args) {System.loadLibrary("MyDyLL");<span style="white-space:pre"></span>//加载C++生成dllMeter m = new Meter();//生成远程跳闸命令String CommandOfRemoteTrip = m.getCommandOfRemoteTrip("120606000975", "1A", "1C", "AA5A9B9D3191452DAFA0FD75F7096247", sjs);System.out.println("远程跳闸命令:\t"+CommandOfRemoteTrip+"\n");//解析生成的跳闸命令String SjCommandOfRemoteTrip = m.getSjjxOfRemoteTrip("120606000975", "1A", "1C", "AA5A9B9D3191452DAFA0FD75F7096247",sjs,"68 75 09 00 06 06 12 68 9C 00 08 16");System.out.println("远程跳闸命令解析结果:\t"+SjCommandOfRemoteTrip+"\n");//生成远程合闸命令String CommandOfRemoteTrip2 = m.getCommandOfRemoteSwitching("120606000975", "4B", "1C", "AA5A9B9D3191452DAFA0FD75F7096247", sjs);//解析生成的合闸命令String SjCommandOfRemoteTrip2 = m.getSjjxOfRemoteSwitching("120606000975", "4B", "1C", "AA5A9B9D3191452DAFA0FD75F7096247",sjs,"68 75 09 00 06 06 12 68 9C 00 08 16");System.out.println("远程合闸命令:\t"+CommandOfRemoteTrip2);System.out.println("远程合闸命令解析结果:\t"+SjCommandOfRemoteTrip2+"\n");}/** * 生成远程跳闸 * @param dbh 电表号 * @param bsf标识符 * @param kzz控制字 * @param dbdqmy电表密钥 * @param sjs随机数 */public String getCommandOfRemoteTrip(String dbh,String bsf,String kzz,String dbdqmy,String sjs){ReadPara re = new ReadPara();re.setDbh(dbh);re.setBsf(bsf);re.setKzz(kzz);re.setDbdqmy(dbdqmy);re.setSjs(sjs);String [] code = this.getAllCommandCodeParameter(re.getDbh(), re.getKzz(), re.getBsf(), re.getDbdqmy(),re.getSjs(), re.getRzsc(),  re.getCzcs(),  re.getCdsj(),  re.getSzdata(),  re.getDbmm());//for (String string : code) {//System.out.println("生成远程跳闸命令:\t"+string);//}System.out.println("");return code[0];}/** * 生成远程合闸命令 * @param dbh 电表号 * @param bsf标识符 * @param kzz控制字 * @param dbdqmy电表密钥 * @param sjs随机数 */public String getCommandOfRemoteSwitching(String dbh,String bsf,String kzz,String dbdqmy,String sjs){ReadPara re = new ReadPara();re.setDbh(dbh);re.setBsf(bsf);re.setKzz(kzz);re.setDbdqmy(dbdqmy);re.setSjs(sjs);String [] code = this.getAllCommandCodeParameter(re.getDbh(), re.getKzz(), re.getBsf(), re.getDbdqmy(),re.getSjs(), re.getRzsc(),  re.getCzcs(),  re.getCdsj(),  re.getSzdata(),  re.getDbmm());//for (String string : code) {//System.out.println("生成远程合闸命令:\t"+string);//}System.out.println("");return code[0];}/** * 解析远程跳闸命令 * @param dbh 电表号 * @param bsf标识符 * @param kzz控制字 * @param dbdqmy电表密钥 * @param sjs随机数 */public String getSjjxOfRemoteTrip(String dbh,String bsf,String kzz,String dbdqmy,String sjs,String eleCode){ReadPara re = new ReadPara();re.setDbh(dbh);re.setBsf(bsf);re.setKzz(kzz);re.setDbdqmy(dbdqmy);re.setSjs(sjs);String [] code = this.getAllSjjxCodeParameter(re.getDbh(), re.getKzz(), re.getBsf(), re.getDbdqmy(),re.getSjs(), re.getRzsc(),  re.getCzcs(),  re.getCdsj(),  re.getSzdata(),  re.getDbmm(),eleCode.replaceAll(" ", ""));//for (String string : code) {//System.out.println("解析跳闸命令:\t"+string);//}System.out.println("远程跳闸解析结果  错误代码:"+code[0] );return code[1];}/** * 解析远程合闸命令 * @param dbh 电表号 * @param bsf标识符 * @param kzz控制字 * @param dbdqmy电表密钥 * @param sjs随机数 */public String getSjjxOfRemoteSwitching(String dbh,String bsf,String kzz,String dbdqmy,String sjs,String eleCode){ReadPara re = new ReadPara();re.setDbh(dbh);re.setBsf(bsf);re.setKzz(kzz);re.setDbdqmy(dbdqmy);re.setSjs(sjs);String [] code = this.getAllSjjxCodeParameter(re.getDbh(), re.getKzz(), re.getBsf(), re.getDbdqmy(),re.getSjs(), re.getRzsc(),  re.getCzcs(),  re.getCdsj(),  re.getSzdata(),  re.getDbmm(),eleCode.replaceAll(" ", ""));//for (String string : code) {//System.out.println("解析远程合闸命令:\t"+string);//}System.out.println("远程解析结果  错误代码:"+code[0] );return code[1];}}

注意事项:

1.怎么生成头文件,用eclipse/MyEclipse编写你要实现的方法,值得注意点是这个方法要是native方法,方法前加native表明这个方法是外部实现的,然后保存编译器就自动的将你的文件编译成.class文件了。

2.然后用cmd进入你的MyEclipse/Eclipse的工作空间,找到你的项目,进入你的项目文件夹(C:\Users\Administrator>cd C:\Workspaces\MyEclipse Blue 2014\Meter\src),然后在src目录下用java自带的javah工具来生成头文件。命令格式javah  包名.类名     就行了。然后在src目录下生成一个 包名.类名.h的文件,这个文件就是上面贴的头文件。

3.建立动态连接库项目,编写实现头文件中的方法,由于编译器版本的不同在加载DLL的时候不同VC6.0不用在dll文件名前面加L,如果是VS2010编译器则需要在dll名称前加L如(hdll=LoadLibrary("YCGD.dll");------》VC6.0写法,hdll=LoadLibrary(L"YCGD.dll");------》VS2010写法。

4.编写实现该头文件中定义的方法。如上面贴的。



注:如有不对的请大家帮忙指出来,共同进步。













0 0
原创粉丝点击