文章来源:正伟数字(www.zwm2m.com )
JAVA调用DLL简直让人伤透脑筋,JAVA提供的JNI要求修改DLL,基本不具可用性。其他的接口方式语焉不详,摸索了很长时间,才找到了真正可用的方式,并实现了由DLL内的函数回调自己的函数。
这次DLL调用亲测了好几种调用DLL的方式,有:JNI、JAwin、Jnative、Jcoba、Jna,最开始看参数类型支持,看网络上的评论,然后看回调函数,特别是回调函数,我所有功能都实现了,最后发现回调不行,只有换接口方式,后来参考项目中DLL厂家提供的DEMO,选定JNA,实现所有功能。支持Pointer、REF、*char、**byte等参数类型,非常好用。
要点说明如下,希望能让你少耽误时间。
下载JNA
在这里下载:
https://jna.dev.java.net/servlets/ProjectDocumentList?folderID=7408&expandFolder=7408&folderID=0
下载后JAR包直接放LIB文件所在文件夹即可。
要测试的DLL使用我们项目中用到的GPRS DLL,代码片段在项目中采用,绝对可用。DLL是上海正伟配套其GPRS产品的,实际使用的DLL,我不能修改他的接口的,DLL名字是“zwgprsnw.dll”,放在项目的文件夹里。
编写接口定义
首先定义一个类Czwgprs,类中定义和DLL匹配的接口,接口中定义和DLL中函数名一致,输入、输出参数对应的函数。
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.PointerByReference;
import com.sun.jna.win32.StdCallLibrary;
public class Czwgprs {
public interface Izwlib extends StdCallLibrary {
boolean zwstartserver(String svrip,int svrpt);
}
加载DLL
public boolean zwloadgprs(){
try{
zwlib = (Izwlib) Native.loadLibrary("zwgprsnw.dll", Izwlib.class);
if ( zwlib !=null ) return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
DLL名字是“zwgprsnw.dll”,放在项目的文件夹里。
简单调用
先调用DLL中“zwstartserver”这个函数,启动GPRS服务器。函数在C#中定义:
bool zwstartserver(string listenip , int listenipport);
在VC中定义:
bool zwstartserver(char * listenip , int listenipport);
把该函数定义到interface Izwlib接口中,String和int类型没有变化,直接定义:
boolean zwstartserver(String svrip,int svrpt);
这样在程序中就可以直接使用了。
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
String svrip = jTextField1.getText();
int svrpt = Integer.parseInt(jTextField2.getText());
try {
boolean zwret = zwgprs.zwlib.zwstartserver(svrip, svrpt);
} catch (Exception e) {
e.printStackTrace();
}
}
点击按钮,试一下,DLL简单功能就实现了。
实现回调
“zwgprsnw.dll”DLL是实现TCP数据接收的,收到TCP数据后,主动调用JAVA的函数,将收到的数据传递给JAVA程序,这是一个难点,怎么实现?
首先,定义回调接口:
public interface izwsvrrevdat extends StdCallCallback {
boolean zwgetdat( PointerByReference zdid, Pointer dat,int datlen) ;
}
定义接口实现:
public class zwimsvrrevdat implements izwsvrrevdat{
public boolean zwgetdat( PointerByReference zdid, Pointer dat,int datlen){
Pointer p = zdid.getValue();
String locip = p.getString(0, false);
locip =locip.trim();
byte[] revdat=dat.getByteArray(0, datlen);
zwui.zwdealzdrev(locip,revdat,datlen);
return true;
}
}
注意看,JNA对指针的支持非常完善。
调用DLL的设置函数,设置回调函数的地址:
public static Izwlib.izwsvrrevdat zwrevdatfunc = new Izwlib.zwimsvrrevdat();
boolean zwsetsvrrevfunc(izwsvrrevdat zwrevdatfunc);
至此,回调函数就实现了,非常简单。JNA真是非常棒!
对比下DLL中函数的C#定义:
回调函数:bool typzwsvrapprev(ref string telid, byte* revdat, int revlen);
设置函数:bool zwsetclntrevfunc(typzwclntapprev func);
程序运行
程序运行后界面如图,可以自动接收TCP数据了。
要特别说明,上面的代码片段来自上海正伟的GPRSCDMA DLL测试代码,他们提供DLL的同时提供了JAVA的完整调用代码,实际使用其实不用自己写了,但是这种技术还是值得学习。
另外,如果需要DLL或者调用代码,也可以和上海正伟联系的,www.zwm2m.com 是他们网站。那个JNA包也附带提供的。