黑马程序员-java——JNI

来源:互联网 发布:小受坐轮椅卖淘宝 编辑:程序博客网 时间:2024/06/08 00:41

---------------------- <a href="http://www.itheima.com"target="blank">ASP.Net+Unity开发</a>、<a href="http://www.itheima.com"target="blank">.Net培训</a>、期待与您交流! ----------------------

1、写一个java的class,在类里声明所调用的库名称和需要使用的函数(注意:需要对方法做本地声明,关键字为native。且只需要声明,而不需要具体实现)

01package com;
02public class javacall
03{
04        static
05        {
06                System.loadLibrary("htgsjencrypt");
07        }
08        
09        public native static String DecodeString(char[] szSrc);
10        public native static String EncodeString(char[] szSrc);
11 
12        private static void printCharArray(char[] content)
13        {
14            String temp=new String(content);
15            System.out.println(temp);
16        }
17        public static void main(String[] args)
18        {
19          String s="123";
20          char[] src=new char[100];
21          src=s.toCharArray();
22          String encode="";
23          printCharArray(src);
24          encode=javacall.EncodeString(src);
25          System.out.println("encode="+encode);
26          String decode="";
27          src=encode.toCharArray();
28          decode=javacall.DecodeString(src);
29          System.out.println("decode="+decode);
30           
31        }
32}

这个地方需要提一下,新建这个class时最好不要建在默认包中,将来对这个工程打包后,在引用的工程中无法找到默认包中的class(也许是我写的不对,不过写在默认包中确实会带来不必要的麻烦)

2、对于以上编译好的class文件通过使用javah命令生成头文件javacall.h,这个文件需要被C++程序调用来生成所需的库文件

01/* DO NOT EDIT THIS FILE - it is machine generated */
02#include "jni.h"
03/* Header for class com_javacall */
04 
05#ifndef _Included_com_javacall
06#define _Included_com_javacall
07#ifdef __cplusplus
08extern "C" {
09#endif
10/*
11 * Class:     com_javacall
12 * Method:    DecodeString
13 * Signature: ([C)Ljava/lang/String;
14 */
15JNIEXPORT jstring JNICALL Java_com_javacall_DecodeString
16  (JNIEnv *, jclass, jcharArray);
17 
18/*
19 * Class:     com_javacall
20 * Method:    EncodeString
21 * Signature: ([C)Ljava/lang/String;
22 */
23JNIEXPORT jstring JNICALL Java_com_javacall_EncodeString
24  (JNIEnv *, jclass, jcharArray);
25 
26#ifdef __cplusplus
27}
28#endif
29#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了,具体代码如下:

01#include "gsjencrypt.h"
02#include "com_javacall.h"
03#include "windows.h"
04#include <iostream>
05//////////////////////////////////////////////////////////////////////
06// Construction/Destruction
07//////////////////////////////////////////////////////////////////////
08 
09gsjencrypt::gsjencrypt()
10{
11 
12}
13 
14gsjencrypt::~gsjencrypt()
15{
16 
17}
18typedef int (WINAPI *FDecodeString)(char szSrc[100], char szDest[100]);
19typedef int (WINAPI *FEncodeString)(char szSrc[100], char szDest[100]);
20 
21JNIEXPORT jstring JNICALL Java_com_javacall_EncodeString(JNIEnv * env, jclass jobject, jcharArray src)
22{
23    HINSTANCE hDLL;
24    hDLL=LoadLibrary("gsjencrypt.dll");//加载动态链接库gsjencrypt.dll文件;
25    if(hDLL==NULL)
26        return 0;
27    FEncodeString encodeString=(FEncodeString)GetProcAddress(hDLL,"EncodeString");
28    jsize size = (env)->GetArrayLength(src);
29 
30    jchar * arrayBody = (env)->GetCharArrayElements(src,0);
31    //char * csrc=(char *)arrayBody;
32     
33    char csrctemp[100]="";
34    int k=0;
35    while(size!=0)
36    {
37        csrctemp[k]=*arrayBody;
38        *arrayBody++;
39        size--;
40        k++;
41    }
42    char cdesttemp[100]="";
43    encodeString(csrctemp,cdesttemp);
44    (env)->ReleaseCharArrayElements(src,arrayBody,0);
45    return (env)->NewStringUTF(cdesttemp);
46}
47JNIEXPORT jstring JNICALL Java_com_javacall_DecodeString(JNIEnv * env, jclass jobject, jcharArray src)
48{
49    HINSTANCE hDLL;
50    hDLL=LoadLibrary("gsjencrypt.dll");//加载动态链接库gsjencrypt.dll文件;
51    if(hDLL==NULL)
52        return 0;
53    FDecodeString decodeString=(FDecodeString)GetProcAddress(hDLL,"DecodeString");
54    jsize size = (env)->GetArrayLength(src);
55    jchar * arrayBody = (env)->GetCharArrayElements(src,0);
56    char * csrc=(char *)arrayBody;
57    char csrctemp[100]="";
58    int k=0;
59    while(size!=0)
60    {
61        csrctemp[k]=*arrayBody;
62        *arrayBody++;
63        size--;
64        k++;
65    }
66    //arrayBody=(env)->GetCharArrayElements(dest,0);
67    //char * cdest=(char *)arrayBody;
68    char cdesttemp[100]="";
69    decodeString(csrctemp,cdesttemp);
70    (env)->ReleaseCharArrayElements(src,arrayBody,0);
71    return (env)->NewStringUTF(cdesttemp);
72}

这里需要注意的是

typedef int (WINAPI *FDecodeString)(char szSrc[100], char szDest[100]);typedef int (WINAPI *FEncodeString)(char szSrc[100], char szDest[100]); 

以上两个方法是原始dll中提供给外界调用的函数接口,声明时一定要记得加WINAPI,否则调用时始终报错。

4、最后将第三方提供的gsjencrypt.dll和新生成的htgsjencrypt.dll同时拷贝到java.library.path里(jdk或者jre的bin文件中),然后将最开始写的java程序打包即可被别的工程调用。

记录一下最难解决的问题,就是不知道怎样在c++中返回给java解密后的串,因为总是想把指针的概念与java中的某个byte数组或者char数组关联起来,始终不能成功,最后尝试使用NewStringUTF才解决问题。

---------------------- <a href="http://www.itheima.com"target="blank">ASP.Net+Unity开发</a>、<a href="http://www.itheima.com"target="blank">.Net培训</a>、期待与您交流! ----------------------

详细请查看:<a href="http://www.itheima.com" target="blank">www.itheima.com</a>

0 0
原创粉丝点击