简体   繁体   English

JNA 传递结构包含指向结构的指针和指向原语的指针

[英]JNA passing structure containing pointer to structure(s) and pointer to primitive

I am using JNA and finding it very straight-forward for retrieving data from a native library, but struggling to understand how to to do it the other way round, ie passing structured data to a native method.我正在使用 JNA 并发现它可以非常直接地从本机库中检索数据,但很难理解如何以相反的方式进行操作,即将结构化数据传递给本机方法。

I'll use a small example from part of the library I'm trying to invoke.我将使用我试图调用的库中的一个小例子。

The native library typedefs are as follows:原生库 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;

So we have a CreateInfo that refers to a number of QueueInfo each of which contains a list of floating-point values.所以我们有一个CreateInfo ,它引用了许多QueueInfo每个QueueInfo都包含一个浮点值列表。

A naive JNA implementation of these structure could be as follows (field order, constructors, etc omitted for brevity):这些结构的原始 JNA 实现可能如下(为简洁起见,省略了字段顺序、构造函数等):

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

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

So:所以:

  1. The JAN mappings are (intentionally) naive but are they really stupid? JAN 映射(故意)幼稚,但它们真的很愚蠢吗? If so what are the logical types?如果是,逻辑类型是什么?

  2. If I already have an array of QueueInfo can I simply set the pointer to the first element of that array?如果我已经有一个QueueInfo数组,我可以简单地将指针设置为该数组的第一个元素吗? Or do I have to allocate an array using Structure::toArray ?还是我必须使用Structure::toArray分配数组? The structures have no constructor other than the default, should they have?这些结构除了默认值之外没有构造函数,应该有吗?

  3. I have the queue priorities float array but how do I set the pointer?我有队列优先级浮点数组,但如何设置指针? Should it actually be a pointer or something else?它实际上应该是一个指针还是其他什么东西? A float[]?一个浮动[]?

I can find lots of questions on SO and the interwebs in general for receiving structures from a native library, but relatively few for passing structured data.我可以在 SO 和一般的互联网上找到很多关于从本地库接收结构的问题,但对于传递结构化数据的问题相对较少。 And the examples I've found all use different approaches for the same problem that seem very complex for what should be pretty simple (?) so I'm at a lost for the 'correct' approach.我发现的所有示例都对同一问题使用了不同的方法,这些方法对于应该非常简单的(?)来说似乎非常复杂,因此我对“正确”方法感到迷茫。

I suspect I'm not asking the right questions which probably means I'm missing something fundamental about JNA.我怀疑我没有提出正确的问题,这可能意味着我错过了 JNA 的一些基本知识。

Hopefully some kind soul can point out what is wrong with the naive JNA code above and how it could be populated with data on the Java side.希望有好心人能指出上面朴素的 JNA 代码有什么问题,以及如何用 Java 端的数据填充它。

1 - JNA mappings 1 - JNA 映射

Mappings are designed to directly relate Java-side types to the corresponding native side types.映射旨在将 Java 端类型直接关联到相应的本机端类型。 When the memory required for these mappings is well known, JNA works very well.当这些映射所需的内存众所周知时,JNA 工作得很好。 Unfortunately, when the amount of native memory to be mapped is variable, that requires a bit of work to allocate and map the required native memory.不幸的是,当要映射的本机内存量是可变的时,需要做一些工作来分配和映射所需的本机内存。 There are a few ways to go about doing this, with varying levels of abstraction/control.有几种方法可以做到这一点,具有不同的抽象/控制级别。

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

With the way you've defined QueueInfo in your question, it's not helpful.按照您在问题中定义QueueInfo的方式,它没有帮助。 You've only defined a Java-side class but the Pointer class implies a native memory pointer.您只定义了一个 Java 端类,但Pointer类暗示了本机内存指针。 You should modify your class to extend Structure and use public on your count field.您应该修改您的类以扩展Structure并在您的count字段上使用public Note that instantiating this structure will only allocate native memory for the int and the Pointer .请注意,实例化此结构只会为intPointer分配本机内存。 The memory for the array itself will need to be allocated separately.数组本身的内存需要单独分配。

3 - allocate float array 3 - 分配浮点数组

As I mentioned in the comments, one way of doing this is to allocate native memory for the float array:正如我在评论中提到的,这样做的一种方法是为浮点数组分配本机内存:

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

Then assuming you have float[] buf defined you can copy this into the native memory using然后假设您定义了float[] buf您可以使用以下命令将其复制到本机内存中

buffer.write(0L, buf, 0, count);

You can then just use buffer as the priorities field of your QueueInfo instance.然后,您可以将buffer用作QueueInfo实例的priorities字段。

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

Now to the question, you can't just set the pointer to the first element unless you know you have a contiguous C-side array.现在回答这个问题,除非您知道您有一个连续的 C 端数组,否则您不能只将指针设置为指向第一个元素。 Your choices are using Structure::toArray to allocate the memory (and then populating each element) or separately creating an array of (contiguous) pointers and copying over the Pointer value from your separately allocated structures.您的选择是使用Structure::toArray分配内存(然后填充每个元素)或单独创建(连续)指针数组并从单独分配的结构中复制Pointer值。 For the toArray variant, you don't need a pointer constructor if you directly set the values in the generated array, but the pointer constructor can make copying (from one native memory block to the other) easier.对于toArray变体,如果直接在生成的数组中设置值,则不需要指针构造函数,但指针构造函数可以使复制(从一个本机内存块到另一个)更容易。

Summary概括

Option 1: instantiate separate QueueInfo structures using the Pointer.write() method for the float array.选项 1:使用浮点数组的Pointer.write()方法实例化单独的QueueInfo结构。 It might be helpful to create a constructor which takes the float[] as an argument and sets the count and allocates and sets priorities variable as described above.创建一个构造函数可能会有所帮助,该构造函数将float[]作为参数并设置count并如上所述分配和设置priorities变量。 Then, create an array of Pointer s for the CreateInfo structure and copy over each element's reference pointer.然后,为CreateInfo结构创建一个Pointer数组,并复制每个元素的引用指针。

Option 2: create an array of structures using Structure::toArray to allocate the native memory;选项 2:使用Structure::toArray创建一个结构数组来分配本机内存; then iterate over this structure and directly create the QueueInfo structures at the appropriate index.然后迭代这个结构并直接在适当的索引处创建QueueInfo结构。

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

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