`
lhy5201314
  • 浏览: 121051 次
  • 性别: Icon_minigender_1
  • 来自: 广州
文章分类
社区版块
存档分类
最新评论

JAVA(JNI,Jnative,JNA)分别调用delphi的动态链接库(dll)的技术交流.

阅读更多
  刚进公司不久就接到了一个很棘手的项目,里面用到的技术以前都没怎么接触过,通过一个多月的努力终于有所收获,但是至今为止还有一点问题没能解决的了,今天晚上我就把这一个多月的折腾分享给大家,希望大家讨论.
  首先我介绍一下本项目所要解决的技术问题:项目是要求用JAVA来调用delphi提供的动态链接库,而且硬件厂商已经提供了库以及接口文档.由于以前没有接触过这样的问题,所以考虑到要跟硬件设备打交道,首先通过查相关的资料,得出在JAVA里面用JNI可以直接访问C提供的动态链接库.但是问题是库是用delphi生成的,貌似用JNI不能直接访问,所以只能用C封装delphi的库供JNI访问,但是这样很麻烦,而且双层封装不稳定,最后在网上看到有人用Jnative可以直接访问delphi的dll库,所以就转向Jnative,但是通过折腾里面还是从在了很多问题,最后通过JavaEye问答讨论,用JNA比用Jnative好用一点,所以最终还是用JNA解决了所需要的问题.下面我就把所需的原码贴出来希望大家指点并讨论.

  1)下面是硬件厂商提供的dll接口文档(为了说明问题我只提供了几个接口的文档):
一、调用参数说明
本动态库中所有函数均需要一个指向下列结构的指针作为参数,这个结构包含了函数运行时所需要的数据。()
 //下面是delphi接口函数所需要的结构体
  TParaBuf=record
    ComNo:integer;        //串口号
    Baud:integer;         //波特率 (一般设为115200)
    Sys_Sec:array [1..3] of integer;   //系统扇区1,2,3 (一般设为0,1,2)
    User_Sec:array [1..3] of integer;   //用户扇区1,2,3 (一般设为3,4,5,可以自由设置)
    AuthorNo:array [1..6] of PChar;     //授权码1,2,3,4,5,6 (该授权码由授权卡内的授权码计算得到。)
  end;
  TPParaBuf=^TParaBuf;	//指向以上结构的指针。


二、函数说明
ReadAuthorInfo
读取授权卡上的客户编号和客户名称。
  function ReadAuthorInfo(
   buf:TPParaBuf;
   pCustNo,pCustName:PChar):integer;

	参数
	buf
		指向参数内存块的指针。	
	pCustNo
		用于返回客户编号。客户编号固定为4字节,所以调用前必须先开辟足够的空间。
	pCustName
		用于返回客户名称。客户名称固定为14字节,所以调用前必须先开辟足够的空间。

	返回值
		如果函数调用成功,返回值为0。
如果函数调用失败,返回值不为0。如需得到错误描述,请调用GetErrMsg。


ReadAuthorCard
读取授权卡上的授权码。
  function ReadAuthorCard(
buf:TPParaBuf):integer;

	参数
	buf
		指向参数内存块的指针。

	返回值
		如果函数调用成功,返回值为0。
如果函数调用失败,返回值不为0。如需得到错误描述,请调用GetErrMsg。
说明
调用本函数可以获取授权码,该码保存于参数块中,供其它函数调用。

Authorize
对新卡进行授权操作。
  function Authorize(
buf:TPParaBuf):integer;

	参数
	buf
		指向参数内存块的指针。

	返回值
		如果函数调用成功,返回值为0。
如果函数调用失败,返回值不为0。如需得到错误描述,请调用GetErrMsg。

   三.
   1)以上的每个函数的参数都要指向delphi提供的一个结构体,但是怎样用JNA来模仿delphi里面的结构体呢,具体如下:
  public class ParaBuf  extends Structure{
	public int comNo;
	public int  baud;
	public int[] sysSec = null;
	public int[] userSec = null;
	public ByteByReference[] authorNo = new ByteByReference[6];
}

delphi结构体里面 的成员变量:
AuthorNo:array [1..6] of PChar;
可以理解为一个指针数组,但是用JAVA的byte[]是不能替代PChar类型的数组,通过摸索用ByteByReference定义的数组可以跟delphi里面的PChar型数组对应.
本结构体类必须要继承JNA开源包的Structure抽象类!
2)定义跟动态链接库的结构函数(我把访问接口函数封装在里一个接口里面)如下:
public interface PCSCard extends StdCallLibrary {
        //这句是利用Native.loadLibrary加载所要访问的动态链接库
	PCSCard INSTANCE = (PCSCard)Native.loadLibrary("pcsCardDll", PCSCard.class);//, DEFAULT_OPTIONS);
        //下面三个函数为库的接口函数,其中ParaBuf paraBuf,表示为一个结构体参数
	int ReadAuthorInfo(ParaBuf paraBuf, byte[] customerNo,byte[] customerName);//(读取授权卡上的客户编号和客户名称。)
	int ReadAuthorCard(ParaBuf paraBuf);//(读取授权卡上的授权码。)
	int Authorize(ParaBuf paraBuf);//(对新卡进行授权操作。)	
}


3)定义访问2)中所定义的接口函数:
  public class PCSCardDemo {
	
	/**
	 * 得到一个调用dll函数的INSTANCE:
	 * @return
	 */
	public PCSCard getpCSCardInstance(){
		PCSCard lib=PCSCard.INSTANCE;
		return lib;
	}
	/**
	 * 设置系统结构体指针参数:
	 * @return 结构体指针对象:
	 */
	public ParaBuf setParaBuf(){
		ParaBuf paraBuf=new ParaBuf();
		paraBuf.comNo=1;
		paraBuf.baud=115200;
		paraBuf.sysSec=new int[3];
		paraBuf.sysSec[0]=0;
		paraBuf.sysSec[1]=1;
		paraBuf.sysSec[2]=2;
		paraBuf.userSec=new int[3];
		paraBuf.userSec[0]=3;
		paraBuf.userSec[1]=4;
		paraBuf.userSec[2]=5;
		return paraBuf;
	}
	/**
	 * 读取授权卡上的授权码:
	 * @param lib
	 * @param paraBuf
	 * @return
	 */
   public ParaBuf readAuthorCard(PCSCard lib,ParaBuf paraBuf){
		int authorCard = lib.ReadAuthorCard(paraBuf);
	System.out.println("return authorCard:" + authorCard);
	ByteByReference[] by = paraBuf.authorNo;
	for(int i=0;i<3;i++){
		System.out.println(paraBuf.sysSec[i]);
	}
	for(int i=0;i<3;i++){
		System.out.println(paraBuf.userSec[i]);
	}
	for(ByteByReference c : by) {
		if(0 != c.getValue()) {
			System.out.println(c.getValue());
		}
	}
	getErrMsg(lib,authorCard);
	return paraBuf;
   }
   
	/**
	 * 对新卡进行授权操作:
	 */
	public int authorize(PCSCard lib,ParaBuf paraBuf){
       int returnl =  lib.Authorize(paraBuf);
//函数getErrMsg为调用返回错误信息的函数
       getErrMsg(lib,returnl);
		return returnl;
		
	}
    /**
     * 得到错误信息:
     * @param lib
     * @param msgNo
     * @return
     */
   public String getErrMsg(PCSCard lib,int msgNo){
		byte[] msg = new byte[14];
		boolean bResult=lib.GetErrMsg(msgNo, msg);
		System.out.println("Return:\t" + bResult);
		System.out.println("error message:\t" + new String(msg));
	    return new String(msg);
   }
	public static void main(String[] args) throws UnsupportedEncodingException {
		/*
		 * 初始化:
		 */
		PCSCardDemo pcscard = new PCSCardDemo();
		PCSCard lib=pcscard.getpCSCardInstance();		        //对结构体进行初始化
		ParaBuf paraBuf=pcscard.setParaBuf();

	/**
	* 读取授权卡上的授权码:
	*/
//pcscard.readAuthorCard(lib, paraBuf);
//System.out.println("authorNo:\t");
        /*
         * 读取授权卡信息:
         */
//int read = pcscard.readAuthorInfo(lib, paraBuf);
	/**
	 * 对新卡进行授权操作,在授权的时候必须得到授权卡的授权码
	 */
//pcscard.authorize(lib,pcscard.readAuthorCard(lib, paraBuf));
	}
}

以上就是访问delphi动态链接库的整个过程.
   明天在将用Jnative访问dll库的过程贴出来,希望大家指点哈

下面附件有jna的包
  • jna.jar (777.2 KB)
  • 下载次数: 842
分享到:
评论
7 楼 zhengpei456 2010-02-09  
你能帮我看看使用JNA的问题吗?

zkemkeeper.dll
里面有函数:

VARIANT_BOOL Connect_Com([in] LONG ComPort, [in] LONG MachineNumber, [in]
LONG BaudRate)


VARIANT_BOOL Connect_Net([in] BSTR IPAdd, [in] LONG Port)



  
 public class Zkem { public interface TestZkem extends Library{ TestZkem INSTANCE=(TestZkem)Native.loadLibrary("zkemkeeper", TestZkem.class); } public static void main(String[] args){ Zkem jfczkem = new Zkem(1); jfczkem.connectCom(1, 1, 115200); System.out.println("Connect:"+jfczkem.connectNet("192.168.0.201", 4370)); } public native boolean connectCom(int comPort, int machineNumber, int baudRate); public native boolean connectNet (String ipAddress, int port);




运行报错:

Exception in thread "main" java.lang.UnsatisfiedLinkError: com.metaarchit.java.Zkem.connectCom(III)Z
at com.metaarchit.java.Zkem.connectCom(Native Method)
at com.metaarchit.java.Zkem.main(Zkem.java:12)
6 楼 fff 2009-12-29  
google了半天,证实了一个问题,在windows下没法load jar包中的dll
感谢楼主,大大缩短了使用JNA的时间
5 楼 lhy5201314 2009-12-11  
其实你可能想的多了 比如:
定义了一个数组参数
String[] str = new String[8];
下面调用
getStr(str);
调用了这个方法之后不用返回,str里面的值以及被参数给初始化了
直接在str这个数组里面取值就可以了!
(注意:我说的这个方法是调用dll的接口函数)
4 楼 mj4678 2009-12-11  
请问java 调用怎么取到参数的返回值呢,比如“调用本函数可以获取授权码,该码保存于参数块中,供其它函数调用。”java调用怎么取到这个参数返回值呢?
3 楼 lhy5201314 2009-03-19  
恩 是很方便 但是具体的参数数据类型一定要对应上要不然很头疼的
2 楼 cyberniuniu 2009-03-19  
用 jna 很简单的,以后基本上可以不再用 jni 了。
1 楼 liuwangxia 2009-03-19  
不错,加油!

相关推荐

    springboot+jna/jni调用动态so/dll库

    springboot+jna/jni调用动态so/dll库

    JNI--java调用不同平台的动态链接库,dll,so,完美,全教程

    假如有一个现有的 .dll/.so 文件,假如使用 JNI 技术调用,我们首先需要另外使用 C 语言写一个 .dll/.so 共享库,使用 SUN 规定的数据结构替换 C 语言的数据结构,调用已有的 ? dll/so 中公布的函数。 然后再在 Java...

    使用JNA替代JNI调用DLL,并解决内存溢出问题

    问题描述: 在开发项目过程中,需要处理算法分析出来二进制流数据,并对数据解析处理转发。我们上层应用平台是使用java开发的...那现在上层应用面临的问题:访问java外部功能接口实现方式(即调用dll)怎么选择及实现?

    Java通过JNI调用DLL动态库

    Java通过JNI调用DLL动态库,亲测试编写

    jni调用c++ delphi中的dll.

    jni调用c++ delphi中的dll.

    JNative用java调用动态库VC++

    因工作的缘故,有机会接触了Java本地方法调用...使用Java的JNI调用C/C++的动态联结库有个固定的步骤,下面将以一个最简单的HelloWorld例子程序来说明调用过程。这个HelloWorld的例子只是简单的显示HelloWorld消息。

    JAVA项目JNI调用dll实现DEMO源码,C++&JAVA

    完整的实现java跨平台调用C程序源码,包含JAVA源码和C源码以及编译后的demo dll。将dll放到jdk bin目录下,java 项目可以直接运行。若要修改dll可以,修改C源码后重新编译生成dll。该demo处理了多线程调用c,全局...

    JNI与JNA性能的比较.docx

    分别用JNI和JNA的方式建立dll,dll中包含一个get方法和一个set方法,在java端进行循环调用1000*1000次,比较所耗费的时间。 JNI和JNA调用的不是同一个dll,但是功能和代码基本相同。本测试从一定角度反映他们的性能...

    jni调用C++动态库,jna调用C++动态库

    jni调用C++动态库,jna调用C++动态库,eclipse maven project

    jni-jna-web.zip

    基于spring-boot2.3.0,net.java.dev.jna5.9.0开发的JNI和JNA的web工程。 主要包括:结构体传参,so加载,so文件调用等

    java调用JNI

    用java的JNI调用C++的dll包容详细的步骤和例子 附带源码 一步步的教你搭建,有兴趣的可以下载看看,包括源码、文档哟

    Java JNI调用C语言写的清屏的动态链接库

    用c语言写了一个清屏的函数,然后生成动态链接库,再通过jni在java里调用清屏函数。请注意代码中的函数JNIEXPORT void JNICALL Java_Test_cls(JNIEnv *env, jobject obj),函数名字的Test是指使用该函数的Java类的...

    JAVA通过JNI调用C#dll的整个项目工程

    本资源包括JAVA工程,C++工程,C#dll测试工程

    jna java 调用c动态库

    java 调用c动态库JNA—JNI终结者,java调用dll、ocx、so最简单的方法

    Java JNI 调用C++ API/dll 示例程序

    完整的展示了Java调用C++ API/dll示例程序. 说明如下: 1. mrSocketAPICInt是准备被java调用的API 2. mrSocketAPIJavaInt是java调用C++ api的中间层 3. mrSocketAPIJavaIntDemo是java程序,展示与C++ api如何对接。...

    java调用动态链接库dll

    动态链接库的唯一功能就是使用Java 能够理解的C 代码来调用目标原生函数。 这个没什么实际用途的动态链接库的编写过程令人沮丧。同时编写Java 和C 代码使开 发难度大大增加。 因此,在Java 开发社区中,人们一直都视...

    GMSSL的java调用(JNI库和调用实例).zip

    基于最新版本的gmssl,实现了java通过jni调用gmssl,可使用国密sm2算法、sm3算法和sm4算法,包括jni的动态库和java调用示例

    jna-4.5.0.jar

    项目是要求用JAVA来调用delphi提供的动态链接库,而且硬件厂商已经提供了库以及接口文档.由于以前没有接触过这样的问题,所以考虑到要跟硬件设备打交道,首先通过查相关的资料,得出在JAVA里面用JNI可以直接访问C提供的...

    通过JNA让Java调用Dll方法

    研究java调用dll的时候,大部分都是通过jni,比较麻烦,我找到了通过jna方法调用dll的方法,用起来比较方便,只需要引用jna.jar包,这个jar包已经包含在程序中,还包含了我调用dll的遇到难道的解决办法。

    Java JNI调用动态库(Linux、Windows)的实现步骤

    Java JNI调用动态库(Linux、Windows)的实现步骤

Global site tag (gtag.js) - Google Analytics