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



本人最近所做的一个项目需要将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 __cplusplus
extern "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;");
	//获得方法id
	jmethodID 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值