学习利用JNI实现Java调C的DLL

来源:互联网 发布:破解软件越来越差 编辑:程序博客网 时间:2024/06/05 10:25


本人最近所做的一个项目需要将C代码移植到Java平台运行。由于先前没有JNI的任何使用经验,花了近一个星期的时间学习,现将过程记录如下。

 

软件环境:NetBeans IDE 8.0.1 + jdk1.8.0_20 + Visual Studio 2010.

 

1)首选编写javaJNICode.java



/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */package test.jnitest;/** * * @author Ai_ViVi */public class JNICode {        static{        System.loadLibrary("NativeTestCode"); // 加载dll文件,无需后缀名     }        public native void saySomeThing();      public native void passIntArray(int n, int[] a); //传递整型数组    public native ObjTest[] returnIntArray(String[] str); //返回自定义结构数组        /**     * @param args the command line arguments     */    public static void main(String[] args) {        // TODO code application logic here        //System.out.println(System.getProperty("java.library.path"));          System.out.println("hello world from Java");                // for test        JNICode obj = new JNICode();        obj.saySomeThing();                int[] a = {1, 2, 3};        obj.passIntArray(3,a);                String[] names = {"Dr.1", "Dr.2", "Dr.3", "Dr.4"};        ObjTest[] rObj = obj.returnIntArray(names);        for(int i=0; i<rObj.length; i++)        {            //System.out.println(rObj[i].id);            System.out.println(rObj[i].name);        }    }    }


2)测试javah是否可用:


Note:如果javah不可用,则需要将java\jdk\bin加入系统环境变量中。

3)利用javahJNICode.java编译成test_jnitest_JNICode.h文件(注意路径):

test_jnitest_JNICode.h文件位于:

C:\Users\Sandon\Documents\NetBeansProjects\JNItest\build\classes\

 

/* DO NOT EDIT THIS FILE - it is machine generated */#include "jni.h"/* Header for class test_jnitest_JNICode */#ifndef _Included_test_jnitest_JNICode#define _Included_test_jnitest_JNICode#ifdef __cplusplusextern "C" {#endif/* * Class:     test_jnitest_JNICode * Method:    saySomeThing * Signature: ()V */JNIEXPORT void JNICALL Java_test_jnitest_JNICode_saySomeThing  (JNIEnv *, jobject);/** Class:     test_jnitest_JNICode* Method:    passIntArray* Signature: (I[I)V*/JNIEXPORT void JNICALL Java_test_jnitest_JNICode_passIntArray(JNIEnv *, jobject, jint, jintArray);/** Class:     test_jnitest_JNICode* Method:    returnIntArray* Signature: ()[Ltest/jnitest/ObjTest;*/JNIEXPORT jobjectArray JNICALL Java_test_jnitest_JNICode_returnIntArray(JNIEnv *, jobject, jobjectArray);#ifdef __cplusplus}#endif#endif

4)然后创建一个C工程NativeTestCode

4.1)新建win32项目;

4.2)C:\ProgramFiles\Java\jdk1.8.0_20\includejni.h,

C:\ProgramFiles\Java\jdk1.8.0_20\include\win32下的jni_md.h拷贝到工程文件夹下。

4.3)拷贝test_jnitest_JNICode.h到工程文件夹下,并导入工程,打开该文件,将#include <jni.h>修改成#include “jni.h”

4.4)创建test_jnitest_JNICode.cpp文件,成员函数实例化:

 

#include "stdafx.h"#include "test_jnitest_JNICode.h"JNIEXPORT void JNICALL Java_test_jnitest_JNICode_saySomeThing(JNIEnv *env, jobject jo){printf("hello world from C\n");}JNIEXPORT void JNICALL Java_test_jnitest_JNICode_passIntArray(JNIEnv *env, jobject jo, jint jn, jintArray jarr){int num = jn;jint* aar =env->GetIntArrayElements(jarr,0);int arrLen=env->GetArrayLength(jarr);if (num == arrLen){printf("array length is right\n");}for (int i=0; i<arrLen; i++){printf("%d ", aar[i]);}printf("\n");delete aar;}JNIEXPORT jobjectArray JNICALL Java_test_jnitest_JNICode_returnIntArray(JNIEnv *env, jobject jo, jobjectArray jstr){jclass cls_obj = env->FindClass("test/jnitest/ObjTest");  //获取结构对象jmethodID m    = env->GetMethodID(cls_obj,"<init>","()V"); //初始化构造函数  jfieldID fid_id = env->GetFieldID(cls_obj, "id", "I");  //获取成员变量jfieldID fid_name = env->GetFieldID(cls_obj, "name", "Ljava/lang/String;");  //获取成员变量//------------将 char* 转化为 jstring/*char* col_timestamp= "goodluck";//加载string类jclass strClass = env->FindClass("Ljava/lang/String;");//获得方法idjmethodID ctorID = env->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");//将字符串转换为jstring jbyteArray bytes_time = env->NewByteArray(strlen(col_timestamp));env->SetByteArrayRegion(bytes_time, 0, strlen(col_timestamp), (jbyte*)col_timestamp);jstring js_time = env->NewStringUTF("utf-8");js_time=(jstring)env->NewObject(strClass, ctorID, bytes_time, js_time); *///------------将 jstring转化为char*int np = env->GetArrayLength(jstr); jclass cls_array=env->FindClass("java/lang/Object");  //创建结构数组jobjectArray obj_array=env->NewObjectArray(np, cls_array, 0);  for (int i=0; i< np; i++){jobject obj=env->NewObject(cls_obj,m);  int a = i;env->SetIntField(obj, fid_id, a);  jobject str = env->GetObjectArrayElement(jstr,i);env->SetObjectField(obj, fid_name, str);env->SetObjectArrayElement(obj_array, i, obj);  }return obj_array;}


5)编译NativeTestCode项目生产NativeTestCode.dll文件

 

6)拷贝NativeTestCode.dlljava\jdk\bin(假设该路径位于java.library.path下,可以使用System.out.println(System.getProperty("java.library.path"))进行查看)运行JNICode.java文件,结果如下:

 

 

另外:

1)如果C工程所生成的dll文件使用了其他dependent libraies(OpenCV),则需要将这些dll文件一并放入java.library.path下。

2)如果C工程中使用到了文件读写输入输出等,一定要用绝对路径,否则javadll会出错。

3)很烦人的一点:一旦Cdll包含隐形错误(能编译通过),java主程序将错误退出,几乎不提供有用的错误信息。

 

参考:

NetBeans IDE Java快速入门教程: 

https://netbeans.org/kb/docs/java/quickstart_zh_CN.html#setup

Java利用JNI调用C/C++写成的DLL(教程):

http://blog.csdn.net/tank_abraham/article/details/32071621

JavaC传入默认类型数组:

http://www.oschina.net/question/214234_162742

javaC之间的数据传递:

http://blog.chinaunix.net/uid-23023613-id-2566756.html

JavaC传递自定义对象的方法:

http://blog.jeoygin.org/2011/12/jni-pass-on-object-parameter.html

JavaC传递对象,中文字符串的方法:  

http://lifeixian824.blog.163.com/blog/static/2837428520091222638738/

JNI中参数的传递与操作(分上中下三篇,详细介绍了一些API函数)

http://blog.csdn.net/hudashi/article/details/7058982

Cjava返回对象的方法:

http://leidiqiu.iteye.com/blog/720307


 





0 0
原创粉丝点击