Java通过JNI调用dll详细过程(转)
最近项目有这样一个需求,在已有的CS软件中添加一个链接,将当前登录用户的用户名加密后放在url地址中,在BS的login方法里通过解密判断,如果为合法用户则无需再次登录直接进入平台,CS软件方提供了一个加密解密的dll文件,我们需要在action中通过该dll解密,那么就涉及到java调用dll的问题。
首先我选择了JNI方式(因为网上说的另两种方式Jawin, Jacob更不会),大体流程如下:
1、写一个java的class,在类里声明所调用的库名称和需要使用的函数(注意:需要对方法做本地声明,关键字为native。且只需要声明,而不需要具体实现)
package com;
public class javacall
{
static
{
System.loadLibrary("htgsjencrypt");
} public native static String DecodeString(char[] szSrc);
public native static String EncodeString(char[] szSrc); private static void printCharArray(char[] content)
{
String temp=new String(content);
System.out.println(temp);
} public static void main(String[] args)
{
String s="123";
char[] src=new char[100];
src=s.toCharArray();
String encode="";
printCharArray(src);
encode=javacall.EncodeString(src);
System.out.println("encode="+encode);
String decode="";
src=encode.toCharArray();
decode=javacall.DecodeString(src);
System.out.println("decode="+decode); }
}
这个地方需要提一下,新建这个class时最好不要建在默认包中,将来对这个工程打包后,在引用的工程中无法找到默认包中的class(也许是我写的不对,不过写在默认包中确实会带来不必要的麻烦)
2、对于以上编译好的class文件通过使用javah命令生成头文件javacall.h,这个文件需要被C++程序调用来生成所需的库文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
/* Header for class com_javacall */ #ifndef _Included_com_javacall
#define _Included_com_javacall
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_javacall
* Method: DecodeString
* Signature: ([C)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_javacall_DecodeString
(JNIEnv *, jclass, jcharArray); /*
* Class: com_javacall
* Method: EncodeString
* Signature: ([C)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_javacall_EncodeString
(JNIEnv *, jclass, jcharArray); #ifdef __cplusplus
}
#endif
#endif
这里需要提到一点,默认生成的头文件中写的是
#include <jni.h>
在C++的calss中引用时编译报错找不到jni.h,可以去jdk安装包的include文件夹中拷贝jni.h、jni_md.h、jawt_md.h三个文件到程序目录,这时再编译可能还报找不到jni.h的错误,可以将#include <jni.h>改为#include "jni.h",因为前者是引用系统头文件的写法
3、在VC中新建一个库文件htgsjencrypt,在新建的class文件中实现java头文件中声明的两个加密解密方法,因为第三方没有提供.lib文件,也没有.h文件,那么只能用动态使用链接库的方式来调用dll了,具体代码如下:
#include "gsjencrypt.h"
#include "com_javacall.h"
#include "windows.h"
#include <iostream>
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
////////////////////////////////////////////////////////////////////// gsjencrypt::gsjencrypt()
{ } gsjencrypt::~gsjencrypt()
{ }
typedef int (WINAPI *FDecodeString)(char szSrc[], char szDest[]);
typedef int (WINAPI *FEncodeString)(char szSrc[], char szDest[]); JNIEXPORT jstring JNICALL Java_com_javacall_EncodeString(JNIEnv * env, jclass jobject, jcharArray src)
{
HINSTANCE hDLL;
hDLL=LoadLibrary("gsjencrypt.dll");//加载动态链接库gsjencrypt.dll文件;
if(hDLL==NULL)
return ;
FEncodeString encodeString=(FEncodeString)GetProcAddress(hDLL,"EncodeString");
jsize size = (env)->GetArrayLength(src); jchar * arrayBody = (env)->GetCharArrayElements(src,);
//char * csrc=(char *)arrayBody; char csrctemp[]="";
int k=;
while(size!=)
{
csrctemp[k]=*arrayBody;
*arrayBody++;
size--;
k++;
}
char cdesttemp[]="";
encodeString(csrctemp,cdesttemp);
(env)->ReleaseCharArrayElements(src,arrayBody,);
return (env)->NewStringUTF(cdesttemp);
}
JNIEXPORT jstring JNICALL Java_com_javacall_DecodeString(JNIEnv * env, jclass jobject, jcharArray src)
{
HINSTANCE hDLL;
hDLL=LoadLibrary("gsjencrypt.dll");//加载动态链接库gsjencrypt.dll文件;
if(hDLL==NULL)
return ;
FDecodeString decodeString=(FDecodeString)GetProcAddress(hDLL,"DecodeString");
jsize size = (env)->GetArrayLength(src);
jchar * arrayBody = (env)->GetCharArrayElements(src,);
char * csrc=(char *)arrayBody;
char csrctemp[]="";
int k=;
while(size!=)
{
csrctemp[k]=*arrayBody;
*arrayBody++;
size--;
k++;
}
//arrayBody=(env)->GetCharArrayElements(dest,0);
//char * cdest=(char *)arrayBody;
char cdesttemp[]="";
decodeString(csrctemp,cdesttemp);
(env)->ReleaseCharArrayElements(src,arrayBody,);
return (env)->NewStringUTF(cdesttemp);
}
这里需要注意的是
typedef int (WINAPI *FDecodeString)(char szSrc[], char szDest[]);
typedef int (WINAPI *FEncodeString)(char szSrc[], char szDest[]);
以上两个方法是原始dll中提供给外界调用的函数接口,声明时一定要记得加WINAPI,否则调用时始终报错。
4、最后将第三方提供的gsjencrypt.dll和新生成的htgsjencrypt.dll同时拷贝到java.library.path里(jdk或者jre的bin文件中),然后将最开始写的java程序打包即可被别的工程调用。
记录一下最难解决的问题,就是不知道怎样在c++中返回给java解密后的串,因为总是想把指针的概念与java中的某个byte数组或者char数组关联起来,始终不能成功,最后尝试使用NewStringUTF才解决问题,哎,C++已经六年没用过了,真是费劲啊
Java通过JNI调用dll详细过程(转)的更多相关文章
- Java使用JNI调用DLL库
JNI是Java自带的方法,不需要引入第三方jar包,优点是因为是java自带的方法,兼容性较好,缺点就是代码书写繁琐 新建Java项目Test --> 新建测试类TestNative,声明本地 ...
- JAVA使用JNI调用C++动态链接库
JAVA使用JNI调用C++动态链接库 使用JNI连接DLL动态链接库,并调用其中的函数 首先 C++中写好相关函数,文件名为test.cpp,使用g++编译为DLL文件,指令如下: g++ -sha ...
- java 用JNA调用dll 参考文档
1 Java调用C语言动态库(JNA方式):回调函数.结构体数组传参.结构体数组返回 2jna结构体数组 JNA结构体数组 3JNA调用C语言动态链接库学习实践总结 4 Java 通过 JNA 调 ...
- ubuntu下Java通过JNI调用C
下面看一个实例,如下: public class TestJNI { static { System.loadLibrary("diaoyong"); // 程序在加载时,自动加载 ...
- 关于Java通过JNI调用C 动态链接库(DLL)
JNI介绍 用JNI实现Java和C语言的数据传递 JNI原理分析和详细步骤截图说明 jni的JNIEnv指针和jobject指针 JNI实现回调| JNI调用JAVA函数|参数和返回值的格式 Jni ...
- Java利用JNI调用C/C++写成的DLL
前言 由于学期作业的要求,笔者需要开发一个语音识别系统.出于对Java的热爱,笔者非常想用Java来写上层程序(前台+数据库的三层),又要用到Microsoft Speech SDK,所以在这些条件下 ...
- 第39篇-Java通过JNI调用C/C++函数
在某些情况下,Java语言需要通过调用C/C++函数来实现某些功能,因为Java有时候对这些功能显的无能为力,如想使用X86_64 的 SIMD 指令提升一下业务方法中关键代码的性能,又或者想要获取某 ...
- JAVA的JNI调用
由于JNI调用C和调用C++差不多,而且C++中可以混合写C代码,所以这里主要是写关于JNI调用C++的部分. 一般步骤: 先是写普通的Java类,其中包括本地方法调用. 然后编译这个Java类,调 ...
- Java通过JNI调用C
Java调用C有多种方式,本文介绍笔者最近的学习过程,避免今后再犯类似的错误. 首先,Java肯定是调用C的动态链接库,即通过编译器编译后的dll/so文件. 下面介绍gcc编译dll的方法. 一般情 ...
随机推荐
- WebKit框架 浅析
摘要 WebKit是iOS8之后引入的专门负责处理网页视图的框架,其比UIWebView更加强大,性能也更优. iOS中WebKit框架应用与解析 一.引言 在iOS8之前,在应用中嵌入网页通常需要使 ...
- Android内核驱动程序的编写和编译过程
注意:涉及的代码为android内核代码而不是android源码. 在智能手机时代,每个品牌的手机都有自己的个性特点.正是依靠这种与众不同的个性来吸引用户,营造品牌凝聚力和用户忠城度,典型的代表非ip ...
- JS-DOM操作应用高级(一)
表格应用--tBodies tHead tFoot rows cells <title>无标题文档</title> <script> window.onlo ...
- JAVA动态代理详解
1.什么是代理 代理模式是常用的Java 设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等. 2.什么是动态代理 在程 ...
- UVALive 6885 Flowery Trails
两次SPFA #include<cstdio> #include<cstring> #include<cmath> #include<vector> # ...
- s5pv210 AD转换
1:ADC:Analog-to-Digital Converter,模拟信号转数字信号,自然界一般为模拟信号,而SoC需要数字信号,所以之间通信需要ADC. 2:转换原理: 以逐次逼近式AD转换为例: ...
- jq模拟操作
1.常用模拟 trigger() $('#btn').trigger('click'); 当页面加载完,点击事件就会完成 上面也可以简写成:$('#btn').click(); 2.触发自定义事件 t ...
- 一种快速查询多点DS18B20温度的方法(转)
源:http://hi.baidu.com/james_xiao/item/79b961c90623093e45941623 一种快速查询多点DS18B20温度的方法 引言 为了满足实时性要 ...
- Efim and Strange Grade
Efim and Strange Grade time limit per test 1 second memory limit per test 256 megabytes input standa ...
- Python3基础 定义有参数有返回值函数 对传入的参数加1
镇场诗: 诚听如来语,顿舍世间名与利.愿做地藏徒,广演是经阎浮提. 愿尽吾所学,成就一良心博客.愿诸后来人,重现智慧清净体.-------------------------------------- ...