JNI编程进阶 数据结构对象的传递
Kaugla
2011/9/3
简介
在《Java调用VC2005 DLL的一个例子》
http://blog.sina.com.cn/s/blog_4c37468101000axv.html
资料的基础上,通过示例源码的形式,展示如何在DLL同Java之间进行数据结构的传递
测试环境:【1】Windows7 【2】JDK1.6.0_26 【3】VisualStudio2010SP1 【4】Eclipse3.2
正文
Java部份源码
package com.kagula; public class MyDataStruct { public int m_iD; public long m_lD; public float m_fD; public double m_dD; public String m_sD; public MyDataStruct() { } public MyDataStruct(int iD,long lD,float fD,double dD,String sD) { m_iD = iD; m_lD = lD; m_fD = fD; m_dD = dD; m_sD = sD; } }使用下面的命令生成com_kagula_TestCallDll2.h文件
E:\JWorkspace\testCallDLL2>"C:\Program Files\Java\jdk1.6.0_25\bin\javah" com.kag
ula.TestCallDll2
根据你计算机中的具体目录适当修改上面的命令
C++语言部份源码
// CallDll2.cpp : Defines the exported functions for the DLL application. // #include "stdafx.h" #include <E:\JWorkspace\testCallDLL2\com_kagula_TestCallDll2.h> #include <stdio.h> #define _MAX_BUF_ 512 //Java Class的实例化,Java Class必须含默认public构造函数(无参)。 jobject getInstance(JNIEnv* env, jclass obj_class) { jmethodID construction_id = env->GetMethodID(obj_class, "<init>", "()V"); jobject obj = env->NewObject(obj_class, construction_id); return obj; } //char *里放的GBK编码的汉字字串 转 jstring 类型 jstring str2jstr(JNIEnv *env,char *buf) { jstring jsR = NULL; jchar* jcBuf = new jchar[_MAX_BUF_]; int len = MultiByteToWideChar(CP_ACP,0,buf,strlen(buf),(LPWSTR)jcBuf,_MAX_BUF_); jsR = env->NewString(jcBuf,len); delete [] jcBuf; return jsR; } int JStringToChar( JNIEnv * env, jstring str, char* desc, int desc_len ) { int len = 0; if (desc == NULL || str == NULL) return -1; // Check buffer size if (env->GetStringLength(str) * 2 + 1 > desc_len) return -2; memset(desc, 0, desc_len); const wchar_t * w_buffer = (wchar_t *)( env->GetStringChars(str, 0) ); len = WideCharToMultiByte(CP_ACP, 0, w_buffer, wcslen(w_buffer) + 1, desc, desc_len, NULL, NULL); env->ReleaseStringChars(str, (jchar *)w_buffer); if (len > 0 && len < desc_len) desc[len] = 0; return strlen(desc); } jobject returnResult(JNIEnv *env,int iD,long long lD,float fD,double dD,char * sD) { jclass m_cls = env->FindClass("com/kagula/MyDataStruct"); //参数列表如下"Z boolean","B byte","C char","S short","I int",J long","F float","D double","L fully-qualified-class ; fully-qualified-class" jfieldID m_fid_1 = env->GetFieldID(m_cls,"m_iD" ,"I"); //如上注释,"I" 为 Java的int类型 jfieldID m_fid_2 = env->GetFieldID(m_cls,"m_lD" ,"J"); //如上注释,"J" 为 Java的long类型 jfieldID m_fid_3 = env->GetFieldID(m_cls,"m_fD" ,"F"); jfieldID m_fid_4 = env->GetFieldID(m_cls,"m_dD" ,"D"); jfieldID m_fid_5 = env->GetFieldID(m_cls,"m_sD" ,"Ljava/lang/String;"); jobject m_obj = getInstance(env, m_cls); env->SetIntField(m_obj ,m_fid_1 ,iD); env->SetLongField(m_obj ,m_fid_2 ,lD); env->SetFloatField(m_obj ,m_fid_3 ,fD); env->SetDoubleField(m_obj ,m_fid_4 ,dD); env->SetObjectField(m_obj,m_fid_5 ,str2jstr(env,sD)); return m_obj; } JNIEXPORT jstring JNICALL Java_com_kagula_TestCallDll2_demoPrimitivesTypeInput (JNIEnv *env, jclass cls, jint jiD, jlong jlD, jfloat jfD, jdouble jdD, jstring jsD) { //数据输入: Java数据类型,转成,C数据类型 int iD = jiD; long long lD = jlD; float fD = jfD; double dD = jdD; char sD[_MAX_BUF_]; char sResult[_MAX_BUF_]; memset(sD,0,sizeof(sD)); memset(sResult,0,sizeof(sResult)); JStringToChar(env,jsD,sD,_MAX_BUF_); //数据处理 //sprintf(sD,"iD=%d lD=%ld fD=%f dD=%lf sD=%s",iD,lD,fD,dD,sD);//只能拆成下面两行,否则会出错(Access Violation),原因不明。 sprintf(sResult,"iD=%d lD=%d fD=%.2f dD=%.2f",iD,lD,jfD,jdD); //fD和dD只输出0.00,原因不明 sprintf(sResult,"%s sD=%s",sResult,sD); //数据返回 return str2jstr(env,sResult); } JNIEXPORT jobject JNICALL Java_com_kagula_TestCallDll2_demoStructTypeInput (JNIEnv *env, jclass cls, jobject joMDS) { //数据输入 int iD; long long lD; float fD; double dD; char sD[_MAX_BUF_]; jclass clsMDS = env->GetObjectClass(joMDS);//得到joMDS的类 iD = env->GetIntField(joMDS , env->GetFieldID(clsMDS,"m_iD","I")); lD = env->GetLongField(joMDS, env->GetFieldID(clsMDS,"m_lD","J")); fD = env->GetFloatField(joMDS, env->GetFieldID(clsMDS,"m_fD","F")); dD = env->GetDoubleField(joMDS, env->GetFieldID(clsMDS,"m_dD","D")); jstring jsD = (jstring) env->GetObjectField(joMDS, env->GetFieldID(clsMDS,"m_sD","Ljava/lang/String;")); JStringToChar(env,jsD,sD,_MAX_BUF_); //数据处理 //数据返回 return returnResult(env,iD,lD,fD,dD,sD); } //参考资料 //[1]《Java调用VC2005 DLL的一个例子》 //http://blog.sina.com.cn/s/blog_4c37468101000axv.html //[2]《native应用 在C中调用JAVA的方法》 //http://leexh8382.blog.163.com/blog/static/5440902007620218785/在Visual Studio 2010里使用Win32 Application Wizard建立DLL项目,根据com_kagula_TestCallDll2.h文件中函数的声明,定义函数。
在项目的Configuration Properties->General->Output Directory里可以指定输出文件(包括DLL)到指定目录,以方便调试DLL程序。
建议你在VisualStudio2010里采用Attach Process的方式跟踪你C++部份代码的执行情况
本文介绍如何在DLL与Java间通过JNI进行复杂数据结构的传递,包括基本数据类型和自定义对象,并提供完整的示例代码。

1639

被折叠的 条评论
为什么被折叠?



