说明:两天前,老大直接给了一个动态库和接口函数说明,叫我封装好方便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下建个项目,具体步骤不说了,上图:
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管理员模式下:
先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关于两个类,一个传值的一个调用动态库的,自己写,或者请教别人吧。。。重要的程序,我全贴上去了。。。