使用Java调用DLL动态链接库的方案通常有几种方式:JNI, JNative,Jawin, Jacob.其中 JNative,Jawin, 调用方式很简单,google一下即刻解决,但是这两种方式都已不支持64系统, Jacob是Java-Com Bridge的缩写,也可以用来调用DLL。其底层也是使用JNI实现,也具有Windows 的平台依赖性,但是要求dll是可注册的,所以也有一定局限性;
回到最初的调用方式 :JNI(Java Native Interface)是Java语言本身提供的调用本地已编译的函数库的方法,本身具有跨平台性,可以在不同的机器上调用不同的本地库, JNI的应用方案是基于Java类和本地函数相映射的。其使用DLL的步骤还是相对比较麻烦,不但涉及到Java编程,还涉及到C/C++编程,一般来说,第三方提供的dll,我们需要用C++做一个中间件调用它(不建议C#实现),然后再由java去调用这给中间件以达到最终效果。
JNI的使用步骤是:
1、编写Java类,用该类将DLL对外提供的函数服务进行声明,其中的Java方法均声明为native,其方法 签名可以自定义,不实现函数体。
package com.my.util;
public class SMSUtil {
public static void main(String[] args) {
start(9, 9600);
sendMsg("测试", "189********");
stop();
}
static
{
System.loadLibrary("SMSService"); //vc++实现的中间件"SMSService.dll"
}
public static native int start(int port, int baudRate);
public static native int stop();
public static native int sendMsg(String msg, String phoneCode);
}
2、 编译成class, 在class根目录执行 Javah 生成 .h
命令: c:\workspace\smsutil\bin>javah com.my.util
生成 com_my_util_SMSUtil.h
生成的函数定义没有参数名称,所以需要对其做简单的修改:
JNIEXPORT jint JNICALL Java_com_my_util_SMSUtil_start
(JNIEnv * env, jclass obj, jint port, jint baudRate);
JNIEXPORT jint JNICALL Java_com_my_util_SMSUtil_stop
(JNIEnv * env, jclass obj);
JNIEXPORT jint JNICALL Java_com_my_util_SMSUtil_sendMsg
(JNIEnv * env, jclass obj, jstring jMsg, jstring jPhone);
3、编写C/C++代码实现.h头文件中声明的函数, 实现接口方法,可以在实现方法中调用第三方DLL库
打开vs2010,建立名称为SMSService的win32控制台应用程序。如下所示:
设置应用程序类型:DLL,附加选项:导出符号。如下图所示:
点击完成。
复制 %jdk%\include\win32\jni_md.h和%jdk%\include\jni.h 到项目根目录下,复制com_my_util_SMSUtil.h到项目根目录,com_my_util_SMSUtil.h文件的引用 include <jni.h> 修改成 include "jni.h", 然后工程头文件中引用其以上三个文件
删除SMSService.h ,SMSService.cpp 所有代码,然后在stdafx.h中写入:#include “com_my_util_SMSUtil.h", SMSService.cpp引用stdafx.h, 实现定义中的方法, 编译生成SMSService.dll,SMSService.lib, 复制到调用着的 system32目录,至此整个实现过程可以说已经完成。
4、接下来可以在 SMSService.cpp 中调用第三方dll
#include "stdafx.h"
#include "stdlib.h"
typedef DWORD (_stdcall *pSMSSendMessageFun)(char* Msg,char* PhoneNo);
typedef int (_stdcall *pSMSStartServiceFun)(int nPort,DWORD BaudRate , int Parity, int DataBits ,int StopBits,int FlowControl,char* csca);
typedef int (_stdcall *pSMSStopSericeFun)();
HINSTANCE hDll;
JNIEXPORT jint JNICALL Java_com_my_util_SMSUtil_start
(JNIEnv * env, jclass obj, jint port, jint baudRate)
{
hDll = LoadLibrary("SMSDLL.dll"); //调用程序目录下须要有此动态库文件
if(hDll == NULL)
{
return -1;
}
pSMSStartServiceFun SMSStartServiceFun;
SMSStartServiceFun = (pSMSStartServiceFun)GetProcAddress(hDll, "SMSStartService");
if(SMSStartServiceFun)
{
int iflag = SMSStartServiceFun(port,baudRate,2,8,0,0,"card");
if(iflag != 0)
{
printf("Service start success ");
return 0;
}
else
{
printf("Service start fail ");
pSMSGetLastErrorFun SMSGetLastErrorFun;
SMSGetLastErrorFun = (pSMSGetLastErrorFun)GetProcAddress(hDll, "SMSGetLastError");
char Err[1024];
memset(Err, 0, 1024);
if(SMSGetLastErrorFun)
{
int len = SMSGetLastErrorFun(Err);
if(len > 0)
{
printf(Err);
}
}
return -1;
}
}
else
{
return -1;
}
}
JNIEXPORT jint JNICALL Java_com_my_util_SMSUtil_stop
(JNIEnv *, jclass)
{
//HINSTANCE hDll = LoadLibrary("SMSDLL.dll"); //调用程序目录下须要有此动态库文件
if(hDll == NULL)
{
return -1;
}
pSMSStopSericeFun SMSStopSericeFun;
SMSStopSericeFun = (pSMSStopSericeFun)GetProcAddress(hDll, "SMSStopSerice");
if(SMSStopSericeFun)
{
int iflag = SMSStopSericeFun();
if(iflag != 0)
{
printf("Serice stop success ");
FreeLibrary(hDll);
return 0;
}
else
{
printf("Serice stop fail ");
FreeLibrary(hDll);
return -1;
}
}
else
{
return -1;
FreeLibrary(hDll);
}
}
JNIEXPORT jint JNICALL Java_com_my_util_SMSUtil_sendMsg
(JNIEnv * env, jclass obj, jstring jMsg, jstring jPhone)
{
//HINSTANCE hDll = LoadLibrary("SMSDLL.dll"); //调用程序目录下须要有此动态库文件
if(hDll == NULL)
{
return -1;
}
char* msg = NULL;
msg = jstringToWindows(env,jMsg);
char* phone = NULL;
phone = jstringToWindows(env,jPhone);
pSMSSendMessageFun SMSSendMessageFun;
pSMSQueryFun SMSQueryFun;
SMSSendMessageFun = (pSMSSendMessageFun)GetProcAddress(hDll, "SMSSendMessage");
SMSQueryFun = (pSMSQueryFun)GetProcAddress(hDll, "SMSQuery");
if(SMSSendMessageFun && SMSQueryFun)
{
SMSSendMessageFun(msg, phone);
Sleep(2000);
}
printf("message send done ");
return 0;
}
char* jstringToWindows( JNIEnv *env, jstring jstr )
{
int length = env->GetStringLength(jstr);
const jchar* jcstr = env->GetStringChars(jstr, 0);
char* rtn = (char*)malloc(length*2+1);
int size = 0;
size = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)jcstr, length, rtn,(length*2+1), NULL, NULL);
if( size <= 0 )
return NULL;
env->ReleaseStringChars(jstr, jcstr);
rtn[size] = 0;
return rtn;
}
5、如果需要在64位环境中运行,需要修改工程配置:
SMSService属性
字符集设置使用多字节字符集,否则 LoadLibrary("SMSDLL.dll") 或出现错误
运行库设置成空,否则调用会出现错误
重新编译dll, 回到初始的java类,调用Main,测试成功!