首先介绍一下JNI吧!

JNI 是Java提供的一个用于调用本地接口的接口层,位于Java代码 和 本地代码之间的一层;主要功能是 数据类型的转换,还有就是通过这一层来调用本地代码!

下面就说说Java 调用 C++  dll是怎么实现的吧!

1、首先用Java代码制作接口层

package NEU.SOFT;

public class NEUdll
{
public NEUdll()
{
}
//供Java调用的本地代码
public native char[] Descrypt(boolean if_encrypt, char[] src_str_out,int src_len,char[] out_src_out, int out_len_out,char[] hex_des_key_out);
}

这样就可以在Java代码中调用Descrypt  这个方法了;记住 关键是 声明本地函数  关键字native

下面是调用Descrypt 方法的Java代码(红色是关键)

import NEU.SOFT.NEUdll;
public class helpMain {
public static void main(String[] args)
{
System.out.println("开始啦~~~~!!");
//加载NEUSOFT.DLL 位于 system32下面
System.loadLibrary("NEUSOFT");
NEUdll neu = new NEUdll();
String src_str = "abcd";
char[] src = {'a','b','c','d'};
char[] key = {'N','E','U','S','O','F','T','2'};
char[] out_data = new char[10000];
char[] getData = neu.Descrypt(true, src, 4, out_data, 10000, key); //
String data = String.valueOf(getData);
System.out.println("结束啦~~~~!!" + data);
}
}

  接下来是要利用C++代码,编写DLL

  既然是Java调用,自然是调用Java的类,因此需要将“接口层”那段代码变成.h文件  javah  .class文件的包名类文件名(不带后缀)  eg:javah  NEU.SOFT.NEUdll  (是class文件 不是  Java源文件)

  现在就生成了一个 NEU.SOFT.NEUdll.h的文件

  新建一个工程 选择 win32 Dynamic link library,然后将刚刚生成的.h头文件放到工程目录下,转到新建的项目中 添加代码 #include NEU.SOFT.NEUdll.h 然后打开NEU.SOFT.NEUdll.h  将里面的#include<jni.h>  改为 #include"jni.h"  在%Javahome% 的目录下 找到

        #include "jni.h"
        #include "jni_md.h"

  这两个.h文件  也放到新建的DLL工程目录下。

  打开刚刚生成的.h文件  可以看到里面有一个函数  样子大概和java接口层中的样子差不多,

  

JNIEXPORT jcharArray JNICALL Java_NEU_SOFT_NEUdll_Descrypt
(JNIEnv *, jobject, jboolean, jcharArray, jint, jcharArray, jint, jcharArray);

  现在就编写他的函数体就行了(在#include  NEU.SOFT.NEUdll.h 的文件中编写),C++代码 如下:

JNIEXPORT jcharArray JNICALL Java_NEU_SOFT_NEUdll_Descrypt
(JNIEnv* env, jobject obj, jboolean in_if_encrypt,jcharArray in_src_str, jint in_src_len, jcharArray in_out_src, jint in_out_len,jcharArray in_hex_des_key)
{ jchar* src_str_array = (env)->GetCharArrayElements(in_src_str, NULL ); //明文
int src_str_array_len = (env)->GetArrayLength(in_src_str); //明文长度
jchar* out_str_array = (env)->GetCharArrayElements(in_out_src, NULL ); //密文
jchar* hex_des_key_array = (env)->GetCharArrayElements(in_hex_des_key, NULL ); //密钥
//对输入的长度进行类型转换
int int_in_out_len = (int)in_out_len;
int& replace_in_out_len = int_in_out_len; //Unicode to ascii
char* in_hex_des_key_asiic = UnicodeToAnsi(hex_des_key_array,8);
char* src_str_array_asiic = UnicodeToAnsi(src_str_array,src_str_array_len);
//加密
char* test_key = "NEUSOFT2";
Descrypt(in_if_encrypt,(unsigned char *)src_str_array_asiic,in_src_len,(unsigned char *)out_str_array, replace_in_out_len,test_key); int len = strlen((char *)out_str_array); //加密后长度
jcharArray ret_array = env->NewCharArray(len); //返回数组
//将密文out_str_array 转为 jcharArray 赋值给ret_array 并返回
jchar *pArray ;
pArray = (jchar*)calloc(len, sizeof(jchar));
int i=0;
for(i = 0; i < len; i++)
{
*(pArray + i) = *((unsigned char *)out_str_array + i);
}
env->SetCharArrayRegion(ret_array,0,len,pArray);
free(pArray); //释放内存 return ret_array;
}

  编写完之后,F7  编译,就会生成DLL文件,放到system32 目录下,就可以像第二段代码中那也调用了。

  步骤小结:1、用Java编写类

       2、使用javah命令将这个类变为.h头文件

       3、在C++工程中,#include 这个头文件(记住修改<>  为 "",还要#include 另外两个)

       4、用C++代码 完成.h头文件中函数内容的编写

       5、生成DLL文件,放到 system32下面

       6、Java代码加载这个文件  产生一个对象,通过这个对象调用里面的方法就行。

  杂记:在生成的.h文件中 函数声明中有JNIEnv* env, jobject obj这样两个参数  其中第一个  作用很大

        可以通过它去获取数组的元素  长度  为数组赋值等很多操作。

      还有就是Java  jni  本地程序   三者之间数据类型的对应关系,网上随便一百度就行  这儿就不写了

补充,在C++中,使用完传入的数组元素后需要执行以下函数:

    if (in_src_str)
{
env->ReleaseCharArrayElements(in_src_str,src_str_array,);
}
if (in_out_src)
{
env->ReleaseCharArrayElements(in_out_src,out_str_array,);
}
if (in_hex_des_key)
{
env->ReleaseCharArrayElements(in_hex_des_key,hex_des_key_array,);
}
if (in_out_len)
{
env->ReleaseIntArrayElements(in_out_len,src_out_len,);
}

  网上都是这么做的,具体原因不详!

第二版C++代码如下:

JNIEXPORT jcharArray JNICALL Java_NEU_SOFT_NEUdll_Descrypt
(JNIEnv* env, jobject obj, jboolean in_if_encrypt, jcharArray in_src_str,
jint in_src_len, jcharArray in_hex_des_key, jcharArray in_out_src, jintArray in_out_len)
{ jchar* src_str_array = (env)->GetCharArrayElements(in_src_str, NULL ); //明文
int src_str_array_len = (env)->GetArrayLength(in_src_str); //明文长度
jchar* out_str_array = (env)->GetCharArrayElements(in_out_src, NULL ); //密文
jchar* hex_des_key_array = (env)->GetCharArrayElements(in_hex_des_key, NULL ); //密钥
jint* src_out_len = (env)->GetIntArrayElements(in_out_len, NULL ); //密钥 //Unicode to ascii
char* in_hex_des_key_asiic = UnicodeToAnsi(hex_des_key_array,);
if (!in_hex_des_key_asiic)
{
return NULL;
} char* src_str_array_asiic = UnicodeToAnsi(src_str_array,src_str_array_len);
if (!src_str_array_asiic)
{
return NULL;
} //加密
char* test_key = in_hex_des_key_asiic;
Descrypt(in_if_encrypt,(unsigned char *)src_str_array_asiic,
in_src_len,(unsigned char *)out_str_array,
(int&)*src_out_len,test_key); //将密文out_str_array 转为 jcharArray 赋值给ret_array 并返回
int len = strlen((char *)out_str_array); //加密后长度
jcharArray ret_array = env->NewCharArray(len); //返回数组 jchar *pArray ;
pArray = (jchar*)calloc(len, sizeof(jchar));
int i=;
for(i = ; i < len; i++)
{
*(pArray + i) = *((unsigned char *)out_str_array + i);
} env->SetCharArrayRegion(ret_array,,len,pArray);
free(pArray); //释放内存 if (in_hex_des_key_asiic)
{
delete[] in_hex_des_key_asiic;
in_hex_des_key_asiic = NULL;
} if (src_str_array_asiic)
{
delete[] src_str_array_asiic;
src_str_array_asiic = NULL;
} if (in_src_str)
{
env->ReleaseCharArrayElements(in_src_str,src_str_array,);
}
if (in_out_src)
{
env->ReleaseCharArrayElements(in_out_src,out_str_array,);
}
if (in_hex_des_key)
{
env->ReleaseCharArrayElements(in_hex_des_key,hex_des_key_array,);
}
if (in_out_len)
{
env->ReleaseIntArrayElements(in_out_len,src_out_len,);
} return ret_array; } //将宽字节wchar_t*转化为单字节char*
char* UnicodeToAnsi( const wchar_t* szStr ,int len)
{
char* ret_data = NULL;
int nLen = WideCharToMultiByte( CP_ACP, , szStr, len, NULL, , NULL, NULL );
if (nLen == )
{
return NULL;
}
char* pResult = new char[nLen];
WideCharToMultiByte( CP_ACP, , szStr, -, pResult, nLen, NULL, NULL ); ret_data = new char[nLen+];
memset(ret_data, , nLen+);
strncpy(ret_data, pResult, len);
ret_data[len] = '\0'; if (pResult)
{
delete [] pResult;
} return ret_data;
}

C++

[JNI] Java 调用 C++ dll的更多相关文章

  1. paip.java 调用c++ dll so总结

    paip.java 调用c++ dll so总结 ///////JNA (这个ms sun 的) 我目前正做着一个相关的项目,说白了JNA就是JNI的替代品,以前用JNI需要编译一层中间库,现在JNA ...

  2. Java调用第三方dll文件的使用方法 System.load()或System.loadLibrary()

    Java调用第三方dll文件的使用方法 public class OtherAdapter { static { //System.loadLibrary("Connector") ...

  3. 巧用C#做中间语言 实现Java调用.net DLL

    本文将详细为大家介绍一个java调用.net DLL的方法,以实现特殊的客户的特殊要求:“在Java项目中必须使用其提供的用.net写的DLL加密机制!” 环境与工具: ◆.net framework ...

  4. cocos2d 中使用jni Java 调用 C++ 方法

    1.首先是LoadLibrary cocos2d中的C++代码会编译成一个.so文件.放在安卓文件夹下的libs/armeabi 下,然后java会load进来,这步我们不用做了,由于cocos2d已 ...

  5. java调用C++ DLL库方法

    最近一个项目要开发网页端人脸识别项目,人脸识别的算法已经写好,是C++版,但是网页端要求使用Java后台,这就涉及到Java调用DLL的问题.经过查找,实现了一个简单的例子. 1.第一步,先在Java ...

  6. java调用c++ dll出现中文乱码

    近期的开发用到了使用java调用本机动态连接库的功能,将文件路径通过java调用C++代码对文件进行操作. 在调用中假设路径中包括有中文字符就会出现故障.程序执行就会中止. 以下用一个小样例,来说明记 ...

  7. java调用c#dll文件配置

    1 在强大的c#语言和java语言之间,二者难免会因为某些特殊的要求会相互调用. 下面就以java调用c#的dll为例做详细介绍 1  在vs中的环境设置如下图,图片中程序仅作为讲解程序,在项目编译成 ...

  8. Java调用C# DLL

    由于项目需要,利用了短信猫,但是一个短信猫会加载多个串口,而只需要其AT口,通过java代码,获取其AT口对应的串口号比较困难,于是通过C#获取,这里直接调用C#生成的DLL,但java不能直接调用C ...

  9. JAVA调用动态链接库(dll)

        菜鸡爬坑 基础知识  因为某个东西的keygen我只会在win下生成!! 所以只能出此下策!!之前一直是android下用jni调用so文件,现在试下java在win平台下调用dll 首先还是 ...

随机推荐

  1. php file取重复

    function FetchRepeatMemberInArray($array) { // 获取去掉重复数据的数组 $unique_arr = array_unique ( $array ); // ...

  2. leetcode441(巧妙利用取整和解方程)

    You have a total of n coins that you want to form in a staircase shape, where every k-th row must ha ...

  3. 缓存2 动态缓存 memcached

    01准备下载好memcached.exe文件-->放置c:\memcached目录中02准备下载好php_memcache.dll文件-->放置php\ext扩展目录中03配置 php.i ...

  4. 给EditText设置边框

    布局文件中加入background属性: <EditText android:layout_width="200dp" android:layout_height=" ...

  5. linux服务器无法显示tomcat详细错误信息

    严重: One or more listeners failed to start. Full details will be found in the appropriate container l ...

  6. Linq分组,linq方法分组

    Group在SQL经常使用,通常是对一个字段或者多个字段分组,求其总和,均值等. Linq中的Groupby方法也有这种功能.具体实现看代码: 假设有如下的一个数据集: 01.public class ...

  7. MyEclipse 2015 如何使项目能够使用 Hibernate自动生成文件

    在MyEclipse-Project facets 下 对hibernate这一栏打钩即可

  8. ubuntu 安装LNMP

    How To Install Linux, nginx, MySQL, PHP (LEMP) stack on Ubuntu 12.04 PostedJune 13, 2012 802.8kviews ...

  9. hibernate缓存机制(二级缓存)

    一.why(为什么要用Hibernate缓存?) Hibernate是一个持久层框架,经常访问物理数据库. 为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能. 缓存内的数据是对物理数 ...

  10. UVA 11992 线段树

    input r c m      r<=20,1<=m<=20000 m行操作 1 x1 y1 x2 y2 v       add v 2 x1 y1 x2 y2 v       s ...