在JNI中调用本地带结构体参数的函数

JNI 传递字符串和结构体 用c写的程序,要生成dll供java调用,现学现用JNI。字符串的调用还比较简单,有现成的语句,传递结构体把俺累的半死,因为结构体里有一维和二维数组。看了不少博文,终于弄出来了,总结一下,希望有助他人。 c和c++的写法略有不同,以下为c++版本。 传递结构体如下: struct mystruct { float array1[M]; float array2[M][N]; };以下重点 阅读详情

说起JNI,《The Java Native Interface -- Programmer's Guide and Specification》我认为是挺好的入门教程。浅显易懂,而且也附有参考。对很多问题和陷阱也进行了讲解和提示。可以在 Sun 的官网上免费下载到这本书,下载地址:http://java.sun.com/docs/books/jni/download/jni.pdf。 

 

但是我认为这本书在第 9 章 Leveraging Existing Native Libaries 中对开头所讲的一段程序的解释有点潦草。内容大意是有一个 Win32 API, CreateFile。它带了很多参数。有 const char*、DWORD、HANDLE,最重要的是它带了一个 SECURITY_ATTRIBUTES*,一个结构体指针。 

C代码 

HANDLE CreateFile(  

    const char *fileName, // file name  

    DWORD desiredAccess, // access (read-write) mode  

    DWORD shareMode, // share mode  

    SECURITY_ATTRIBUTES *attrs, // security attributes  

    DWORD creationDistribution, // how to create  

    DWORD flagsAndAttributes, // file attributes  

    HANDLE templateFile // file with attr. to copy  

);  

 

这个 SECURITY_ATTRIBUTES 是自定义的。具体的定义就不给出了。书中也给出了对应的 Java 函数。 

Java代码 

public class Win32 {  

    public static native int CreateFile(  

        String fileName, // file name  

        int desiredAccess, // access (read-write) mode  

        int shareMode, // share mode  

        int[] secAttrs, // security attributes  

        int creationDistribution, // how to create  

        int flagsAndAttributes, // file attributes  

        int templateFile); // file with attr. to copy  

    ...  

}  

 

但怪的是,作者使用了一个 int[] 来对应 SECURITY_ATTRIBUTES*。对此,作者只有一段短小的解释。 

引用

 

Because of potential differences in how fields are laid out in memory, we do 

not map C structures to classes in the Java programming language. Instead, we use 

an array to store the contents of the C structure SECURITY_ATTRIBUTES. The caller 

may also pass null as secAttrs to specify the default Win32 security attributes. 

We will not discuss the contents of the SECURITY_ATTRIBUTES structure or how to 

encode that in an int array. 

 

我认为这个解释是为了让读者耐心读下去而写的。这里用 int[] 是说不通的。可以理解作者。书中这时的重点还是讲解如何调用一个普通函数。在读完这章的时候,我才明白,这里应该用后面所介绍的 Peer Class 来做。但我后面给出的解决方法并不是针对这个例子的。但是,看完后您可以自已写一个解决方法。因为后面的示例给出一个解决 Java 调用 C/C++ 带结构体参数函数的思路。 

 

Peer Class,用我的话来说就是一个 Java 类,它包含了一个 C/C++ 对象的指针。一个通常的 Peer Class 长成这个样子: 

Java代码 

public class PeerClass {  

 

    private long peer;  

    ...  

 

}  

 

引用《The Java Native Interface -- Programmer's Guide and Specification》,java.io.FileDescriptor 也包含一个 int fd。用来保存对应本地结构体的一个指针。所以说,Peer Class 的使命就是提供一个对 C/C++ 结构体或类的一个包装,使得 Java 可以使用。故,解决上面 CreateFile 函数参数问题的办法就是针对 SECURITY_ATTRIBUTES 结构体定义一个包装类。具体的实现我用另外一个例子。因为 CreateFile 的签名太长,有点吓人 (#o#) 

 

假定,Java 一段程序需要调用 C++ 一个函数 CppFunc(STRUCT* stru)。这个 STRUCT 包含一个 long 成员变量和一个 char 成员变量。CppFunc 会打印出这个结构体实例中变量的值。为了构造一个这样的 C++ 结构体,我们给它做一个包装类。也就是一个 Peer Class。不妨叫 StructWrapper。通过构造 StructWrapper,Java 程序给其对应的 C++ 结构体赋值。再将这个 StructWrapper 实例传给 Java 里对 CppFunc 的包装函数,从而达到目的。 

 

示例中的 C++ 工程是一个 Win32 DLL。下面的代码展示可能为了逻辑的连贯性而把一个文件的内容分开来。读者实践的时候可以自行合并。 

 

首先,定义 C++ 的 CppFunc 和 STRUCT 结构体。 

C++代码 

// Entry.cpp  

 

using namespace std;  

 

void CppFunc(STRUCT* stru)  

{  

    cout << "long value:/t" << stru->l << endl;  

    cout << "char value:/t" << stru->c << endl;  

}  

 

 

// Struct.h  

 

#ifndef _Included_STRUCT  

#define _Included_STRUCT  

 

typedef struct _STRUCT  

{  

    long l;  

    char c;  

} STRUCT;  

 

#endif  

 

再次,定义 STRUCT 的包装类 StructWrapper。 

Java代码 

// StructWrapper.java  

 

public class StructWrapper {  

 

    private long peer;  

 

    public long getPeer() {  

        return peer;  

    }  

 

    private native long initialize(long l, char c);  

 

    private native void destroy(long peer);  

 

    public StructWrapper(long l, char c) {  

        peer = initialize(l, c);  

    }  

 

    public synchronized void destroy() {  

        if (peer != 0) {  

            destroy(peer);  

            peer = 0;  

        }  

    }  

 

    protected void finalize() {  

        destroy();  

    }  

 

    static {  

        System.loadLibrary("TestJNI");  

    }  

 

}  

 

initialize 函数的作用就是调用 C++ 代码来初始化一个 C++ 下的 STRUCT 对象,并返回这个对象的指针。StructWrapper 在构造时把这个指针保存在 peer 中。这里 peer 其实可以用 int。因为 C++ 下指针是四字节,Java 下 int 也是四字节。destroy 设计为线程安全的原因是因为在 finalize 方法中会自动调用 destroy。而用户也可能会手动销毁对象。有可能出现并发的情况。 

 

还缺一个针对 CppFunc 的 Java 包装函数。 

Java代码 

// Entry.java  

 

public class Entry {  

 

    private native void callCppFunc(long structWrapperPeer);  

 

    public static void main(String[] args) {  

        ...  

    }  

 

}  

 

callCppFunc(long) 这个 Java 函数。它提供了一个 CppFunc 的包装。它所需要的参数实际上是 StructWrapper 实例中所保存的 C++ STRUCT 结构体实例的地址。这样就实现了把 Java 对象传给 C++。 

 

大家看到,这里 StructWrapper 用到了几个本地函数。我们一样得在 C++ 中实现它们。 

C++代码 

// StructWrapper.h  

 

/* DO NOT EDIT THIS FILE - it is machine generated */  

#include <jni.h>  

/* Header for class StructWrapper */  

 

#ifndef _Included_StructWrapper  

#define _Included_StructWrapper  

#ifdef __cplusplus  

extern "C" {  

#endif  

/* 

 * Class:     StructWrapper 

 * Method:    initialize 

 * Signature: (JC)J 

 */  

JNIEXPORT jlong JNICALL Java_StructWrapper_initialize  

  (JNIEnv *, jobject, jlong, jchar);  

 

/* 

 * Class:     StructWrapper 

 * Method:    destroy 

 * Signature: (J)V 

 */  

JNIEXPORT void JNICALL Java_StructWrapper_destroy  

  (JNIEnv *, jobject, jlong);  

 

#ifdef __cplusplus  

}  

#endif  

#endif  

 

 

// StructWrapper.cpp  

 

#include "StructWrapper.h"  

#include "Struct.h"  

 

JNIEXPORT jlong JNICALL  

Java_StructWrapper_initialize(JNIEnv* env, jobject self, jlong l, jchar c)  

{  

    STRUCT* peer = new STRUCT();  

    peer->l = (long)l;  

    peer->c = (char)c;  

    return (jlong)peer;  

}  

 

JNIEXPORT void JNICALL  

Java_StructWrapper_destroy(JNIEnv* env, jobject self, jlong peer)  

{  

    delete (STRUCT*)peer;  

}  

 

Okay,现在可以定义主函数了。 

Java代码 

// Entry.java  

 

public class Entry {  

 

    private native void callCppFunc(long strutWrapperPeer);  

 

    public static void main(String[] args) {  

        StructWrapper struct = new StructWrapper(1, 'a');  

 

        new Entry().callCppFunc(struct.getPeer());  

 

        struct.destroy();  

    }  

 

}  

 

其对应的 C++ 实现, 

C++代码 

// Entry.h  

 

/* DO NOT EDIT THIS FILE - it is machine generated */  

#include <jni.h>  

/* Header for class Entry */  

 

#ifndef _Included_Entry  

#define _Included_Entry  

#ifdef __cplusplus  

extern "C" {  

#endif  

/* 

 * Class:     Entry 

 * Method:    callCppFunc 

 * Signature: (J)V 

 */  

JNIEXPORT void JNICALL Java_Entry_callCppFunc  

  (JNIEnv *, jobject, jlong);  

 

#ifdef __cplusplus  

}  

#endif  

#endif  

 

// Entry.cpp  

 

JNIEXPORT void JNICALL  

Java_Entry_callCppFunc(JNIEnv* env, jobject self, jlong structWrapperPeer)  

{  

    STRUCT* structPointer = (STRUCT*)structWrapperPeer;  

    CppFunc(structPointer);  

}  

 

如果顺利的话,您现在跑这个 Java 程序,应该输出 

引用

 

long value: 1 

char value: a 

 

【 IDA】使用IDA load file功能,导入JNI.h解析【JNI 函数】 一、需求: 使用IDA 导入C/C++头文件,添加头文件中的结构体,使用此结构体中的函数替换反汇编中的偏移,是文件可读性更好!!!! 二、步骤: 步骤一:点击IDAPro 菜单项“File->Load file->Parse c header file ” 选择jni.h头文件 步骤二:简单修改jni.h ,注释第27行的#include ,还有将1122行的#define JNI 阅读详情

相关推荐

JNI语法 JNI参考 JNI函数大全

原文地址:JNI语法 JNI参考 JNI函数大全 内容太多,请按Ctrl+F查找你需要的信息。   一、对照表 Java类型    本地类型         描述 boolean    jboolean       C/C++8位整型 byte       jbyte          C/C++带符号的8位整型 char       jchar         

Android移动开发者的专栏 3219

JNI中参数的传递与操作(上)

文章参自:http://wenku.baidu.com/view/0b78684669eae009581bec73.html http://wenku.baidu.com/view/3114e862caaedd3383c4d396.html JNI的所有的本地方法的第一个参数都是指向JNIEnv结构的。这个结构是用来调用JNI函数的。第二个参数jclass/j...

mmdev 309

Java与Delphi通过JNI实现本地调用实战指南

在Java Native Interface(JNI)体系中,Java本地方法的定义与动态库的加载构成了整个跨语言交互的基础。本章将从Java本地方法的声明与实现入手,逐步介绍如何编译并加载C/C++动态库,以及本地方法的注册与调用流程,最后探讨在实际开发过程中常见的错误与调试方法。在Java类中,使用native关键字声明一个本地方法。

weixin_42311427的博客 863

jni函数参数

在c语言中JNIEnv是结构体指针,代表java运行环境,调用java代码。JNIEnv * env,env是二级指针 在java中输出一个自符串(*env)->NewStringUTF(env,"C String"); 在C++中,JNIEnv是一个结构体的别名,JNIEnv *env;env是一个结构体指针, 在java中输出一个字符串,env->NewStringUTF("C+

难不难的博客 1602

从压电传感器到示波器:手把手教你用CA3140搭建电荷放大器(含PCB布局与调零技巧)

本文详细介绍了如何使用CA3140运算放大器搭建专业级电荷放大器,从压电传感器信号特性分析到PCB布局与调零技巧,全程实战演示。重点解析了CA3140的低通滤波器设计、反馈网络参数计算及抗干扰增强方案,帮助电子爱好者高效实现微弱电荷信号的稳定转换与测量。

weixin_31355483的博客 597

保姆级教程:手把手配置MAX9295/9296 GMSL2-CSI2链路,搞定4LAN/1LAN模式与常见调试

本文提供MAX9295/9296 GMSL2-CSI2链路的详细配置教程,涵盖4LAN和1LAN模式的硬件连接、寄存器配置及调试技巧。通过实战案例和代码示例,帮助开发者快速实现高带宽视频传输,解决常见问题如信号同步和功耗优化,适用于车载摄像头和机器人视觉系统开发。

weixin_42561143的博客 434

JNI调用c++函数,该函数的参数是结构体(——对象的传递)

第三方C++函数接口为 int api_get_logfile(Struct fileinfo tfile),参数是个结构体,且套了另一个结构体: struct fileinfo{  char *fullpath;  int filesize;  int filemode;  struct disnode *tnode; }; struct disnode{  int nu

haoruifly的专栏 6580

three.js中如何高效加载并播放GLB格式的3D动画

本文详细介绍了在three.js中高效加载并播放GLB格式3D动画的最佳实践。通过对比GLB与GLTF格式的优势,提供从环境搭建、模型加载到动画控制的完整解决方案,并分享性能优化技巧和常见问题排查方法,帮助开发者提升3D动画项目的开发效率和用户体验。

weixin_27890975的博客 362

JNI实现回调| JNI调用JAVA函数|参数和返回值的格式

代码下载:http://dl.dbank.com/c0c0xs3b24 一、JNI实现回调 通过JNI在Native层调用JAVA层的方法,来实现Native层向JAVA层传递消息。 JNICallback.java public class JNICallb

stefzeus的专栏 2万+

AnyLogic 建立谢林模型

AnyLogic 建立谢林模型说明创建一个新模型创建代理人群体和离散空间双击 people 前的图标,编辑 Person设置 Agent 的形状(Person)在模型中启用离散时间,实现代理行为点击 Person,进行编辑点击运行按钮效果图 说明 我们将把 Schelling 的模型实现为一个基于离散空间/离散时间的代理模型。空间代表一个城市,每个单元格代表一个房子。 agent 是人,是两种颜色:黄色和红色。 最初,人是随机分布在城市中的。人比房子少,所以总是有一个人可能会移动。 这个模型中的 agent

qq_45642410的博客 2577

STM32F407+LWIP实战:手把手教你移植mbedtls库实现Modbus TCP双向认证

本文详细介绍了如何在STM32F407微控制器上移植mbedtls库,结合LWIP协议栈实现Modbus TCP的双向认证功能。通过TLS 1.2加密通道,有效提升工业物联网通信的数据安全性,涵盖证书管理、内存优化及性能调优等关键步骤,为嵌入式系统开发者提供了一套完整的解决方案。

weixin_28721917的博客 516

Jni函数调用

Chap1:JNI完全手册... 3 Chap2:JNI-百度百科... 11 Chap 3:javah命令帮助信息... 16 Chap 4:用javah产生一个.h文件... 17 Chap5:jni教程(very very good) 19 Chap6: JNI传递返回值... 26 15.2.2.3 传递字符串... 28 15.2.2.4 传递整型数组... 29 15.

kangyaping的专栏 2万+

利用ArcMap实现遥感图像语义分割标注的完整流程解析

本文详细解析了利用ArcMap进行遥感图像语义分割标注的完整工作流。从工程创建、数据导入、SHP文件创建,到实战勾画地物、要素转栅格,再到最终的裁剪对齐,提供了每一步的关键操作与避坑指南。该方法特别适合处理大尺寸、带地理坐标的遥感影像,能高效产出精准对齐的图像-标签对,为后续深度学习模型训练奠定可靠的数据基础。

gpu4optimizer的博客 1212

android jni 结构体_JNI 返回结构体参数 android

如何使用JNI的一些基本方法和过程在网上多如牛毛,如果你对Jni不甚了解,不知道Jni是做什么的,如何建立一个基本的jni程序,或许可以参考下面下面这些文章:利用VC++6.0实现JNI的最简单的例子JNI入门教程之HelloWorld篇SUN JNI Tutorial这些资料的例子中,大多数只是输入一些简单的参数,获取没有参数。而在实际的使用过程中,往往需要对参数进行处理转换。才可以被C/C++...

weixin_28730927的博客 671

lidar点云比赛-Southlidar软件使用入门

lidar点云比赛-Southlidar软件使用入门 广西高校重点实验室培训基地 系统控制与信息处理重点实验室 本篇博客来自河池学院: 智控无人机小组 写作时间:2020.09.29 一、软件资源及安装 1.下载地址: https://pan.baidu.com/s/1jN1pynmAZOqj5mMx774pVg 提取码:gkvv (资源来自南方测绘) 2.安装 进入链接,找到软件文件夹, 内含文件即为安装包 3.下载成功后按提示安装即可 4.安装成功后桌面自动创建一个快捷方式 二、界面布

qq_49621416的博客 4891

ABAP BOM展开避坑指南:CS_BOM_EXPL_MAT_V2函数参数配置详解

本文深入解析了SAP ABAP开发中用于物料清单展开的核心函数CS_BOM_EXPL_MAT_V2。针对其复杂的参数配置,如CAPID、STLAN、DATUV和MEHRS,提供了详细的避坑指南和最佳实践,帮助开发者避免数据错误与性能陷阱,实现高效、准确的BOM多层展开。

pea55的博客 854

java代码通过JNI调用c函数

java代码通过JNI调用c函数 一. 总览 在Java代码中通过JNI调用C函数的步骤如下: 第一步:编写java代码 :在Java类中声明本地方法 第二步:编译java代码 :javac HelloJNI.java 生成 HelloJNI.class 第三步:生成C语言头文件 :使用javah命令,生成饱含JNI本地函数原型的头文件 第四步:编写C代...

阿路 1049

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

JNI函数调用大全

转自这里写链接内容 Chap1:JNI完全手册 3 Chap2:JNI-百度百科 11 Chap 3:javah命令帮助信息 16 Chap 4:用javah产生一个.h文件 17 Chap5:jni教程(very very good) 19 Chap6: JNI传递返回值 26 15.2.2.3 传递字符串 28 15.2.2.4 传递整型数组 29 15.2.2.

sbf2011的专栏 4525

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

JNI调用机制

JNI android ndk

com360的专栏 9025

JNI 传递结构体参数

JNI 传递结构体参数

vrix的专栏 1万+

JNI调用机制与JNI实现

JNI调用机制JNI第一篇 此文是JNI的第二篇博客,我在之前的博客里写过如何实现一个基本的JNI,这篇文章是上一篇的升级版,详细解释了各种参数和实现方式,所以,在阅读此文前,请先看下如何实现一个基本的JNI调用,点击跳转 JNI:Java Native Interface是java本地接口。所谓的native,这里指C/C++写的底层接口。 一般在java层调用C层有这样的需求: 调用驱动

Sizon的专栏 2491
上一篇: JNI 传递结构体参数
下一篇: JNI 返回结构体参数
vrix
博客等级 码龄24年 673粉丝 167原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值