我正在使用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
,每个public class CreateInfo extends Structure {
public int count;
public QueueInfo.ByReference queues;
}
public QueueInfo extends Structure {
int count;
public Pointer priorities;
}
都包含一个浮点值列表。
这些结构的简单JNA实现可以如下(为简洁省略了字段顺序,构造函数等):
QueueInfo
所以:
Structure::toArray
数组,我可以简单地将指针设置为该数组的第一个元素吗?或者我是否必须使用QueueInfo
分配数组?如果它们有结构,那么结构没有默认的构造函数?我可以在SO和一般网站上找到很多关于从本地库接收结构的问题,但是传递结构化数据相对较少。我发现的例子都使用不同的方法来解决同样的问题,这些问题对于应该非常简单的问题看起来非常复杂(?)所以我对“正确”方法感到迷茫。
我怀疑我不是在问正确的问题,这可能意味着我错过了一些关于JNA的基本信息。
希望某种灵魂可以指出上面的天真JNA代码有什么问题,以及如何在Java端填充数据。
1 - Jana Mappings
映射旨在将Java端类型直接与相应的本机端类型相关联。当这些映射所需的内存众所周知时,JNA可以很好地工作。不幸的是,当要映射的本机内存量是可变的时,这需要一些工作来分配和映射所需的本机内存。有几种方法可以实现这一点,具有不同的抽象/控制水平。
2 - 已经有QueueInfo [](第1部分)
通过你在问题中定义Pointer
的方式,它没有用。您只定义了一个Java端类,但Structure
类意味着一个本机内存指针。您应修改您的类以扩展public
并在count
字段上使用int
。请注意,实例化此结构只会为Pointer
和one way of doing this分配本机内存。阵列本身的内存需要单独分配。
3 - 分配float数组
正如我在评论中提到的,Memory buffer = new Memory(count * Native.getNativeSize(Float.TYPE));
是为float数组分配本机内存:
float[] buf
然后假设您已定义buffer.write(0L, buf, 0, count);
,您可以使用将其复制到本机内存中
buffer
然后你可以使用priorities
作为QueueInfo
实例的Structure::toArray
字段。
2 - 已经有QueueInfo [](第2部分)
现在问题是,除非您知道有一个连续的C端数组,否则不能只将指针设置为第一个元素。您的选择是使用Pointer
分配内存(然后填充每个元素)或单独创建(连续)指针数组并从单独分配的结构复制toArray
值。对于QueueInfo
变体,如果直接在生成的数组中设置值,则不需要指针构造函数,但指针构造函数可以更容易地进行复制(从一个本机内存块到另一个)。
摘要
选项1:使用Pointer.write()
方法为浮点数组实例化单独的float[]
结构。创建一个构造函数可能会有所帮助,该构造函数将count
作为参数并设置priorities
并分配和设置Pointer
变量,如上所述。然后,为CreateInfo
结构创建一个Structure::toArray
s数组,并复制每个元素的引用指针。
选项2:使用QueueInfo
创建一个结构数组来分配本机内存;然后迭代这个结构并直接在适当的索引处创建qazxswpoi结构。