JNA中的Marshal.StructureToPtr Java等效项

时间:2020-09-17 20:56:06

标签: java c# jna

我正在一个项目中,我唯一要传达的lib是一个.dll文件,而我拥有的资源是一个带有源代码的C#工作项目;我正在使用JNA访问本机代码,并且在调用该方法时当前遇到了无效的内存访问;

c#代码:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]  
public struct RSSlapInfo
{
    public int fingerType;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
    public RSPoint[] fingerPosition;
    public int imageQuality;
    public int rotation;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
    public int[] reserved;
};

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct RSSlapInfoArray
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
    public RSSlapInfo[] RSSlapInfoA;
};

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct RSPoint
{
    public int x;
    public int y;
};

RSSlapInfoArray slapInfoA = new RSSlapInfoArray();
IntPtr slapInfoArray;

int _size = Marshal.SizeOf(typeof(RSSlapInfoArray));
slapInfoArray = Marshal.AllocHGlobal(_size);
Marshal.StructureToPtr(slapInfoA, slapInfoArray, true);

在调试模式下,我注意到上述调用后slapInfoArray的值发生了变化

我的Java代码:

public static class RSSlapInfo extends Structure
{
    public RSSlapInfo(){}
    public int fingerType;
    public RSPoint[] fingerPosition = new RSPoint[4];
    public int imageQuality;
    public int rotation;
    public int[] reserved =new int[3];
}
    
@Structure.FieldOrder({"RSSlapInfoA"})
public static class RSSlapInfoArray extends Structure implements Structure.ByValue
{
    public RSSlapInfoArray() {
    }

    public RSSlapInfo RSSlapInfoA[] = new RSSlapInfo[4];
}

@Structure.FieldOrder({"x","y"})
public static class RSPoint extends Structure
{
    public RSPoint(){
    }

    public int x;
    public int y;
}

在我使用slapInfoArray进行本机调用之前,当前停留在正确的方式来转换代码的C#部分

RSSlapInfoArray slapInfoA = new RSSlapInfoArray();
IntPtr slapInfoArray;
    
int _size = Marshal.SizeOf(typeof(RSSlapInfoArray));
slapInfoArray = Marshal.AllocHGlobal(_size);
Marshal.StructureToPtr(slapInfoA, slapInfoArray, true);

1 个答案:

答案 0 :(得分:0)

Marshal.StructureToPtr()的文档为您提供了有关您需要做什么的强烈提示:

将数据从托管对象封送到非托管内存块。

structure一个托管对象,其中包含要封送的数据。该对象必须是格式化类的结构或实例。

ptr指向非托管内存块的指针,必须在调用此方法之前分配该内存。

您具有结构参数,但是您需要分配第二个参数所需的内存块。这可以通过JNA的Memory类来完成。

复杂的是,您需要传递的结构实际上包含其他结构的数组,并且必须在连续内存中分配。您在RSSlapInfoArray包装中完成此操作的方式实际上根本没有分配任何内存;它只是声明一个带有空指针的Java端数组,该数组将传递给本机端。

您需要做的第一件事是更正RSSlapInfoArray映射以连续分配结构数组。更改

public RSSlapInfo RSSlapInfoA[] = new RSSlapInfo[4]; // does not allocate anything

public RSSlapInfo[] RSSlapInfoA = (RSSlapInfo[]) new RSSlapInfo().toArray(4); // contiguous allocation 

您应该对RSPoint数组执行类似的操作:

public RSPoint[] fingerPosition = new RSPoint().toArray(4);

关于结构映射的另一条注释:您重写了Structure类构造函数而未实现它。您应该删除(不需要的)构造函数,或者在构造函数内部调用super()

假设您已经在加载DLL的接口中映射了StructureToPtr:

void StructureToPtr(Structure structure, Pointer ptr, boolean fDeleteOld);

然后问题中最后5行的JNA代码应该是

// Create the managed structure with the array inline
RSSlapInfoArray slapInfoA = new RSSlapInfoArray();
// Allocate a block of memory for it
Memory slapInfoArray = new Memory(slapInfoA.size());
// Call StructureToPtr
YourInterface.INSTANCE.StructureToPtr(slapInfoA, slapInfoArray, true);
相关问题