博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[JNI] Java 调用 C++ dll
阅读量:4588 次
发布时间:2019-06-09

本文共 7036 字,大约阅读时间需要 23 分钟。

首先介绍一下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,0);    }    if (in_out_src)    {        env->ReleaseCharArrayElements(in_out_src,out_str_array,0);    }    if (in_hex_des_key)    {        env->ReleaseCharArrayElements(in_hex_des_key,hex_des_key_array,0);    }    if (in_out_len)    {        env->ReleaseIntArrayElements(in_out_len,src_out_len,0);    }

 

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

 

第二版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,8);    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=0;    for(i = 0; i < len; i++)      {          *(pArray + i) = *((unsigned char *)out_str_array + i);    }     env->SetCharArrayRegion(ret_array,0,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,0);    }    if (in_out_src)    {        env->ReleaseCharArrayElements(in_out_src,out_str_array,0);    }    if (in_hex_des_key)    {        env->ReleaseCharArrayElements(in_hex_des_key,hex_des_key_array,0);    }    if (in_out_len)    {        env->ReleaseIntArrayElements(in_out_len,src_out_len,0);    }        return ret_array;}//将宽字节wchar_t*转化为单字节char*  char* UnicodeToAnsi( const wchar_t* szStr ,int len)  {      char* ret_data = NULL;    int nLen = WideCharToMultiByte( CP_ACP, 0, szStr, len, NULL, 0, NULL, NULL );      if (nLen == 0)      {          return NULL;      }      char* pResult = new char[nLen];      WideCharToMultiByte( CP_ACP, 0, szStr, -1, pResult, nLen, NULL, NULL );      ret_data = new char[nLen+1];    memset(ret_data, 0, nLen+1);    strncpy(ret_data, pResult, len);    ret_data[len] = '\0';    if (pResult)    {        delete [] pResult;    }        return ret_data;  }
C++

 

转载于:https://www.cnblogs.com/tengpan-cn/p/4782021.html

你可能感兴趣的文章
C# 针对特定的条件进行锁操作,不用lock,而是mutex
查看>>
Spring归纳
查看>>
MyEclipse Web Project导入Eclipse Dynamic Web Project,无法部署到tomcat问 题
查看>>
24小时学通Linux内核之向内核添加代码
查看>>
python 函数
查看>>
Solr4.0 如何配置使用UUID自动生成id值
查看>>
Marketing™Series用户手册(Marketing™Series Manual)
查看>>
Java动态代理
查看>>
二维码开源库zbar、zxing使用心得
查看>>
框架设计读书笔记--扩展点设计--组合法
查看>>
Web开发小贴士 -- 全面了解Cookie
查看>>
收藏Javascript中常用的55个经典技巧
查看>>
Arm-linux-gcc-4.3.2安装步骤
查看>>
Java多线程与并发编程学习
查看>>
Support Vector Machine
查看>>
牛客-2018多校算法第五场C-KMP
查看>>
Linux查看文件内容
查看>>
[转]社会生活中十二大著名法则 1 马太效应 2 手表定理 3 不值得定律 4 彼得原理 5 零和游戏原理 6 华盛顿合作规律 7 酒与污水定律 8 水桶定律 9 蘑菇管理 10 奥...
查看>>
浅谈三层与实体
查看>>
cocostudio——js 3 final控件事件
查看>>