700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > Java调用C/C++编写的第三方dll动态链接库(zz)

Java调用C/C++编写的第三方dll动态链接库(zz)

时间:2024-06-07 10:50:37

相关推荐

Java调用C/C++编写的第三方dll动态链接库(zz)

这里主要用的方法是JNI。在网上查资料时看到很多人说用JNI非常的复杂,不仅要看很多的文档,而且要非常熟悉C/C++编程。恐怕有很多人在看到诸如此类的评论时已经决定绕道用其他方法了。本文将做详细的介绍。

AD:51CTO网+ 首届中国APP创新评选大赛火热招募中……

最近在用weka做一个数据挖掘相关的项目,不得不说,weka还是一个不错的开放源代码库,提供了很多最常用的分类和聚类算法。

在我的项目中要用到一个聚类算法,Affinity Propagation(AP),由多伦多大学的Brendan J. Frey发表于。相比其他的聚类算法,AP算法的聚类结果更加准确。

在AP的官方网站公布了AP算法的动态链接库,我的目标就是实现在Java工程中调用这个动态链接库。

在网上查了资料,发现,如果仅仅是想调用Windows的Native API还是比较省事的,这里我主要针对第三方dll的调用。

下面进入正题。

这里主要用的方法是JNI。在网上查资料时看到很多人说用JNI非常的复杂,不仅要看很多的文档,而且要非常熟悉C/C++编程。恐怕有很多人在看到诸如此类的评论时已经决定绕道用其他方法了。但是,假如你要实现的功能并不复杂(简单的参数传递,获取返回值等等),我还是支持使用这个方法的。

Java Native Interface,简称JNI,是Java平台的一部分,可用于让Java和其他语言编写的代码进行交互。下面是从网上摘取的JNI工作示意图。

图1 JNI的工作模式

下面就举具体的例子说明一下使用步骤:

1) 编写一个类,声明native方法

publicclassAPCluster{ publicnativeint[]CallAPClusterDll(intarg_Int, double[]arg_DoubleArray, booleanarg_boolean); static{ System.loadLibrary("APClusterDllMedium"); } }

上面是APCluster.java文件,定义了一个APCluster类,其中有一个方法CallAPClusterDll(),需要传递三种不同类型的参数,并且返回一个整型数组。

注意,这里只需要声明这个方法,并不需要实现,具体实现就在APClusterDllMedium中。

APClusterDllMedium就像中介一样,Java通过调用这个中介Dll中的CallAPClusterDll方法,间接调用真正的第三方Dll。

2)编译生成.h文件

第一步:

javac APCluster.java 生成APCluster.class

第二步:

javah APCluster 生成APCluster.h头文件,内容如下:

/*DONOTEDITTHISFILE-itismachinegenerated*/#include<jni.h> /*HeaderforclassAPCluster*/#ifndef_Included_APCluster #define_Included_APCluster #ifdef__cplusplus extern"C"{ #endif10/* *Class:APCluster *Method:CallAPClusterDll *Signature:(I[DZ)[I */JNIEXPORTjintArrayJNICALLJava_APCluster_CallAPClusterDll (JNIEnv*,jobject,jint,jdoubleArray,jboolean); #ifdef__cplusplus } #endif21#endif

注意,APCluster.h这个头文件的内容是不能修改的,否则JNI会找不到相对应的CallAPClusterDll()的实现。

3)创建C/C++工程,实现CallAPClusterDll()方法。

创建一个C/C++工程,工程名为APClusterDllMedium(其实,生成的dll名为APClusterDllMedium即可),导入APCluster.h这个头文件,并创建一个CPP文件,实现.h文件中的方法。

图2 新建工程结构

由于我创建的工程是win32控制台程序,所以最后默认生成的是.exe文件,所以还要做一步工程属性修改,让它生成.dll后缀文件。

打开Project Property ->General,做以下修改:

图3 修改工程属性

下面就是实现 JNIEXPORT jintArray JNICALL Java_APCluster_CallAPClusterDll (JNIEnv *, jobject, jint, jdoubleArray, jboolean); 这个方法了。先贴代码再慢慢解释吧。

#include"APCluster.h" #include<stdio.h> #include<windows.h> #ifdef__cplusplus extern"C"{ #endif typedefint*(__stdcall*APCLUSTER32)(double*,unsignedint,bool); JNIEXPORTjintArrayJNICALLJava_APCluster_CallAPClusterDll (JNIEnv*env,jobject_obj,jint_arg_int,jdoubleArray_arg_doublearray,jboolean_arg_boolean) { HMODULEdlh=NULL; APCLUSTER32apcluster32; if(!(dlh=LoadLibrary("apclusterwin.dll")))//第三方DLL位置 { printf("LoadLibrary()failed:%d\n",GetLastError()); } if(!(apcluster32=(APCLUSTER32)GetProcAddress(dlh,"apcluster32")))//具体调用apcluster32方法 { printf("GetProcAddress()failed:%d\n",GetLastError()); } intm_int=_arg_int;//类型转换 double*m_doublearray=env->GetDoubleArrayElements(_arg_doublearray,NULL); boolm_boolean=_arg_boolean; int*ret=(*apcluster32)(m_doublearray,m_int,m_boolean);/*actualfunctioncall*/jintArrayresult=env->NewIntArray(_arg_int); env->SetIntArrayRegion(result,0,_arg_int,(constjint*)ret); FreeLibrary(dlh);/*unloadDLLandfreememory*/if(ret) { free(ret); } returnresult; } #ifdef__cplusplus } #endif

a)首先为了#include <jni.h>,必须添加JNI所在的目录。

打开Project Property -> C/C++ -> General -> Additional Include Directories添加相应目录:

图4 添加JNI目录

b)在APCluster.h文件中自动生成的函数,只标识了函数参数类型,为了引用这些参数,自己起一个相应的名字:

JNIEXPORT jintArray JNICALL Java_APCluster_CallAPClusterDll

(JNIEnv *env, jobject _obj, jint _arg_int, jdoubleArray _arg_doublearray, jboolean _arg_boolean) ......

c)声明函数指针,就是你要调用的第三方dll中函数的类型。

d)LoadLibrary,导入真正的第三方Dll,并找到要调用的方法的函数地址。

把这个函数地址赋值给函数指针,接下来就可以通过这个函数指针调用真正的apcluster函数了!

e)类型转换:

读读jni.h文件就知道jdouble和double其实是一个东西,jboolean就是unsigned char类型,jni.h中是这么声明的:

typedefunsignedcharjboolean; typedefunsignedshortjchar; typedefshortjshort; typedeffloatjfloat; typedefdoublejdouble;

但是数组类型就没有这么简单,获取数组要使用类型相对应的env->GetTypeArrayElement(jTypeArray...)。

最后,要返回一个jint类型的数组,就要新创建一个此类型的数组,再为其赋值:

jintArrayresult=env->NewIntArray(_arg_int); env->SetIntArrayRegion(result,0,_arg_int,(constjint*)ret);

其中,_arg_int代表的是创建数组的长度。

最后return result。

4)Build这个工程。

Build,生成相应的APCluster.dll文件,将这个dll放到java工程目录下。

图5 将生成的dll放到java工程下

5)编写测试java程序,调用dll库。

以下为测试程序,Test.java:

publicclassTest { publicstaticvoidmain(String[]args) { doublearg_doublearray[]={0.1,0.2,0.3}; intarg_int=3; booleanarg_boolean=true; int[]result=newAPCluster().CallAPClusterDll(arg_int,arg_doublearray,arg_boolean); ..... } }

到此,java调用第三方dll就基本完成了。

本文也主要是介绍大概的操作流程,至于具体应该使用哪些API就只有去研究官方文档了。

另外还有一些需要注意的问题,比如64位的程序去调用32位的dll会报错啊等等...这些都是细节问题了。

最后,个人认为,自己动手实践还是很重要,网上都说这个复杂那个难,但是至于难还是不难,还是要实践了才知道...不能不去尝试...

原文链接:/AnnieKim/archive//01/01/2309567.html

来源:/art/01/311363.htm

来自为知笔记(Wiz)

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。