java调用dll库

来源:互联网 发布:jc js jk 编辑:程序博客网 时间:2024/05/22 16:45

最近项目需要用到java调用dll库。于是学习了一番,中间遇到一些问题,这里记录一下整体过程。

首先是把需要调用的函数用java写出来。这里写两个函数:

package com.tgb.controller;/** * Created by Chan on 2016/6/24. */public class picture {    static    {        System.loadLibrary("puppet");    }    public native static String compare(String disign , String scan , int param);    public native static String test(int i);}

特别需要注意的地方是这里有package com.tgb.controller。后来才发现有package和没有package的区别是相当大的。

然后需要编译这个文件。因为是在SpringMVC里面做的,这里的路径是

springmvcTest\src\main\java\com\tgb\controller\picture.java

然后在controller目录下,shift+鼠标右键调出cmd窗口,然后javac编译这个文件。

javac picture.java

接着,需要生成一个c++用的头文件。转到目录java下,即

springmvcTest\src\main\java\

用javah命令生成头文件。

javah com.tgb.controller.picture

没有后缀名,命令执行完之后就会在java目录下生成一个叫com_tgb_controller_picture.h的文件,这就是我们后来要用到的头文件。

如果picture.java没有包的话直接在与它相同的目录下javah picture就可以了。

然后打开VS,开始c++这边的编写。不过在那之前需要做些准备工作。
首先,将以下三个文件拷贝到工程目录下,或者是放到VS/VC/include/下

  1. com_tgb_controller_picture.h
  2. JDK/include/jni.h
  3. JDK/include/win32/jni_md.h

然后打开VS。。。。
打开之后新建项目–win32项目—然后见下图:
这里写图片描述
然后点完成就行了。

接着新建一个源文件,头三句话就是这个:

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

这里先不接着写,我们先打开com_tgb_controller_picture.h看一下有些啥。

/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class com_tgb_controller_picture */#ifndef _Included_com_tgb_controller_picture#define _Included_com_tgb_controller_picture#ifdef __cplusplusextern "C" {#endif/* * Class:     com_tgb_controller_picture * Method:    compare * Signature: (Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_com_tgb_controller_picture_compare  (JNIEnv *, jclass, jstring, jstring, jint);/* * Class:     com_tgb_controller_picture * Method:    test * Signature: (I)Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_com_tgb_controller_picture_test  (JNIEnv *, jclass, jint);#ifdef __cplusplus}#endif#endif

一大堆东西其实不用管,可以看到里面声明了两个函数:

JNIEXPORT jstring JNICALL Java_com_tgb_controller_picture_compare (JNIEnv *, jclass, jstring, jstring, jint);

JNIEXPORT jstring JNICALL Java_com_tgb_controller_picture_test (JNIEnv *, jclass, jint);

可以看到函数名还是比较直观,前两个参数不用管,我们需要的参数从第三个开始。这就是我们之前在java写的两个方法的对应,我们只需要在这里实现这两个函数就行了。

源文件如下:

#include"jni.h"#include"jni_md.h"#include"com_tgb_controller_picture.h"#include<stdlib.h>#include<string.h>char* jstringTostring(JNIEnv* env, jstring jstr){    char* rtn = NULL;    jclass clsstring = env->FindClass("java/lang/String");    jstring strencode = env->NewStringUTF("utf-8");    jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");    jbyteArray barr = (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);    jsize alen = env->GetArrayLength(barr);    jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);    if (alen > 0)    {        rtn = (char*)malloc(alen + 1);        memcpy(rtn, ba, alen);        rtn[alen] = 0;    }    env->ReleaseByteArrayElements(barr, ba, 0);    return rtn;}jstring stoJstring(JNIEnv* env, const char* pat){    jclass strClass = env->FindClass("Ljava/lang/String;");    jmethodID ctorID = env->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");    jbyteArray bytes = env->NewByteArray(strlen(pat));    env->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*)pat);    jstring encoding = env->NewStringUTF("utf-8");    return (jstring)env->NewObject(strClass, ctorID, bytes, encoding);}JNIEXPORT jstring JNICALL Java_com_tgb_controller_picture_compare(JNIEnv * env, jclass, jstring design,    jstring scan, jint param) {    char *desChar = jstringTostring(env, design);    char *scanChar = jstringTostring(env, scan);    FILE *designpic = fopen(desChar,"r");    FILE *scanpic = fopen(scanChar, "r");    if (designpic == NULL || scanpic == NULL) {        return stoJstring(env, "cannot open file.");    }    fclose(designpic);    fclose(scanpic);    return stoJstring(env, "files open succeed");}JNIEXPORT jstring JNICALL Java_com_tgb_controller_picture_test(JNIEnv * env, jclass, jint n) {    if (n == 0) {        return stoJstring(env, "test succeed");    }    else        return stoJstring(env, "test failure");}

char* jstringTostring(JNIEnv* env, jstring jstr)和jstring stoJstring(JNIEnv* env, const char* pat)是两个类型转换用的函数,因为java中的string和c++的字符串还有点不一样,所以在用的时候转换一下会方便很多。函数的功能很简单,看代码就行了。

接着,我们需要生成dll库,首先看java是多少位的。
如果是64位的就
这里写图片描述
32位的就
这里写图片描述
然后生成解决方案就可以了。

然后dll文件可以在VS项目中的debug文件夹中找到。将这个文件放到java项目目录下,或者C:\windows\system32目录下都可以。

然后在回到java中,我们写了一个简单的HelloController

package com.tgb.controller;import org.springframework.stereotype.Controller;import org.springframework.ui.ModelMap;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;@Controller@RequestMapping("/")public class HelloController {    @RequestMapping(method = RequestMethod.GET)    public String printWelcome(ModelMap model) {        model.addAttribute("message", "Hello world!");        int n = 0;        System.out.println("been here");        String ret = picture.compare("D:\\1.jpg","D:\\2.jpg",1);        String testRet = picture.test(n);        System.out.println(ret+"     "+testRet);        return "hello";    }}

然后直接跑。控制台输出如下:
这里写图片描述
说明本地库调用成功,至于为什么调用了三次有待进一步的学习。初步猜想是@RequestMapping(“/”)map到了所有的请求。

0 0