Java通过JNI调用dll详细过程(转)

源: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[100], char szDest[100]);
typedef int (WINAPI *FEncodeString)(char szSrc[100], char szDest[100]); 

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 0;
    FEncodeString encodeString=(FEncodeString)GetProcAddress(hDLL,"EncodeString");
    jsize size = (env)->GetArrayLength(src);

    jchar * arrayBody = (env)->GetCharArrayElements(src,0);
    //char * csrc=(char *)arrayBody;

    char csrctemp[100]="";
    int k=0;
    while(size!=0)
    {
        csrctemp[k]=*arrayBody;
        *arrayBody++;
        size--;
        k++;
    }
    char cdesttemp[100]="";
    encodeString(csrctemp,cdesttemp);
    (env)->ReleaseCharArrayElements(src,arrayBody,0);
    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 0;
    FDecodeString decodeString=(FDecodeString)GetProcAddress(hDLL,"DecodeString");
    jsize size = (env)->GetArrayLength(src);
    jchar * arrayBody = (env)->GetCharArrayElements(src,0);
    char * csrc=(char *)arrayBody;
    char csrctemp[100]="";
    int k=0;
    while(size!=0)
    {
        csrctemp[k]=*arrayBody;
        *arrayBody++;
        size--;
        k++;
    }
    //arrayBody=(env)->GetCharArrayElements(dest,0);
    //char * cdest=(char *)arrayBody;
    char cdesttemp[100]="";
    decodeString(csrctemp,cdesttemp);
    (env)->ReleaseCharArrayElements(src,arrayBody,0);
    return (env)->NewStringUTF(cdesttemp);
}

  这里需要注意的是

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才解决问题,哎,C++已经六年没用过了,真是费劲啊

时间: 2024-07-29 23:02:18

Java通过JNI调用dll详细过程(转)的相关文章

Java采用JNI调用VC++生成的dll(Java与C++交互)

应项目需求,需要android调用java,java再调用C++实现android一个图片匹配的功能,我们作为java组需要和C++和Android进行交互.下面是java和C++采用JNI的方式进行接口传参交互,我做的一个demo并运行成功. 什么是JNI? JNI全拼是Java Native Interface,中文意思为Java本地调用.JNI标准是Java平台的一部分,它允许java和其他语言的代码进行交互.JNI开始是为了本地已经编译好的语言,尤其是C和C++而设计的,我们也可以使用J

JAVA的JNI调用

由于JNI调用C和调用C++差不多,而且C++中可以混合写C代码,所以这里主要是写关于JNI调用C++的部分. 一般步骤: 先是写普通的Java类,其中包括本地方法调用.  然后编译这个Java类,调用javah命令,生成.h头文件 接着,就是实现头文件中的函数:实现过程中有点比较麻烦,要知道JNI中JAVA和C/C++的类型转换,比如数组类型的转换,基本类型的转换等,最好是看文档,或者网上找相关资料. 源代码链接:http://files.cnblogs.com/GDUT/jni-demo.r

java通过JNI调用c++代码

java通过JNI调用c++代码 1 用java约定接口,生成头文件 创建JniHelloWorld.java public class JniHelloWorld { public JniHelloWorld(){ } public native void sayHello(String name); } 生成头文件供c++使用 javah-jni JniHelloWorld 产生JniHelloWorld.h文件,里面是用c++代码规定了接口形式. 2生成动态链接库文件(http://blo

JAVA使用JNI调用C++动态链接库

JAVA使用JNI调用C++动态链接库 使用JNI连接DLL动态链接库,并调用其中的函数 首先 C++中写好相关函数,文件名为test.cpp,使用g++编译为DLL文件,指令如下: g++ -shared -Wl,--kill-at,--output-def,test.def -o test.dll test.cpp #如果cpp中要调用其他dll,需要在命令后面添加相关lib描述 这样就在当路径下同时生成了test.def 和 test.dll 文件 顺便说一下,.lib文件可以通过.def

java 通过jni调用c++实现详解

Java通过JNI调用C++程序 JNI是Java Native Interface的缩写,中文为JAVA本地调用.使用JNI可以很方便的用我们的Java程序调用C/C++程序.很多时候,某些功能用Java无法实现,比如说涉及到底层驱动的一些功能,这时候我们就可以利用JNI来调用C或者C++程序来实现,这就是JNI的强大之处.但是JNI也有它的缺点,使用java与本地已编译的代码交互,通常会丧失平台可移植性. 下面是一个JNI例子,调用C++输出"hello world": 第一步:创

关于Java通过JNI调用C 动态链接库(DLL)

JNI介绍 用JNI实现Java和C语言的数据传递 JNI原理分析和详细步骤截图说明 jni的JNIEnv指针和jobject指针 JNI实现回调| JNI调用JAVA函数|参数和返回值的格式 Jni接口-深入研究参数的传递(一)

Java通过JNI调用C

Java调用C有多种方式,本文介绍笔者最近的学习过程,避免今后再犯类似的错误. 首先,Java肯定是调用C的动态链接库,即通过编译器编译后的dll/so文件. 下面介绍gcc编译dll的方法. 一般情况把主函数,子函数定义,子函数声明(全局变量,宏等)分别放在不同的文件中. 我们主要对子函数编译生成可用的dll,供主函数调用. 有一个工程,里面有三个文件,分别是 #include <stdio.h> #include "test.h" int main(int argc,

java源代码分析----jvm.dll装载过程

简述众所周知java.exe是java class文件的执行程序,但实际上java.exe程序只是一个执行的外壳,它会装载jvm.dll(windows下,以下皆以windows平台为例,linux下和solaris下其实类似,为:libjvm.so),这个动态连接库才是java虚拟机的实际操作处理所在.本文探究java.exe程序是如何查找和装载jvm.dll动态库,并调用它进行class文件执行处理的.源代码本文分析之代码,<JavaTM 2 SDK, Standard Edition, v

Java通过JNI调用C的一个小DEMO

最近看java源代码,发现很多方法用native修饰,那么什么事native方法呢?     简单地讲,一个Native Method就是一个java调用非java代码的接口.一个Native Method是这样一个java的方法:该方法的实现由非java语言实现,比如C.这个特征并非java所特有,很多其它的编程语言都有这一机制,比如在C++中,你可以用extern "C"告知C++编译器去调 今天做项目用到了一个非常有意思的东东,上网查了下资料,需求是点击某一个键使屏幕常亮不锁屏.