java 封装动态库_java通过JNI方法封装VC++的Dll(大四实习+1)

本文详细介绍了如何使用Java的JNI技术封装VC++编译的DLL动态库,包括设置本地方法声明、生成头文件、建立VC项目、编写封装代码,并提供了测试案例。在遇到字符串参数传递问题时,作者借助前辈的帮助解决了传出值的问题。
摘要由CSDN通过智能技术生成

说明:两天前,老大直接给了一个动态库和接口函数说明,叫我封装好方便java环境调用接口函数,java没搞过啊,C++也才接触几个月,在网上找了一些文档,全是入门级的,全是自己去建dll,然后再调,没有用java编程软件建立项目,显得非常凌乱。。。

开始自己照着网上教程来编的差不多了,就一个函数卡住了,该函数需要把两个字符串参数传出来,当时不懂java没有把值传进传出的概念,用java测试程序怎么都取不到传出的值,o(︶︿︶)o

唉,各种在VC里加函数瞎搞,测试,就是传不出来,后来咨询了办公室的一位搞java语言的前辈(勤学好问,少走弯路),他给了我一个他自己编写的一个类,通过该类可以把值传出来,感谢他。。。。

下面介绍我的步骤过程,如果有词不达意,语句混乱,汉字错误的话请包涵,欢迎各种代码熟练工的谩骂和指正:

1、提供的动态库:GEIT_GoldCardDev.dll,

导出函数: int Set_Bank(int

BankId); int Open_Com(int ComPort,int Baud);

int

Close_Com(); int

Sel_Module(int Module);

int ReadMagCard(int TrkId,int Timeout);

int WriteMagCard(int TrkId,int Timeout,String

Trak2Data,String Trk3Data);

2、在eclpse下建个项目,具体步骤不说了,上图:

a4c26d1e5885305701be709a3d33442f.png

3、要对dll里面的方法做本地声明:

在javacall.java里做本地声明,因为我的程序加载动态库和自定义类都有专门的类处理,可能会为你带来困扰,我只带来编程思想及步骤,具体实现方法还得个人去完成:

public class javacall {

public

native int Set_Bank(int BankId);

public native int Open_Com(int ComPort,int

Baud);

public native int Close_Com();

public native int Sel_Module(int Module);

public native JniResult

ReadMagCard(int TrkId,int Timeout);

public native int WriteMagCard(int TrkId,int

Timeout,String Trak2Data,String Trk3Data);

注:JniResult

类就是能实现多个参数值传出的功能能,当然如果你的项目文文件夹里如果有这个类的话,软件会自动帮你在前面加一句话:import

com.guoguang.util.JniResult;

4、现在进入eclipse项目文件bin目录下,把地址copy下,进入CMD管理员模式下:

a4c26d1e5885305701be709a3d33442f.png

先cd到bin目录下,因为eclipse把编译好的类文件都放在下面,第一次由于把类文件地址输错报错了,生成头文件,javacall.class在com文件下的guoguang文件下的jni文件夹里。头文件有了。。。

5、下面开始建立VC项目进行封装了哈,我用的VS2008,新建个Dll文件,①win32 ②win32项目里 ③

应用程序设置 ④Dll OK,dll文件建好鸟。。。下面开始贴代码了啊,看个人理解了。。。

⒈先把刚刚生成的头文件导入到项目里

#include

#ifndef _Included_com_guoguang_jni_javacall

#define _Included_com_guoguang_jni_javacall

#ifdef __cplusplus

extern "C" {

#endif

JNIEXPORT jint JNICALL

Java_com_guoguang_jni_javacall_Set_1Bank

(JNIEnv *, jobject, jint);

JNIEXPORT jint JNICALL

Java_com_guoguang_jni_javacall_Open_1Com

(JNIEnv *, jobject, jint, jint);

JNIEXPORT jint JNICALL

Java_com_guoguang_jni_javacall_Close_1Com

(JNIEnv *, jobject);

JNIEXPORT jint JNICALL

Java_com_guoguang_jni_javacall_Sel_1Module

(JNIEnv *, jobject, jint);

JNIEXPORT jobject JNICALL

Java_com_guoguang_jni_javacall_ReadMagCard

(JNIEnv *, jobject, jint, jint);

JNIEXPORT jint JNICALL

Java_com_guoguang_jni_javacall_WriteMagCard

(JNIEnv *, jobject, jint, jint, jstring,

jstring);

#ifdef __cplusplus

}

#endif

#endif

⒉在项目生成的头文件里定义函数指针:

typedef int (WINAPI *SETBANK)(int BankId);

typedef int (WINAPI *OPENCOM)(int ComPort,int Baud);

typedef int (WINAPI *CLOSECOM)();

typedef int (WINAPI *SELMODULE)(int Module);

typedef int (WINAPI *READCARD)(int TrkId,int Timeout,unsigned char

*Trk2Data,unsigned char *Trk3Data);

typedef int (WINAPI *WRITECARD)(int TrkId,int Timeout,unsigned char

*Trk2Data,unsigned char *Trk3Data);

⒊在项目生成的cpp文件里面链接动态库代码

// dllmain.cpp : 定义 DLL 应用程序的入口点。

#include "stdafx.h"

#include "dllmain.h"

#include "stdio.h"

#include "iostream"

#include

#include

using namespace std;

SETBANK m_setbank;

OPENCOM m_opencom;

CLOSECOM m_closecom;

SELMODULE m_selmodule;

READCARD m_readcard;

WRITECARD m_writecard;

BOOL APIENTRY DllMain( HMODULE hModule,

DWORD ul_reason_for_call,

LPVOID lpReserved

)

{

switch (ul_reason_for_call)

{

case DLL_PROCESS_ATTACH:

{ //加载动态库------------------------------

HINSTANCE hInst;

char dpath[1024];

memset(dpath,0,1024);

char lpath[1024];

memset(lpath,0,1024);

GetModuleFileName(hModule,dpath,1024);

for(int i=

strlen(dpath);i>0;i--){

if(dpath[i]=='\\'){

break;

}else{

dpath[i]='\0';

}

}

sprintf(lpath,"%sGEIT_GoldCardDev.dll",dpath);

hInst =

LoadLibrary(lpath);

if(!hInst){

// MessageBox(NULL,"加载ICC_GEIT.dll失败","错误",0);

}

m_setbank =

(SETBANK)GetProcAddress(hInst,"Set_Bank");

m_opencom =

(OPENCOM)GetProcAddress(hInst,"Open_Com");

m_closecom =

(CLOSECOM)GetProcAddress(hInst,"Close_Com");

m_selmodule =

(SELMODULE)GetProcAddress(hInst,"Sel_Module");

m_readcard =

(READCARD)GetProcAddress(hInst,"ReadMagCard");

m_writecard =

(WRITECARD)GetProcAddress(hInst,"WriteMagCard");

break;

}

case DLL_THREAD_ATTACH:

case DLL_THREAD_DETACH:

case DLL_PROCESS_DETACH:

break;

}

return TRUE;

}

⒋然后你就得新建个cpp文件,开始封装了.

// GeitGoldCardDev_JNI.cpp : 定义 DLL 应用程序的导出函数。

//

#include "stdafx.h"

#include "com_guoguang_jni_javacall.h"

#include "dllmain.h"

extern SETBANK m_setbank;

extern OPENCOM m_opencom;

extern CLOSECOM m_closecom;

extern SELMODULE m_selmodule;

extern READCARD m_readcard;

extern WRITECARD m_writecard;

JNIEXPORT jint JNICALL

Java_com_guoguang_jni_javacall_Set_1Bank

(JNIEnv *env, jobject jo, jint BankId)

{

return

(jint)m_setbank((int)BankId);

}

JNIEXPORT jint JNICALL

Java_com_guoguang_jni_javacall_Open_1Com

(JNIEnv *env, jobject jo, jint ComPort, jint Baud)

{

return

(jint)m_opencom((int)ComPort,(int)Baud);

}

JNIEXPORT jint JNICALL

Java_com_guoguang_jni_javacall_Close_1Com

(JNIEnv *env, jobject jo)

{

return (jint)

m_closecom();

}

JNIEXPORT jint JNICALL

Java_com_guoguang_jni_javacall_Sel_1Module

(JNIEnv *env, jobject jo, jint Module)

{

return

(jint)m_selmodule((int)Module);

}

JNIEXPORT jobject JNICALL

Java_com_guoguang_jni_javacall_ReadMagCard

(JNIEnv *env, jobject jo, jint TrkId, jint Timeout)

{

char trk2[1024];

char trk3[1024];

memset(trk2,0,1024);

memset(trk3,0,1024);

int rc =

m_readcard((int)TrkId,(int)Timeout,(unsigned char *)trk2,(unsigned

char *)trk3);

//创建返回对像

jclass cls =

env->FindClass("com/guoguang/util/JniResult");

jobject obj =

env->AllocObject(cls);

jmethodID mid =

env->GetMethodID(cls, "setResultCode",

"(I)V");

env->CallVoidMethod(obj, mid,

(jint)rc);

if(rc>=0){

jbyteArray rcValue =

env->NewByteArray(strlen(trk2));

env->SetByteArrayRegion(rcValue,

0, strlen(trk2), (jbyte*)trk2);

jbyteArray rcValue2 =

env->NewByteArray(strlen(trk3));

env->SetByteArrayRegion(rcValue2,

0, strlen(trk3), (jbyte*)trk3);

jmethodID mid =

env->GetMethodID(cls, "setResultData",

"(Ljava/lang/String;Ljava/lang/Object;)V");

jstring trackName =

env->NewStringUTF("trk2Data");

env->CallVoidMethod(obj,

mid, trackName,rcValue);

jstring trackName2 =

env->NewStringUTF("trk3Data");

env->CallVoidMethod(obj,

mid, trackName2,rcValue2);

//jstring trackName2 =

env->NewStringUTF("prapduLen");

//env->CallVoidMethod(obj,

mid, trackName2,(jshort)strlen(part));

}

return obj;

}

JNIEXPORT jint JNICALL

Java_com_guoguang_jni_javacall_WriteMagCard

(JNIEnv *env, jobject jo, jint TrkId, jint Timeout, jstring

Trk2Data, jstring Trk3Data)

{

char * trk2 = (char

*)env->GetStringUTFChars(Trk2Data,0);

char * trk3 = (char

*)env->GetStringUTFChars(Trk3Data,0);

int rc =

m_writecard((int)TrkId,(int)Timeout,(unsigned char *)trk2,(unsigned

char *)trk3);

return (jint)rc;

}

⒍编译通过,记得设置项目属性,Release输出,静态链接库,使用多字节字符集等。。。

⒎把生成的动态库和之前调用的动态库,放入eclipse项目os.win32下,记住不能直接复制到文件下,这样导致程序调不到库文件,应该在eclipse软件项目中包的位置右键粘帖。。。

⒏再次补充javacall的程序,因为我们刚刚只是声明了本地方法,还没有教会它怎么去调用动态库,当然这里会用到另一个类-Library,javacall完整程序如下:

package com.guoguang.jni;

import java.io.UnsupportedEncodingException;

import java.net.URLDecoder;

import com.guoguang.util.JniResult;

import com.guoguang.util.Library;

public class javacall {

private static String workdir=null;

static

{

loadLibrary();

}

public native int Set_Bank(int BankId);

public native int Open_Com(int ComPort,int

Baud);

public native int Close_Com();

public native int Sel_Module(int Module);

public native JniResult ReadMagCard(int TrkId,int

Timeout);

public native int WriteMagCard(int TrkId,int

Timeout,String Trak2Data,String Trk3Data);

private static void loadLibrary(){

workdir =

javacall.class.getProtectionDomain().getCodeSource().getLocation().getFile();

try {

workdir =

URLDecoder.decode(workdir,"UTF-8");

} catch

(UnsupportedEncodingException e) {

e.printStackTrace();

}

workdir = workdir.substring(1,

workdir.lastIndexOf("/")+1);

try{

Library.extract("/os/win32",

"GEIT_GoldCardDev.dll",workdir);

Library.extract("/os/win32",

"MyDll.dll",workdir);

}catch(Exception e){

System.out.println("提取动态库失败:"+e.getMessage());

e.printStackTrace();

}

String lPath = workdir+"MyDll.dll";

System.out.println("loadLibrary:"+lPath);

try{

System.load(lPath);

System.out.println(lPath+"

已加载.");

}catch (Exception e) {

System.out.println(lPath+"

加载失败!");

e.printStackTrace();

}

}

public static String getWorkdir() {

return workdir;

}

public static void setWorkdir(String workdir) {

javacall.workdir = workdir;

}

⒐现在可以编写个测试类了。。。Test.java

package com.guoguang.jni;

import com.guoguang.util.JniResult;

public class Test {

public static void main(String[] args) {

javacall ggd=new

javacall();

int rc = ggd.Open_Com(4,

9600);

System.out.println(rc);

JniResult jr =

ggd.ReadMagCard(2, 10);

System.out.println(jr);//操作返回码

2成功

System.out.println(jr.getResultCode());

System.out.println(jr.getResultDataStr("trk2DataStr"));//二磁道

System.out.println(jr.getResultDataStr("trk3DataStr"));//三磁道

}

总结,如果我是什么都不懂,进来看到自己写的东西我会说这个大!#!#¥写的什么乱七八糟的啊,完全看不懂,说实话,我也觉得挺乱的,没办法,只能写成这样,建议先去看看这个http://singlerwong.spaces.eepw.com.cn/articles/article/item/25111和这个http://blog.csdn.net/rohsuton/article/details/3637272关于两个类,一个传值的一个调用动态库的,自己写,或者请教别人吧。。。重要的程序,我全贴上去了。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值