JNI 调用dll

用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 __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

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");			//加载dll
		if(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++生成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.编写实现该头文件中定义的方法。如上面贴的。



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













  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Java中使用JNI(Java Native Interface)调用DLL(Dynamic-Link Library)中间件需要以下步骤: 1. 创建Java类和本地方法声明:首先,在Java类中声明本地方法。本地方法声明使用`native`关键字,并且没有方法体。例如: ```java public class MyDLL { public native void myFunction(); } ``` 2. 生成JNI头文件:运行`javac`命令编译Java类,然后使用`javah`命令生成JNI头文件。在命令行中切换到包含Java类的目录,并执行以下命令: ```shell javac MyDLL.java javah MyDLL ``` 这将生成名为`MyDLL.h`的头文件。 3. 编写C/C++实现:使用生成的JNI头文件作为C/C++代码的基础,实现本地方法。在C/C++文件中,包含生成的头文件并实现本地方法。例如: ```c #include "MyDLL.h" JNIEXPORT void JNICALL Java_MyDLL_myFunction(JNIEnv *env, jobject obj) { // 实现DLL中间件的功能 } ``` 4. 编译C/C++代码为DLL:使用适当的编译器将C/C++代码编译为DLL。具体步骤取决于所使用的编译器和操作系统。 5. 加载和调用DLL:在Java代码中加载并调用DLL。在Java代码中,使用`System.loadLibrary()`方法加载DLL,并调用本地方法。例如: ```java public class Main { static { System.loadLibrary("mydll"); } public static void main(String[] args) { MyDLL mydll = new MyDLL(); mydll.myFunction(); } } ``` 在上述示例中,`System.loadLibrary("mydll")`加载名为`mydll`的DLL,然后通过创建`MyDLL`对象并调用`myFunction()`方法来调用DLL中的函数。 请注意,执行此操作需要确保DLL文件与Java代码在相同的操作系统平台和架构上兼容,并且DLL文件路径正确。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值