我正试图用JNA从C向Java发送和接收结构数组。在Java中,从C#接收可以很好地工作,但传输到C#只会给出一行。我认为问题是“pointerByReference.setPointer(数组[0].getPointer())”。但是我不知道如何为数组创建PointerByReference来填充所有项。有人能帮我吗?
C#
using System;
using System.Runtime.InteropServices;
namespace JNATest
{
public class Class1
{
[StructLayout(LayoutKind.Sequential)]
public struct Struct
{
public int x;
public int y;
public int z;
public string name;
}
[DllExport]
public static int getStructureArray(out Struct[] structureArray)
{
structureArray = new Struct[] {
new Struct { x = 12345, y = 99, z = 65432, name = "Hello from C# 1" },
new Struct { x = 4423, y = 44, z = 31, name = "Hello from C# 2" },
new Struct { x = 65233, y = 1244, z = 323, name = "Hello from C# 3" },
};
return structureArray.Length;
}
[DllExport]
public static void setStructureArray(Struct[] structureArray)
{
Console.WriteLine("Length: " + structureArray.Length);
for (int i = 0; i < structureArray.Length; i++)
{
Console.WriteLine(structureArray[i].x);
Console.WriteLine(structureArray[i].y);
Console.WriteLine(structureArray[i].z);
Console.WriteLine(structureArray[i].name);
}
}
}
}
Java接口
公共接口IJNA扩展Library{IJNA INSTANCE=(IJNA)Native.load("JNATest.dll", IJNA. class);
@FieldOrder({ "x", "y", "z", "name" })
public class Struct extends Structure {
public int x;
public int y;
public int z;
public String name;
public Struct() {
}
public Struct(Pointer pointer) {
super(pointer);
read();
}
public Struct(Pointer pointer, int offset) {
super(pointer.share(offset));
read();
}
public Struct(Struct struct) {
super(struct.getPointer());
read();
}
public static class ByReference extends Struct implements Structure.ByReference {
public ByReference(Pointer pointer) {
super(pointer);
}
}
public static class ByValue extends Struct implements Structure.ByValue {
}
}
public int getStructureArray(PointerByReference structureArray);
public void setStructureArray(PointerByReference structureArray);
Java Main
import com.sun.jna.ptr.PointerByReference;
public class Main {
public static void main(String[] args) {
getStructureArray();
setStructureArray();
}
public static void getStructureArray() {
System.out.println("--- getStructureArray ------------------------------------------------");
PointerByReference pointerByReference = new PointerByReference();
int length = IJNA.INSTANCE.getStructureArray(pointerByReference);
IJNA.Struct.ByReference structure =
new IJNA.Struct.ByReference(pointerByReference.getValue());
IJNA.Struct.ByReference structures[] = (IJNA.Struct.ByReference[]) structure.toArray(length);
System.out.println("Length: " + length);
for (int i = 0; i < structures.length; i++) {
structure = structures[i];
System.out.println("x: " + structure.x);
System.out.println("y: " + structure.y);
System.out.println("z: " + structure.z);
System.out.println("name: " + structure.name);
}
}
public static void setStructureArray() {
System.out.println("--- setStructureArray ------------------------------------------------");
IJNA.Struct[] array = new IJNA.Struct[5];
for (int i = 0; i < array.length; i++) {
array[i] = new IJNA.Struct();
array[i].x = 1;
array[i].y = 2;
array[i].z = 3;
array[i].name = "Hello from Java " + (i + 1);
array[i].write();
}
PointerByReference pointerByReference = new PointerByReference();
pointerByReference.setPointer(array[0].getPointer());
IJNA.INSTANCE.setStructureArray(pointerByReference);
}
}
输出:
--- getStructureArray ------------------------------------------------
Length: 3
x: 12345
y: 99
z: 65432
name: Hello from C# 1
x: 4423
y: 44
z: 31
name: Hello from C# 2
x: 65233
y: 1244
z: 323
name: Hello from C# 3
--- setStructureArray ------------------------------------------------
Length: 1
1
2
3
Hello from Java 1
编辑:我更改了代码,但仍然得到相同的结果。
@FieldOrder({ "x", "y", "z", "name" })
public class Struct extends Structure {
public int x;
public int y;
public int z;
public String name;
}
public static void setStructureArray() {
System.out.println("--- setStructureArray -------------------------------
-----------------");
IJNA.Struct struct = new IJNA.Struct();
IJNA.Struct[] array = new IJNA.Struct[5];
long size = struct.size();
Memory memory = new Memory(array.length * size);
for (int i = 0; i < array.length; i++) {
array[i] = IJNA.Struct.newInstance(IJNA.Struct.class, memory.share(i
* size, size));
array[i].x = 1;
array[i].y = 2;
array[i].z = 3;
array[i].name = "Hello from Java " + (i + 1);
}
IJNA.INSTANCE.setStructureArray(array);
}
输出:
--- setStructureArray ------------------------------------------------
Length: 1
1
2
3
Hello from Java 1
编辑2:
我自己找到了解决方案:
只有将MarshalAs参数添加到方法中才有效。
C#
[DllExport]
public static void setStructureArray([In, Out,
MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] Struct[]
structureArray, int length)
{
Console.WriteLine("Length: " + structureArray.Length);
for (int i = 0; i < structureArray.Length; i++)
{
Console.WriteLine(structureArray[i].x);
Console.WriteLine(structureArray[i].y);
Console.WriteLine(structureArray[i].z);
Console.WriteLine(structureArray[i].name);
}
}
我自己找到了解决方案:
只有将MarshalAs参数添加到方法中才有效。
C#
[DllExport]
public static void setStructureArray([In, Out,
MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] Struct[]
structureArray, int length)
{
Console.WriteLine("Length: " + structureArray.Length);
for (int i = 0; i < structureArray.Length; i++)
{
Console.WriteLine(structureArray[i].x);
Console.WriteLine(structureArray[i].y);
Console.WriteLine(structureArray[i].z);
Console.WriteLine(structureArray[i].name);
}
}
在C中,数组是由单个连续内存块组成的“平面”。
您在Java端定义了数组,如下所示:
IJNA.Struct[] array = new IJNA.Struct[5];
for (int i = 0; i < array.length; i++) {
array[i] = new IJNA.Struct();
...
}
这会产生5个结构,每个结构在本机端都有非连续的内存支持。当您将指针传递给数组的第一个元素时,本机端不知道数组的其他元素在哪里。
需要在Java端使用Structure.toArray()
来分配连续内存:
IJNA.Struct[] array = (IJNA.Struct[]) new IJNA.Struct().toArray(5);
for (int i = 0; i < array.length; i++) {
// array[i] = new IJNA.Struct(); <-- no longer needed
...
}
这声明了为所有5个结构提供足够空间的后备内存,并在内部实例化了Java端对象,每个对象都参考其自己的起始内存地址:
// This is internal to Structure.toArray.
// You do not need to implement this yourself
array[i] = newInstance(getClass(), memory.share(i*size, size));
您仍然可以像现在一样将地址传递给元素,但不同的是,其他元素实际上位于本机端预期的位置,偏移了第一个结构的大小。
问题内容: 我在C 中有一个方法,该方法将双精度数组作为参数。我从Java调用此方法,需要传递一个双精度数组。C 例程读取和修改数组的值,而我需要Java中的那些更新后的值。我该怎么做呢? 例如,使用C ++例程: 和Java代码: 我猜不能像上面的调用那样对myMethod进行调用…还是可以吗?而在Swig中进行这项工作所需的是什么。如果我无法进行上述调用,如何将我的值获取到C ++代码? 问题
我目前正在做一个项目,需要开发一个原生DLL(用C++)来访问Java应用程序。我选择了JNA来做桥接工作,我面临着从Java向C++函数传递正确的int值的问题。 简单地说,我有一个函数在C++中接受一个int值作为参数:(代码被剥离,方法被重命名以保持机密性) 是一种简单的方法,它使用将任何数据类型的值转换为。执行情况如下: 是从我在代码中使用的实际结构重命名的。是的数组。和都是共享内存中的全
问题内容: 我有一个字符串数组一样,我想这个数组发送到 ç 使用 JNI 。我找不到任何明确的解决方案。我试图将此字符串视为成功,但没有成功。 有没有办法做到这一点? 问题答案: 您可以编写一个简单的函数,该函数接受一个对象,将每个对象强制转换为jstring,然后对其进行调用。 像这样:
装饰器定义了一组可以从父组件传递的参数。例如,我们可以修改HelloComponent组件,以便可以由父提供。 我们现在可以使用我们的组件:
问题内容: C部分: 开始部分: 我可以通过这种方式获取数组的第一个元素。但是如何获得带有n个元素的整个数组呢?以及如何安全地释放它们? 问题答案: 首先,即使您正在使用Go,添加cgo时也不再存在任何“安全”。由您决定何时以及如何释放内存,就像使用C进行编程一样。 在go中使用C数组的最简单方法是通过数组将其转换为切片: 最大大小的数组实际上并未分配,但是Go需要恒定大小的数组,并且要足够大。该
我编写了以下类来包装win32事件对象的创建 我在Windows7机器上使用JNA3.3,当我试图创建这个类的实例时,我得到了以下堆栈跟踪。 线程“main”java.lang.UnsatifiedLinkError中出现异常:查找函数“CreateEvent”时出错:找不到指定的过程。