用java调用C++写的DLL一直以来都是一个比较麻烦但又很常见的问题。

我们知道,使用 JNI 调用 .dll/.so 共享类库是非常非常麻烦和痛苦的。

如果有一个现有的 .dll/.so 文件,如果使用 JNI 技术调用,我们首先需要另外使用 C 语言写一个 .dll/.so 共享库,使用 SUN 规定的数据结构替代 C 语言的数据结构,调用已有的   dll/so 中公布的函数。然后再在 Java 中载入这个适配器 dll/so ,再编写 Java   native 函数作为 dll 中函数的代理。经过 2 个繁琐的步骤才能在 Java 中调用本地代码。因此,很少有 Java 程序员愿意编写调用 dll/.so 库中的原生函数的 java 程序。这也使 Java 语言在客户端上乏善可陈。可以说 JNI 是 Java 的一大弱点。

现在好了出现了一个JNA的武器,JNA框架是一个开源的 Java 框架,是 SUN 公司主导开发的,建立在经典的 JNI 的基础之上的一个框架。通过JNA能够很方便的调用C++写的DLL。

先来一个Hello Word

C++代码

 #ifndef DEMOC_H
#define DEMOC_H
#ifndef DLLDIR
#define DLLDIR extern "C"__declspec(dllexport)
#endif
typedef struct{
char *m_sername;
char *m_username;
char *m_password;
WORD m_tranType;
HWND m_hChMsgWnd;
UINT m_nChmsgid;
int m_sockType;
int m_errormsg;
void (WINAPI *m_messagecallback)(LONG hHandle,char *wParam,int lParam);
void *context;
}SERVER_UPDATEINFO;
DLLDIR LONG __stdcall VSNET_ServerStart(char *m_url,SERVER_UPDATEINFO *m_pSerinfo,WORD wserport = 3000);
#endif

这是一个标准的C++头文件,在这个头文件中定义了一个函数VSNET_ServerStart,下面来分析一下这个头文件。首先看到在这个头文件中定义了一个宏DLLDIR,这个宏意义为导出编码为标准C(extern "C"),并且为declspec的。

然后看到在头文件中还定义了一个结构体SERVER_UPDATEINFO,在SERVER_UPDATEINFO中具有以下几种数据类型:char类型指针,word类型,hwnd类型,uint,int,回调函数,void指针。

这就是我们知道DLL中的所有信息。

对了还有一个比较关键的地方,在C、C++中如果直接编译DLL,在DLL中导出的函数名是会在编译时被编译器修改掉,所以我们必须制定导出的函数名,这就需要在工程中定义一个def文件。

def文件

 LIBRARY    "demoC"
EXPORTS
VSNET_ServerStart

好了到此为止这就是我们所知道的所有DLL信息,一般这也是DLL组件会暴漏出来的所有信息。下面就来说明用JNA如何调用。

首先我们先把DLL中的函数导出来,编程JAVA 的代码

 public interface CLibrary extends StdCallLibrary {
VSNET_ServerStart
}

声明一个CLibrary的java接口,继承自JNA类库中的StdCallLibrary。OK已经导出来了,对了就这么简单。

那么有些同学就问了,这个函数在C++的头文件中有一个LONG的返回值,而且还有参数啊?别急下面就来讲解。

首先我们看到VSNET_ServerStart有一个LONG的返回值,LONG是C++中的数据类型,在java中是没有的,但是JNA已经为我们提供了这种类型叫做NativeLong。OK那么修改一下我们的JAVA代码

 public interface CLibrary extends StdCallLibrary {
NativeLong VSNET_ServerStart
}

下面是JNA类型与C++类型的对比:

接下来我们来看函数的参数如何处理。

VSNET_ServerStart函数的参数为(char *m_url,SERVER_UPDATEINFO *m_pSerinfo,WORD wserport = 3000)。通过类型的对比我们知道char *=String,WORD=short。那个SERVER_UPDATEINFO这种结构体如何处理呢。

在JNA中类库提供了一种Structure的类型专门处理结构体。下面我们用JAVA来描述一下这个结构体。

 public static class SERVER_UPDATEINFO extends Structure {
public String m_sername;
public String m_username;
public String m_password;
public short m_tranType;
public int m_hChMsgWnd;
public int m_nChmsgid;
public int m_sockType;
public int m_errormsg;
public ICallback fun;
}

对函数指针的处理

对函数指针的处理

 public interface ICallback extends StdCallCallback{
public abstract void fun(NativeLong hHandle,String wParam,int lParam);
}

OK我们成功的描述的结构体,下面再来修改我的java接口。

 public interface CLibrary extends StdCallLibrary {
NativeLong VSNET_ServerStart(String m_url,SERVER_UPDATEINFO s,short sho)
}

到此就全部完成了DLL到JAVA的导出。下面来看如何使用。

 CLibrary INSTANCE = (CLibrary)Native.loadLibrary("demoC", CLibrary.class);
ICallback C = new CallbackImp();
CLibrary.SERVER_UPDATEINFO su = new CLibrary.SERVER_UPDATEINFO();
su.m_sername = "sername";
su.m_username = "username";
...
su.fun = C;
short sho = 3000;
NativeLong nl = CLibrary.INSTANCE.VSNET_ServerStart("url",su,sho);

OK,搞定。

注意: 1、函数、结构体定义的名称必须和DLL中的一样。 2、函数结构体的参数顺序必须一样

最新文章

  1. VS项目中使用Nuget还原包后编译生产还一直报错?
  2. 常用的一些复杂SQL语句
  3. SQL Developer报错:Unable to find a Java Virtual Machine解决办法
  4. SQL Server 2000: 维护计划无法执行
  5. codevs 3143 二叉树的序遍历
  6. jQuery发送ajax请求
  7. PHP学习笔记:利用时间和mt_rand函数获取随机名字
  8. JQuery基础学习总结
  9. Linux下配置C/C++开发环境-----Eclipse
  10. Java线程经典面试题
  11. 交作业啊,python爬取58的页面
  12. (转)http authorization 基本认证
  13. pycharm5.0 快捷键大全osx
  14. Kubernetes中pod创建流程
  15. 大数据分析界的“神兽”Apache Kylin有多牛?【转】
  16. webpack打包使用
  17. ThreadLocal 详解
  18. FZU2110 Star【计算几何】
  19. React Native 之轮播图swiper组件
  20. 字符串"k:1“” 处理成字典 {'k':1,'k1':2....}

热门文章

  1. vue 导航菜单默认子路由
  2. wafII笔记
  3. 原来这才是Kafka的“真面目”
  4. HDU 2268 How To Use The Car (数学题)
  5. 获取url
  6. AtCoder ABC 070D - Transit Tree Path
  7. JavaScript基础的记录
  8. jsonp 后台返回注意事项
  9. i=i+1,i+=1与i++的区别
  10. 用JAVA的抽象类实现编码组合进度的灵活性