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;
}
所以:
JAN 映射(有意)幼稚,但它们真的很愚蠢吗?如果是这样,逻辑类型是什么?
如果我已经有一个QueueInfo
的数组,我可以简单地将指针设置为该数组的第一个元素吗?还是我 有 使用 Structure::toArray
分配数组?这些结构没有默认构造函数,它们应该有吗?
我有队列优先级浮点数组,但如何设置指针?它实际上应该是一个指针还是其他什么东西?一个浮点数[]?
我可以在 SO 和互联网上找到很多关于 从本机库接收 结构的问题,但对于 传递 [=49= 的问题相对较少] 结构化数据。我发现的示例都针对同一个问题使用了不同的方法,这些方法对于应该非常简单的问题(?)来说似乎非常复杂,所以我对 'correct' 方法感到困惑。
我怀疑我没有问正确的问题,这可能意味着我遗漏了一些关于 JNA 的基本知识。
希望有好心人能指出上面朴素的 JNA 代码有什么问题,以及如何在 Java 端用数据填充它。
1 - JNA 映射
映射旨在直接将 Java 端类型与相应的本机端类型相关联。当这些映射所需的内存是众所周知的时,JNA 工作得很好。不幸的是,当要映射的本机内存量可变时,需要做一些工作来分配和映射所需的本机内存。有几种方法可以做到这一点,具有不同级别的 abstraction/control.
2 - 已经有 QueueInfo[](第 1 部分)
根据您在问题中定义 QueueInfo
的方式,这没有帮助。您只定义了 Java 端 class,但 Pointer
class 暗示了本机内存指针。您应该修改 class 以扩展 Structure
并在 count
字段上使用 public
。请注意,实例化此结构只会为 int
和 Pointer
分配本机内存。数组本身的内存需要单独分配。
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
结构。
我正在使用 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;
}
所以:
JAN 映射(有意)幼稚,但它们真的很愚蠢吗?如果是这样,逻辑类型是什么?
如果我已经有一个
QueueInfo
的数组,我可以简单地将指针设置为该数组的第一个元素吗?还是我 有 使用Structure::toArray
分配数组?这些结构没有默认构造函数,它们应该有吗?我有队列优先级浮点数组,但如何设置指针?它实际上应该是一个指针还是其他什么东西?一个浮点数[]?
我可以在 SO 和互联网上找到很多关于 从本机库接收 结构的问题,但对于 传递 [=49= 的问题相对较少] 结构化数据。我发现的示例都针对同一个问题使用了不同的方法,这些方法对于应该非常简单的问题(?)来说似乎非常复杂,所以我对 'correct' 方法感到困惑。
我怀疑我没有问正确的问题,这可能意味着我遗漏了一些关于 JNA 的基本知识。
希望有好心人能指出上面朴素的 JNA 代码有什么问题,以及如何在 Java 端用数据填充它。
1 - JNA 映射
映射旨在直接将 Java 端类型与相应的本机端类型相关联。当这些映射所需的内存是众所周知的时,JNA 工作得很好。不幸的是,当要映射的本机内存量可变时,需要做一些工作来分配和映射所需的本机内存。有几种方法可以做到这一点,具有不同级别的 abstraction/control.
2 - 已经有 QueueInfo[](第 1 部分)
根据您在问题中定义 QueueInfo
的方式,这没有帮助。您只定义了 Java 端 class,但 Pointer
class 暗示了本机内存指针。您应该修改 class 以扩展 Structure
并在 count
字段上使用 public
。请注意,实例化此结构只会为 int
和 Pointer
分配本机内存。数组本身的内存需要单独分配。
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
结构。