转 JNI学习笔记 C++传递结构体、String、数组对象给JavaC++传递结构体、String、数组对象给Java

转自https://blog.csdn.net/xp_lx1/article/details/58137704

有时候我们需要传递结构体给Java,而Java中没有与结构体,我们可以用一个类来接受结构数据,下面用一个Demo来说明如果传递。

关于如何通过Jni建立c++和Java通信,请看上篇博文JNI学习笔记(一)

Java代码:

创建2个类,一个类用来测试,一个类用来接收结构体参数。

测试类

 

[java] view plain copy

  

  1. package test;  
  2.   
  3. public class MyJNI {  
  4.     /* ***************** 定义本地方法 ******************* */  
  5.     // 输入常用的数值类型(Boolean,Byte,Char,Short,Int,Float,Double)  
  6.     public native void displayParms(String showText, int i, boolean bl);  
  7.     // 调用一个静态方法  
  8.     public native int add(int a, int b);  
  9.     // 输入一个数组  
  10.     public native void setArray(boolean[] blList);  
  11.     // 返回一个字符串数组  
  12.     public native String[] getStringArray();  
  13.     // 返回一个结构  
  14.     public native DiskInfo getStruct();  
  15.     // 返回一个结构数组  
  16.     public native DiskInfo[] getStructArray();  
  17.   
  18.     static {  
  19.         // System.loadLibrary("myJNI"); //加载动态链接库  
  20.         System.load("E:\\Workspaces\\CodeBlocks\\myJNI\\bin\\Debug\\myJNI.dll");  
  21.     }  
  22.   
  23.     // 主测试程序  
  24.     public static void main(String[] args) {  
  25.         MyJNI changeJni = new MyJNI();  
  26.   
  27.         // 输入常用的数值类型(string int boolean)  
  28.         System.out.println("-----输入常用的数值类型(string int boolean)------");  
  29.         changeJni.displayParms("Hello World!", 100, true);  
  30.   
  31.         // 调用一个静态方法  
  32.         System.out.println("------------------调用一个静态方法-----------");  
  33.         int ret = changeJni.add(12, 20);  
  34.         System.out.println("The result is: " + String.valueOf(ret));  
  35.   
  36.         // 输入一个数组  
  37.         System.out.println("------------------输入一个数组-----------");  
  38.         boolean[] blList = new boolean[] { true, false, true };  
  39.         changeJni.setArray(blList);  
  40.   
  41.         // 返回一个字符串数组  
  42.         System.out.println("-------------返回一个字符串数组-----------");  
  43.         String[] strList = changeJni.getStringArray();  
  44.         for (int i = 0; i < strList.length; i++) {  
  45.             System.out.print(strList[i]);  
  46.         }  
  47.         System.out.println();  
  48.   
  49.         System.out.println("--------------返回一个结构-----------");  
  50.   
  51.         // 返回一个结构  
  52.         DiskInfo disk = changeJni.getStruct();  
  53.         System.out.println("name:" + disk.name);  
  54.         System.out.println("Serial:" + disk.serial);  
  55.   
  56.         // 返回一个结构数组  
  57.         System.out.println("-----------返回一个结构数组 -----------");  
  58.         DiskInfo[] diskList = changeJni.getStructArray();  
  59.         for (int i = 0; i < diskList.length; i++) {  
  60.             System.out.println("name:" + diskList[i].name);  
  61.             System.out.println("Serial:" + diskList[i].serial);  
  62.         }  
  63.     }  
  64. }  

 

接收结构体类:

 

[java] view plain copy

  

  1. package test;  
  2.   
  3. class  DiskInfo  {  
  4.     // 名字   
  5.      public  String name;  
  6.   
  7.     // 序列号   
  8.      public   int  serial;  
  9. }  

 

C++代码(本人用的CodeBlocks生成的dll)

 

[cpp] view plain copy

  

  1. #include <stdio.h>  
  2. #include "test_MyJNI.h"  
  3. #include <windows.h>  
  4.   
  5. //硬盘信息  
  6. struct DiskInfo  
  7. {  
  8.     char name[256];  
  9.     int serial;  
  10. };  
  11.   
  12. //将jstring类型转换成windows类型  
  13. char* jstringToWindows(JNIEnv *env, jstring jstr);  
  14. //将windows类型转换成jstring类型  
  15. jstring WindowsTojstring(JNIEnv* env, char* str);  
  16.   
  17. /** 
  18. *主函数 
  19. DLL本身不会独立创建进程,也就不需要所谓main函数之类的程序入口。 
  20. 另外,DLL的入口函数是DllMain 
  21. */  
  22. BOOL WINAPI DllMain(HANDLE hHandle, DWORD dwReason, LPVOID lpReserved)  
  23. {  
  24.     return TRUE;  
  25. }  
  26.   
  27. //输入常用的数值类型 Boolean,Byte,Char,Short,Int,Float,Double  
  28. JNIEXPORT void JNICALL Java_test_MyJNI_displayParms(JNIEnv *env, jobject obj, jstring s, jint i, jboolean b)  
  29. {  
  30.     const char* szStr = (env)->GetStringUTFChars(s, 0);  
  31.     printf("String = [%s]\n", szStr);  
  32.     printf("int = %d\n", (int)i);  
  33.     printf("boolean = %s\n", (b == JNI_TRUE ? "true" : "false"));  
  34.     (env)->ReleaseStringUTFChars(s, szStr);  
  35. }  
  36.   
  37. //调用一个静态方法,只有一个简单类型输出  
  38. JNIEXPORT jint JNICALL Java_test_MyJNI_add(JNIEnv *env, jobject, jint a, jint b)  
  39. {  
  40.     int rtn = (int)(a + b);  
  41.     return (jint)rtn;  
  42. }  
  43.   
  44. //输入一个数组,这里输入的是一个Boolean类型的数组  
  45. JNIEXPORT void JNICALL Java_test_MyJNI_setArray(JNIEnv *env, jobject, jbooleanArray ba)  
  46. {  
  47.     jboolean* pba = (env)->GetBooleanArrayElements(ba, 0);  
  48.     jsize len = (env)->GetArrayLength(ba);  
  49.     // change even array elements  
  50.     for(int i = 0; i < len; i += 2)  
  51.     {  
  52.         pba[i] = JNI_FALSE;  //JNI_FALSE是在jni.h中定义的  
  53.         printf("boolean = %s\n", (pba[i] == JNI_TRUE ? "true" : "false"));  
  54.     }  
  55.     (env)->ReleaseBooleanArrayElements(ba, pba, 0);  
  56. }  
  57.   
  58. 返回一个字符串数组  
  59. JNIEXPORT jobjectArray JNICALL Java_test_MyJNI_getStringArray(JNIEnv *env, jobject)  
  60. {  
  61.     jstring      str;  
  62.     jobjectArray args = 0;  
  63.     jsize        len = 5;  
  64.     const char* sa[] = { "Hello,", "world!", " JNI", " is", " fun" };  
  65.     //int          i=0;  
  66.     args = (env)->NewObjectArray(len, (env)->FindClass("java/lang/String"), 0);  
  67.     for(int i = 0; i < len; i++)  
  68.     {  
  69.         str = (env)->NewStringUTF(sa[i]);  
  70.         (env)->SetObjectArrayElement(args, i, str);  
  71.     }  
  72.     return args;  
  73. }  
  74.   
  75. //返回一个结构,这里返回一个硬盘信息的简单结构类型  
  76. JNIEXPORT jobject JNICALL Java_test_MyJNI_getStruct(JNIEnv *env, jobject obj)  
  77. {  
  78.     /* 下面为获取到Java中对应的实例类中的变量*/  
  79.   
  80.     //获取Java中的实例类  
  81.     jclass objectClass = (env)->FindClass("test/DiskInfo");  
  82.     //获取类中每一个变量的定义  
  83.     //名字  
  84.     jfieldID str = (env)->GetFieldID(objectClass, "name", "Ljava/lang/String;");  
  85.     //序列号  
  86.     jfieldID ival = (env)->GetFieldID(objectClass, "serial", "I");  
  87.   
  88.     //给每一个实例的变量赋值  
  89.     (env)->SetObjectField(obj, str, (env)->NewStringUTF("my name is D:"));  
  90.     (env)->SetShortField(obj, ival, 10);  
  91.   
  92.     return obj;  
  93. }  
  94.   
  95. //返回一个结构数组,返回一个硬盘信息的结构数组  
  96. JNIEXPORT jobjectArray JNICALL Java_test_MyJNI_getStructArray(JNIEnv *env, jobject _obj)  
  97. {  
  98.     //申明一个object数组  
  99.     jobjectArray args = 0;  
  100.     //数组大小  
  101.     jsize        len = 5;  
  102.     //获取object所属类,一般为ava/lang/Object就可以了  
  103.     jclass objClass = (env)->FindClass("java/lang/Object");  
  104.     //新建object数组  
  105.     args = (env)->NewObjectArray(len, objClass, 0);  
  106.     /* 下面为获取到Java中对应的实例类中的变量*/  
  107.   
  108.     //获取Java中的实例类  
  109.     jclass objectClass = (env)->FindClass("test/DiskInfo");  
  110.     //获取类中每一个变量的定义  
  111.     //名字  
  112.     jfieldID str = (env)->GetFieldID(objectClass, "name", "Ljava/lang/String;");  
  113.     //序列号  
  114.     jfieldID ival = (env)->GetFieldID(objectClass, "serial", "I");  
  115.     //给每一个实例的变量付值,并且将实例作为一个object,添加到objcet数组中  
  116.     for(int  i = 0; i < len; i++)  
  117.     {  
  118.         //给每一个实例的变量付值  
  119.         jstring jstr = WindowsTojstring(env, (char*)"我的磁盘名字是 D:");  
  120.         //(env)->SetObjectField(_obj,str,(env)->NewStringUTF("my name is D:"));  
  121.         (env)->SetObjectField(_obj, str, jstr);  
  122.         (env)->SetShortField(_obj, ival, 10);  
  123.   
  124.         //添加到objcet数组中  
  125.         (env)->SetObjectArrayElement(args, i, _obj);  
  126.     }  
  127.     //返回object数组  
  128.     return args;  
  129. }  
  130.   
  131. /*作编码格式转换的函数*/  
  132. //将jstring类型转换成windows类型  
  133. char* jstringToWindows(JNIEnv  *env, jstring jstr)  
  134. {  
  135.     int length = (env)->GetStringLength(jstr);  
  136.     const jchar* jcstr = (env)->GetStringChars(jstr, 0);  
  137.     char* rtn = (char*)malloc(length * 2 + 1);  
  138.     int size = 0;  
  139.     size = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)jcstr, length, rtn, (length * 2 + 1), NULL, NULL);  
  140.     if(size <= 0)  
  141.         return NULL;  
  142.     (env)->ReleaseStringChars(jstr, jcstr);  
  143.     rtn[size] = 0;  
  144.     return rtn;  
  145. }  
  146.   
  147. //将windows类型转换成jstring类型  
  148. jstring WindowsTojstring(JNIEnv* env, char* str)  
  149. {  
  150.     jstring rtn = 0;  
  151.     int slen = strlen(str);  
  152.     unsigned short * buffer = 0;  
  153.     if(slen == 0)  
  154.         rtn = (env)->NewStringUTF(str);  
  155.     else  
  156.     {  
  157.         int length = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)str, slen, NULL, 0);  
  158.         buffer = (unsigned short *)malloc(length * 2 + 1);  
  159.         if(MultiByteToWideChar(CP_ACP, 0, (LPCSTR)str, slen, (LPWSTR)buffer, length) > 0)  
  160.             rtn = (env)->NewString((jchar*)buffer, length);  
  161.     }  
  162.     if(buffer)  
  163.         free(buffer);  
  164.     return rtn;  
  165. }  
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要将JNI中的char*类型换为Java中的byte数组,可以按照以下步骤进行操作: 1. 获取char*类型字符串的长度,使用strlen()函数可以获取。 2. 创建一个jbyteArray类型的Java数组,长度为字符串长度,使用NewByteArray()函数可以创建。 3. 将char*类型字符串换为jbyte类型数组,使用jbyte*类型的指针指向char*类型字符串,然后使用SetByteArrayRegion()函数将每个char类型元素换为jbyte类型并设置到Java数组中。 4. 释放char*类型字符串的内存空间,使用free()函数释放。 下面是一个示例代码: ```c++ JNIEXPORT jbyteArray JNICALL Java_com_example_MyClass_charToByteArray(JNIEnv *env, jobject obj, jcharArray charArray) { // 将jcharArray类型换为jchar类型指针 jchar *chars = env->GetCharArrayElements(charArray, NULL); // 获取字符串长度 int len = strlen(chars); // 创建jbyteArray类型的Java数组 jbyteArray byteArray = env->NewByteArray(len); // 将char*类型字符串换为jbyte类型的数组 jbyte *bytes = (jbyte*)chars; env->SetByteArrayRegion(byteArray, 0, len, bytes); // 释放char*类型字符串的内存空间 free(chars); // 返回jbyteArray类型的Java数组 return byteArray; } ``` 在上面的示例代码中,我们首先将输入的jcharArray类型换为jchar类型指针,然后获取字符串长度。接着,我们使用NewByteArray()函数创建一个长度为字符串长度的jbyteArray类型的Java数组。然后,我们将jchar类型指针换为jbyte类型指针,并使用SetByteArrayRegion()函数将每个char类型元素换为jbyte类型并设置到Java数组中。最后,我们使用free()函数释放char*类型字符串的内存空间,并返回jbyteArray类型的Java数组

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值