I'm trying to transmit and receive a Structure Array with JNA from C# to/from Java. Receiving from C# in Java works fine, but transmitting to C# gives only one Line. I think the Problem is "pointerByReference.setPointer(array[0].getPointer())". But I don´t know how to create the PointerByReference for an Array to populate all Items. Can someone help me?
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 Interface
public interface IJNA extends 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);
}
}
Output:
--- 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
EDIT: I changed my code, but still get the same result.
@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);
}
Output:
--- setStructureArray ------------------------------------------------
Length: 1
1
2
3
Hello from Java 1
EDIT 2:
I found the Solution by my self:
Only add the MarshalAs Argument to the Method works.
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);
}
}