JNA调用C语言dll
最近公司要求要要用java
代码调用C语言的接口,给我一个dll文件去,看了网上一些,不太全,还是踩了很多坑,把踩得的坑记录下来,希望能帮助到你
首先新建一个maven项目,导入所需要的JNA包
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>4.1.0</version>
</dependency>
将dll文件放到jdk对应的bin目录下,或者是放到C:\Windows\System32 ,
CLibrary INSTTANCE = (CLibrary) Native.loadLibrary("", CLibrary.class);
但是这样有点不好,我们想将文件放到项目里面,跟着项目一起,
public interface CLibrary extends Library {
String path = Thread.currentThread().getContextClassLoader().getResource("").getPath().replaceAll("%20"," ").replaceFirst("/","").replace("/","\\")+"win32-x64\\JGDFDAPI";
CLibrary INSTTANCE = (CLibrary) Native.loadLibrary(path, CLibrary.class);
}
这样就能放到项目里边了
直接放导resources下面
这里有个坑,里边对应的dll文件必须与jdk的位数相对应,另外eclipse32位的不能调用64位的dll,即使jdk是64位的也不行,还有,dll内部引用的文件必须全部弄进来,否则也会是报找不到对应文件(这个问题困扰了我一天才解决,一直以为只要一个dll文件就可以了)
最基础的部分就到这里了,然后最最重要也是最麻烦的来了,数据类型,大家可以去看下C语言对应java的数据类型
这些基本能解决你的问题了,但是也会有特殊的,例如枚举,
JGDFDAPI int DFDAPI_SetEnv(DFDAPI_SET_ENVIRONMENT eSetEnv, int nEnvValue);
以上是C语言中的接口。以及枚举类
其实这里对应java中,你可以创建一个枚举或者是一个接口,参数看成是一个常量
public interface DFDAPI_SET_ENVIRONMENT {
public static final int DFDAPI_ENVIRON_HEART_BEAT_INTERVAL=0;//("Heart Beat间隔(秒数),若值为0则表示默认值10秒钟"),
public static final int DFDAPI_ENVIRON_OPEN_TIME_OUT=0;//(" 在调DFDAPI_Open期间,接收每一个数据包的超时时间(秒数,不是DFDAPI_Open调用总的最大等待时间),若值为0则默认30秒"),
public static final int DFDAPI_ENVIRON_USE_PACK_OVER=1;//(""),
public static final int DFDAPI_ENVIRON_HEART_BEAT_FLAG=1;//("心跳数据发送方式(0: 取消发送心跳包 1:没有数据发送的时候发送心跳数据,2:有规律发送心跳数据)"),
public static final int DFDAPI_ENVIRON_SOURCE_MODE=1;//("双活数据源模式,值参考DFDAPI_SOURCE_SETTING枚举类"),
public static final int DFDAPI_ENVIRON_SOURCE_MODE_VALUE=1;//("双活数据源模式下参数的值"),
public static final int DFDAPI_ENVIRON_OUT_LOG=1;//("当前目录下创建log,否则在当前路径有log文件夹时创建到log文件夹中"),
public static final int DFDAPI_ENVIRON_SNAPSHOT_ENENT=1;//("发送快照事件和清盘通知但快照不发送到回调函数,否则直接发送快照到回调函数,无快照通知"),
public static final int DFDAPI_ENVIRON_ORIGINAL_VOL=1;//("原始结构有效,1、指数成交量和成交额的单位为股和元,默认为100股和100元"),
public static final int DFDAPI_ENVIRON_BREAKPOINT=1;//("1.网络断开后断点续传,else.请求最新快照"),
public static final int DFDAPI_ENVIRON_PUSHMODE=1;//("0:启用默认订阅推送;1:禁用默认订阅推送。"),
public static final int DFDAPI_ENVIRON_COMPRESS=1;//("0:默认压缩传输行情数据;1:不压缩传输行情数据。");
}
对应java方法
/*
* 设置环境变量 一个变量类型设置一次,可以不设置使用默认值,默认值参考DFDAPI_SET_ENVIRONMENT
* @param[in] eSetEnv 环境变量设置项
* @param[in] unEnvValue 环境变量设置值
* return 成功:DFDAPI_ERR_SUCCESS 未知参数:DFDAPI_ERR_INVALID_PARAMS
*/
public int DFDAPI_SetEnv(int eSetEnv, int nEnvValue);
C接口中传参为Struct,相当于java中对象
struct DFDAPI_OPEN_CONNECT_SET
{
DFDAPI_SERVER_INFO ServerInfo[JGAPI_SERVERINFO_MAX];
unsigned int unServerNum;
dfdapi_data_callback data_fun;
dfdapi_notice_callback notice_fun;
const char* szMarkets;
const char* szSubScriptions;
const char* szTypeFlags;
unsigned int nTime;
unsigned int nConnectionID;
};
/*
* 打开服务链接
* @param[in] pConnectSet 连接参数设置,在调用期间会通过回调收到连接登录获取代码表结果消息
* 如果断开连接会将错误码放入pErrCode
* @param[in] pErrCode 错误码
* return 成功返回一个实例标识 否则返回NULL
*/
JGDFDAPI VHANDLE DFDAPI_OpenConnect(DFDAPI_OPEN_CONNECT_SET *pConnectSet, DFDAPI_ERR_CODE *pErrCode);
public class DFDAPI_OPEN_CONNECT_SET extends Structure{
public DFDAPI_SERVER_INFO [] serverInfos = (DFDAPI_SERVER_INFO[]) new DFDAPI_SERVER_INFO().toArray(100); ///< 服务器信息
public int unServerNum; ///< 服务器数量
public String szMarkets; ///< 市场订阅!例如"SZ;SH;CF;SHF;DCE;SHF",需要订阅的市场列表,以“;”分割.
public String szSubScriptions; ///< 代码订阅!例如"600000.sh;IH1711.cf;000001.sz",需要订阅的股票,以“;”分割.
public String szTypeFlags; ///< 数据类型订阅!支持订阅3种类型TRANSACTION;ORDER;ORDERQUEUE。!注意:行情数据任何时候都发送,不需要订阅! 参见enum DATA_TYPE_FLAG.
public int nTime; ///< 为0则请求实时行情,为0xffffffff从头请求.
public int nConnectionID; ///< 连接ID,连接回调消息的附加结构 DFDAPI_CONNECT_RESULT中 会包含这个ID,消息头也会包含该ID.
public DFDAPI_OPEN_CONNECT_SET(String vHandle, DFDAPI_CALLBACK_MSG pMsg) {
JavaCallC.CLibrary.ccback callback = new CallBackImpl();
callback.dfdapi_data_callback(vHandle, pMsg);
callback.dfdapi_notice_callback(vHandle, pMsg);
}
public DFDAPI_OPEN_CONNECT_SET() {
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
protected List getFieldOrder() {
List list = new ArrayList();
list.add("serverInfos");
list.add("unServerNum");
list.add("szMarkets");
list.add("szSubScriptions");
list.add("szTypeFlags");
list.add("nTime");
list.add("nConnectionID");
return list;
}
public DFDAPI_SERVER_INFO[] getServerInfos() {
return serverInfos;
}
public void setServerInfos(DFDAPI_SERVER_INFO[] serverInfos) {
this.serverInfos = serverInfos;
}
public int getUnServerNum() {
return unServerNum;
}
public void setUnServerNum(int unServerNum) {
this.unServerNum = unServerNum;
}
public String getSzMarkets() {
return szMarkets;
}
public void setSzMarkets(String szMarkets) {
this.szMarkets = szMarkets;
}
public String getSzSubScriptions() {
return szSubScriptions;
}
public void setSzSubScriptions(String szSubScriptions) {
this.szSubScriptions = szSubScriptions;
}
public String getSzTypeFlags() {
return szTypeFlags;
}
public void setSzTypeFlags(String szTypeFlags) {
this.szTypeFlags = szTypeFlags;
}
public int getnTime() {
return nTime;
}
public void setnTime(int nTime) {
this.nTime = nTime;
}
public int getnConnectionID() {
return nConnectionID;
}
public void setnConnectionID(int nConnectionID) {
this.nConnectionID = nConnectionID;
}
}
public class DFDAPI_SERVER_INFO extends Structure{
public byte [] szIp = new byte[32];
public short nPort;
public byte [] szUser = new byte[64];
public byte [] szPwd = new byte[64];
public int bDoMain;
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
protected List getFieldOrder() {
List list = new ArrayList();
list.add("szIp");
list.add("nPort");
list.add("szUser");
list.add("szPwd");
list.add("bDoMain");
return list;
}
public byte[] getSzIp() {
return szIp;
}
public void setSzIp(byte[] szIp) {
this.szIp = szIp;
}
public short getnPort() {
return nPort;
}
public void setnPort(short nPort) {
this.nPort = nPort;
}
public byte[] getSzUser() {
return szUser;
}
public void setSzUser(byte[] szUser) {
this.szUser = szUser;
}
public byte[] getSzPwd() {
return szPwd;
}
public void setSzPwd(byte[] szPwd) {
this.szPwd = szPwd;
}
public int getbDoMain() {
return bDoMain;
}
public void setbDoMain(int bDoMain) {
this.bDoMain = bDoMain;
}
}
继承Struct类,重写getFieldOrder(),把对应的属性都填进去,
里面有几个坑,给大家说下,记得一定要初始化数组,不然会报数组没有初始化,
里面对应的属性也要设置成public,设置成private会报属性只能设置为public
char szIp [32],对应public byte [] szIp = new byte[32]; 也要初始化,位数对应c中的位数,不然一直报无效内存
好了,这是我第一次写jna,记录一下,希望能帮到你,写的不好的地方希望各位海涵