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;
}
}
package com.kagula;
public class TestCallDll2 {
static {
System.loadLibrary("CallDll2");
}
public native static String demoPrimitivesTypeInput(int iD,long lD,float fD,double dD,String sD);
public native static MyDataStruct demoStructTypeInput(MyDataStruct mds);
public static void main(String args[])
{
System.out.println("this is a TestCallDll class");
//原始类型的输入输出测试
String sR;
sR = TestCallDll2.demoPrimitivesTypeInput(1,23l,4.5f,7.8,"测试输入");
System.out.println(sR);
//数据结构类型的输入输出测试
MyDataStruct mds = new MyDataStruct(1,23l,4.5f,7.8,"测试输入");
mds = TestCallDll2.demoStructTypeInput(mds);
System.out.println(mds.m_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++部份代码的执行情况