繁体   English   中英

如何使用JNA从Java将int作为C ++函数参数传递

[英]How to pass int as a C++ function parameter from Java using JNA

我目前正在从事一个项目,该项目需要开发一个本机DLL(在C ++中)才能由Java应用程序访问。 我已选择JNA进行桥接,但是在将正确的int值从Java传递到C ++函数时遇到了问题。

简单地说,我有一个函数可以接受int值作为C ++中的参数:(剥离了代码,并重命名了方法以保持机密性)

JAVALINK_EXPORT SomeStructure WINAPI GetSomeStructureFromIndex(int index) {
    std::string debugMsg("Received index of ");
    debugMsg.append(toString(index));
    OutputDebugString(debugMsg.c_str());
    SomeStructure result = defaultStructure;
    if (index >= 0 && index < structListSize)
        result = structList[index];

    return result;
}

toString是一种转换的任何数据类型的值,以一个简单的方法std::string使用std::stringstream 实现如下:

template <class T>
inline std::string toString (const T& t) {
    std::stringstream ss;
    ss << t;
    return ss.str();
}

SomeStructure从我在代码中使用的实际结构重命名。 structList是阵列SomeStructure structListSizestructList都是共享内存中的全局变量。

这是DLL的Java接口中的方法签名:

SomeStructure.ByValue GetSomeStructureFromIndex(int index);

这就是我将Java中的方法用于测试用例的方式:

SomeStructure.ByValue received = library.GetSomeStructureFromIndex(1);

library是使用Native.loadLibrary生成的DLL文件( StdCallLibrary子类)的接口的实例。 当上述代码在Java中执行时,我的Windows调试输出中得到类似以下输出的内容:

Received index of 86701080

(如果我在从数组中获取结构之前省略了对if (index >= 0 && index < structListSize)行的index检查,则程序将继续遇到访问冲突错误)

86701080可以是任意值。 我意识到它会根据导出函数的签名而变化。 我在这里想念什么吗? 如果函数签名为void PrintIndex(int index)该函数正确接收期望值为1void PrintIndex(int index)

EDIT(0):我修改了示例代码以使其更接近实际代码。

EDIT(1):根据ByValue的指针,我已开始将ByValue用于所有方法签名和收集返回结构的变量。

EDIT(2):与C ++中的SomeStructure结构相比,Java类SomeStructure具有一个额外的变量和Java方法。 我目前正在测试是否是导致差异的原因。

问题解决了

@technomage解释说,对于C ++函数来说,按预期解释其参数和返回值,用作返回类型的结构(以及用作函数参数的结构)的大小不应与Java对应的大小相同。 SomeStructure的情况下,可以在C ++中使用sizeof(SomeStructure)进行检查,在Java中使用SomeStructure.size()

基本上,发生的事情是SomeStructure结构的大小与其Java表示的大小不同。 SomeStructure包含一个固定长度的数组,如下面的代码所示:

#define MAX_LIST_SIZE 256
typedef struct {
    int list[MAX_LIST_SIZE];
    int length;
} SomeStructure;

但是,Java表示没有指定固定长度数组的大小。 list初始化为包含单个值0

package model;

import com.sun.jna.Structure;

public class SomeStructure extends Structure {
    public static class ByValue extends SomeStructure implements Structure.ByValue { }
    public int[] list = {0};
    public int length = 0;
}

我通过将错误的初始化语句替换为以下内容来解决了该问题:

private static final int MAX_LIST_SIZE = 256;
public int[] list = new int[MAX_LIST_SIZE];

注意 :整数常量MAX_LIST_SIZE被声明为private以使其仅限于Java。

进行所有这些修改后,我的代码可以正常工作,不再遇到访问冲突。

“ WINAPI”表示stdcall调用约定,但是您必须确定本地的宏定义才能确定。 如果是这样,则需要StdCallLibrary而不是Library 这可能会影响您的传入index参数。

您还将复制结构(通过值语义),而不是指向它的指针。 当按值传递结构或按值返回结构时,您需要告诉JNA您正在这样做

编辑

确保SomeStructure.size()与本机sizeof(SomeStructure)匹配。 通常,实现按值返回的结构,以便调用方在堆栈上分配内存,并将隐式指针传递给被调用方,然后该被调用方将其写入该内存。 如果调用方和被调用方在该内存大小上存在分歧,则可能影响堆栈上的其他内容(例如,参数和返回值)。 您还可以向函数添加更多参数,并打印它们的值(十六进制),以大致了解堆栈中的内容。 如果传入可识别的参数(例如0x12345678),通常会很清楚是什么在错误的方向推动或拉动堆栈。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM