JNA 传递包含结构指针和基元指针的结构

JNA passing structure containing pointer to structure(s) and pointer to primitive

我正在使用 JNA 并发现它非常直接地从本机库中检索数据,但很难理解如何以相反的方式执行此操作,即将结构化数据传递给本机方法。

我将使用我尝试调用的部分库中的一个小示例。

原生库typedef如下:

typedef struct CreateInfo {
    int count;                    // Number of queue infos
    const QueueInfo* queues;      // Zero-or-more queue info structures
} CreateInfo;

typedef struct QueueInfo {
    int count;                    // Number of queue priorities
    const float* priorities;      // 'array' of queue priorities
} QueueInfo;

所以我们有一个 CreateInfo,它引用了多个 QueueInfo,每个都包含一个浮点值列表。

这些结构的简单 JNA 实现如下(为简洁起见省略了字段顺序、构造函数等):

public class CreateInfo extends Structure {
    public int count;
    public QueueInfo.ByReference queues;
}

public QueueInfo extends Structure {
    int count;
    public Pointer priorities;
}

所以:

  1. JAN 映射(有意)幼稚,但它们真的很愚蠢吗?如果是这样,逻辑类型是什么?

  2. 如果我已经有一个QueueInfo的数组,我可以简单地将指针设置为该数组的第一个元素吗?还是我 使用 Structure::toArray 分配数组?这些结构没有默认构造函数,它们应该有吗?

  3. 我有队列优先级浮点数组,但如何设置指针?它实际上应该是一个指针还是其他什么东西?一个浮点数[]?

我可以在 SO 和互联网上找到很多关于 从本机库接收 结构的问题,但对于 传递 [=49= 的问题相对较少] 结构化数据。我发现的示例都针对同一个问题使用了不同的方法,这些方法对于应该非常简单的问题(?)来说似乎非常复杂,所以我对 'correct' 方法感到困惑。

我怀疑我没有问正确的问题,这可能意味着我遗漏了一些关于 JNA 的基本知识。

希望有好心人能指出上面朴素的 JNA 代码有什么问题,以及如何在 Java 端用数据填充它。

1 - JNA 映射

映射旨在直接将 Java 端类型与相应的本机端类型相关联。当这些映射所需的内存是众所周知的时,JNA 工作得很好。不幸的是,当要映射的本机内存量可变时,需要做一些工作来分配和映射所需的本机内存。有几种方法可以做到这一点,具有不同级别的 abstraction/control.

2 - 已经有 QueueInfo[](第 1 部分)

根据您在问题中定义 QueueInfo 的方式,这没有帮助。您只定义了 Java 端 class,但 Pointer class 暗示了本机内存指针。您应该修改 class 以扩展 Structure 并在 count 字段上使用 public。请注意,实例化此结构只会为 intPointer 分配本机内存。数组本身的内存需要单独分配。

3 - 分配浮点数组

正如我在评论中提到的,one way of doing this 是为浮点数组分配本机内存:

Memory buffer = new Memory(count * Native.getNativeSize(Float.TYPE));

然后假设您定义了 float[] buf,您可以使用

将其复制到本机内存中
buffer.write(0L, buf, 0, count);

然后您可以只使用 buffer 作为 QueueInfo 实例的 priorities 字段。

2 - 已经有 QueueInfo[](第 2 部分)

现在回答问题,除非您知道您有一个连续的 C 端数组,否则您不能只将指针设置为第一个元素。您的选择是使用 Structure::toArray 分配内存(然后填充每个元素)或单独创建一个(连续)指针数组并从单独分配的结构中复制 Pointer 值。对于 toArray 变体,如果直接在生成的数组中设置值,则不需要指针构造函数,但指针构造函数可以使复制(从一个本机内存块到另一个内存块)更容易。

总结

选项 1:使用浮点数组的 Pointer.write() 方法实例化单独的 QueueInfo 结构。创建一个将 float[] 作为参数并设置 count 并分配和设置 priorities 变量的构造函数可能会有所帮助,如上所述。然后,为 CreateInfo 结构创建一个 Pointer 的数组,并复制每个元素的引用指针。

选项 2:使用 Structure::toArray 创建结构数组以分配本机内存;然后迭代这个结构并直接在适当的索引处创建 QueueInfo 结构。