JNI编程进阶 数据结构对象的传递

 

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++部份代码的执行情况

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kagula086

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值