java调用dll库

最近项目需要用到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 __cplusplus
extern "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到了所有的请求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值