JAVA(JNI,Jnative,JNA)分别调用delphi的动态链接库(dll)
2012-03-26 15:24
627 查看
首先我介绍一下本项目所要解决的技术问题:项目是要求用JAVA来调用delphi提供的动态链接库,而且硬件厂商已经提供了库以及接口文档.由于以前没有接触过这样的问题,所以考虑到要跟硬件设备打交道,首先通过查相关的资料,得出在JAVA里面用JNI可以直接访问C提供的动态链接库.但是问题是库是用delphi生成的,貌似用JNI不能直接访问,所以只能用C封装delphi的库供JNI访问,但是这样很麻烦,而且双层封装不稳定,最后在网上看到有人用Jnative可以直接访问delphi的dll库,所以就转向Jnative,但是通过折腾里面还是从在了很多问题,最后通过JavaEye问答讨论,用JNA比用Jnative好用一点,所以最终还是用JNA解决了所需要的问题.下面我就把所需的原码贴出来希望大家指点并讨论.
1)下面是硬件厂商提供的dll接口文档(为了说明问题我只提供了几个接口的文档):
一、调用参数说明
本动态库中所有函数均需要一个指向下列结构的指针作为参数,这个结构包含了函数运行时所需要的数据。()
Java代码
//下面是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; //指向以上结构的指针。
二、函数说明
Java代码
ReadAuthorInfo
读取授权卡上的客户编号和客户名称。
function ReadAuthorInfo(
buf:TPParaBuf;
pCustNo,pCustName:PChar):integer;
参数
buf
指向参数内存块的指针。
pCustNo
用于返回客户编号。客户编号固定为4字节,所以调用前必须先开辟足够的空间。
pCustName
用于返回客户名称。客户名称固定为14字节,所以调用前必须先开辟足够的空间。
返回值
如果函数调用成功,返回值为0。
如果函数调用失败,返回值不为0。如需得到错误描述,请调用GetErrMsg。
Java代码
ReadAuthorCard
读取授权卡上的授权码。
function ReadAuthorCard(
buf:TPParaBuf):integer;
参数
buf
指向参数内存块的指针。
返回值
如果函数调用成功,返回值为0。
如果函数调用失败,返回值不为0。如需得到错误描述,请调用GetErrMsg。
说明
调用本函数可以获取授权码,该码保存于参数块中,供其它函数调用。
Authorize
对新卡进行授权操作。
function Authorize(
buf:TPParaBuf):integer;
参数
buf
指向参数内存块的指针。
返回值
如果函数调用成功,返回值为0。
如果函数调用失败,返回值不为0。如需得到错误描述,请调用GetErrMsg。
三.
1)以上的每个函数的参数都要指向delphi提供的一个结构体,但是怎样用JNA来模仿delphi里面的结构体呢,具体如下:
Java代码
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结构体里面 的成员变量:
Java代码
AuthorNo:array [1..6] of PChar;
本结构体类必须要继承JNA开源包的Structure抽象类!
2)定义跟动态链接库的结构函数(我把访问接口函数封装在里一个接口里面)如下:
Java代码
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)中所定义的接口函数:
Java代码
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动态链接库的整个过程.
转自:http://www.iteye.com/topic/340823
补充一个调用例子:
1)下面是硬件厂商提供的dll接口文档(为了说明问题我只提供了几个接口的文档):
一、调用参数说明
本动态库中所有函数均需要一个指向下列结构的指针作为参数,这个结构包含了函数运行时所需要的数据。()
Java代码
//下面是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; //指向以上结构的指针。
//下面是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; //指向以上结构的指针。
二、函数说明
Java代码
ReadAuthorInfo
读取授权卡上的客户编号和客户名称。
function ReadAuthorInfo(
buf:TPParaBuf;
pCustNo,pCustName:PChar):integer;
参数
buf
指向参数内存块的指针。
pCustNo
用于返回客户编号。客户编号固定为4字节,所以调用前必须先开辟足够的空间。
pCustName
用于返回客户名称。客户名称固定为14字节,所以调用前必须先开辟足够的空间。
返回值
如果函数调用成功,返回值为0。
如果函数调用失败,返回值不为0。如需得到错误描述,请调用GetErrMsg。
ReadAuthorInfo 读取授权卡上的客户编号和客户名称。 function ReadAuthorInfo( buf:TPParaBuf; pCustNo,pCustName:PChar):integer; 参数 buf 指向参数内存块的指针。 pCustNo 用于返回客户编号。客户编号固定为4字节,所以调用前必须先开辟足够的空间。 pCustName 用于返回客户名称。客户名称固定为14字节,所以调用前必须先开辟足够的空间。 返回值 如果函数调用成功,返回值为0。 如果函数调用失败,返回值不为0。如需得到错误描述,请调用GetErrMsg。
Java代码
ReadAuthorCard
读取授权卡上的授权码。
function ReadAuthorCard(
buf:TPParaBuf):integer;
参数
buf
指向参数内存块的指针。
返回值
如果函数调用成功,返回值为0。
如果函数调用失败,返回值不为0。如需得到错误描述,请调用GetErrMsg。
说明
调用本函数可以获取授权码,该码保存于参数块中,供其它函数调用。
Authorize
对新卡进行授权操作。
function Authorize(
buf:TPParaBuf):integer;
参数
buf
指向参数内存块的指针。
返回值
如果函数调用成功,返回值为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里面的结构体呢,具体如下:
Java代码
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];
}
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结构体里面 的成员变量:
Java代码
AuthorNo:array [1..6] of PChar;
AuthorNo:array [1..6] of PChar;可以理解为一个指针数组,但是用JAVA的byte[]是不能替代PChar类型的数组,通过摸索用ByteByReference定义的数组可以跟delphi里面的PChar型数组对应.
本结构体类必须要继承JNA开源包的Structure抽象类!
2)定义跟动态链接库的结构函数(我把访问接口函数封装在里一个接口里面)如下:
Java代码
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);//(对新卡进行授权操作。)
}
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)中所定义的接口函数:
Java代码
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));
}
}
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动态链接库的整个过程.
转自:http://www.iteye.com/topic/340823
补充一个调用例子:
Java中调用例子 CallDll.java ================== package libPassChk; public class CallDll { static { System.loadLibrary("libPassChk"); } public native boolean IsValidPassword(String APass, String AEncodedPass); } 调用的例子 import libPassChk.*; public class TestCallDll { public static void main(String[] args) { CallDll jc = new CallDll(); String j; if (jc.IsValidPassword("", "ddd")){ System.out.println("ok"); }else{ System.out.println("not ok"); } } }
相关文章推荐
- JAVA(JNI,Jnative,JNA)分别调用delphi的动态链接库(dll)的技术交流.
- Java调用本地库,如调用DLL或者SO,如:JNI, Jawin, Jacob,JNative,JNA
- java调用C/C++生成的dll动态链接库----借助JNI
- Java通过JNI 调用动态链接库DLL
- JNI java调用动态链接库dll
- JNA—JNI终结者,java调用dll、ocx、so最简单的方法
- JNA—JNI终结者,java调用dll、ocx、so最简单的方法
- 关于Java通过JNI调用C 动态链接库(DLL)
- 如何在java中使用jna.jar调用Delphi写的dll
- JAVA调用动态链接库DLL之JNative学习
- [转]Java调用DLL动态链接库的方案:JNI, Jawin, Jacob.
- JAVA调用动态链接库DLL之JNative学习
- [JNA系列]Java调用Delphi编写的Dll之实例Delphi使用PAnsiChar
- Java Jni 调用动态链接库总结 dll文件
- [JNA系列]Java调用Delphi编写的Dll之Delphi与JAVA基本数据类型对比
- JNA—JNI终结者,java调用dll、ocx、so最简单的方法
- 使用Java的JNative调用dll动态链接库
- [JNA系列]Java调用Delphi编写的Dll之JNA使用
- JNI:Java调用Delphi编写的dll
- JAVA调用动态链接库DLL之JNative学习