前一段时间在写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);
/* 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 __cplusplus
extern "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
#include
#include
#include
#include
#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"); //加载dll
if(hdll==NULL){
cout<<"动态库加载失败............."<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"<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;
}
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"); //加载C++生成dll
Meter 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.编写实现该头文件中定义的方法。如上面贴的。
注:如有不对的请大家帮忙指出来,共同进步。