Struct JNA-使用结构数组作为byref参数

Struct JNA-使用结构数组作为byref参数,struct,arguments,pass-by-reference,jna,Struct,Arguments,Pass By Reference,Jna,我知道这个问题的一部分已经被这里的一些帖子所覆盖,我已经看过了一些帖子并测试了一些,但是没有运气。 我有这个本机方法签名,它应该填充提供的CBadgeData结构数组,结果如下: int elc_GetBadges(int nHandle, char* cErr, int* nRecCount, CBadgeData** arr) CBadgeData结构的实现如下: package test.elcprog; import java.util.Arrays; import java.uti

我知道这个问题的一部分已经被这里的一些帖子所覆盖,我已经看过了一些帖子并测试了一些,但是没有运气。 我有这个本机方法签名,它应该填充提供的CBadgeData结构数组,结果如下:

int elc_GetBadges(int nHandle, char* cErr, int* nRecCount, CBadgeData** arr)
CBadgeData结构的实现如下:

package test.elcprog;

import java.util.Arrays;
import java.util.List;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;

public class CBadgeData extends Structure{

    public static class ByReference extends CBadgeData implements Structure.ByReference { }

    public int nBadgeID, nTrigger, nExtraData;
    public String cName;

    public CBadgeData(Pointer pointer){
        super(pointer);
    }

    public CBadgeData(){ }

    public String ToString() {
        return nBadgeID + "," + nTrigger + "," + nExtraData + "," + cName;
    }

    @Override
    protected List getFieldOrder() {
        String[] s = new String[]{"nBadgeID","nTrigger","nExtraData","cName"};
        return Arrays.asList(s);
    }
}
我最后一次尝试创建此参数并调用此方法的方式如下:

CBadgeData.ByReference[] badges = new CBadgeData.ByReference[max_items];
new CBadgeData.ByReference().toArray(badges);
int ret = inst.elc_GetBadges(handle, err, recCount, badges);
它因分段错误而失败。

我的问题是,在调用
elc\u GetBadges
时,这里应该提供什么Java类型作为本机
CBadgeData**
的参数?

编辑-1-

自己填充数组(使用或不使用终止空指针)不起作用,并导致进一步的Seg崩溃。然后,我使用technomage建议的指针[]arg:

Pointer[] pointers = new Pointer[max_items];
for(int i=0; i<max_items; i++){
    pointers[i] = new CBadgeData.ByReference().getPointer();
}
int ret = inst.elc_GetBadges(handle, err, recCount, pointers);
在结构上使用explicit read()/write()会导致Seg再次崩溃(在读取时): 你知道我还缺什么吗


编辑-2-

有趣的是,在调用本机方法后,直接使用
Memory.get
获得正确的结果:

Memory m= (Memory)pointers[0];
System.out.println("1st int: "+m.getInt(0)); // this gets 24289 which is 5ee1
System.out.println("2nd int: "+m.getInt(4)); // this gets 3
System.out.println("3rd int: "+m.getInt(8)); // this gets 255
System.out.println("String: "+m.getString(12)); // this gets "Badge[5EE1]" as supposed

但是
read()
仍然崩溃。有什么想法吗?

我推断CBadgeData**输入是一个指向CBadgeData的指针数组

因此,Structure.ByReference标记是正确的

Structure.toArray()
在这里可能不合适,或者至少不必要(它在内存中分配一个连续的结构块)。您可以使用CBadgeData.ByReference实例填充数组

也许您的被调用者希望数组末尾有一个空指针?我没有看到被调用方的数组长度的另一个指示符

CBadgeData.ByReference[] badges = new CBadgeData.ByReference[max_items+1];
for (int i=0;i < badges.length-1;i++) {
    badges[i] = new CBadgeData.ByReference();
}
badges[badges.length-1] = null;
CBadgeData.ByReference[]徽章=新的CBadgeData.ByReference[max_items+1];
对于(int i=0;i
我很确定这是可行的。无论出于何种原因,如果有一个bug处理
结构。通过引用[]
,我知道
指针[]
是可靠的,并且会做同样的事情

编辑

如果使用
指针[]
而不是
结构。ByReference[]
(如果
结构不起作用,请在项目站点上发布一个bug。ByReference[]
不起作用),则必须在本机函数调用之前/之后手动调用
结构。写入/读取
,因为JNA不知道指针引用需要与本机内存同步的结构。但是,我敢打赌,使用
Structure.ByReference[]
时崩溃的原因很简单,JNA在调用后自动调用
Structure.read()
,并触发了与显式调用时相同的错误


如果读取时出现segfault,则可能意味着结构字段未正确对齐或定义,或者(不太可能)存在无法正确读取的损坏数据。要诊断此问题,请设置
jna.dump\u memory=true
,并在调用
Structure.write()
后打印出结构,以查看结构的内容是否如预期的那样显示。如果可能的话,在这里发布您的结构的本机和JNA表单也会有所帮助。

我推断CBadgeData**输入是指向CBadgeData的指针数组

因此,Structure.ByReference标记是正确的

Structure.toArray()
在这里可能不合适,或者至少不必要(它在内存中分配一个连续的结构块)。您可以使用CBadgeData.ByReference实例填充数组

也许您的被调用者希望数组末尾有一个空指针?我没有看到被调用方的数组长度的另一个指示符

CBadgeData.ByReference[] badges = new CBadgeData.ByReference[max_items+1];
for (int i=0;i < badges.length-1;i++) {
    badges[i] = new CBadgeData.ByReference();
}
badges[badges.length-1] = null;
CBadgeData.ByReference[]徽章=新的CBadgeData.ByReference[max_items+1];
对于(int i=0;i
我很确定这是可行的。无论出于何种原因,如果有一个bug处理
结构。通过引用[]
,我知道
指针[]
是可靠的,并且会做同样的事情

编辑

如果使用
指针[]
而不是
结构。ByReference[]
(如果
结构不起作用,请在项目站点上发布一个bug。ByReference[]
不起作用),则必须在本机函数调用之前/之后手动调用
结构。写入/读取
,因为JNA不知道指针引用需要与本机内存同步的结构。但是,我敢打赌,使用
Structure.ByReference[]
时崩溃的原因很简单,JNA在调用后自动调用
Structure.read()
,并触发了与显式调用时相同的错误


如果读取时出现segfault,则可能意味着结构字段未正确对齐或定义,或者(不太可能)存在无法正确读取的损坏数据。要诊断此问题,请设置
jna.dump\u memory=true
,并在调用
Structure.write()
后打印出结构,以查看结构的内容是否如预期的那样显示。如果可能的话,在这里发布您的结构的本机和JNA表单也会有所帮助。

谢谢!请看我的“答案”,它符合你的建议。为什么我不能用完整的细节来“回答”你的回答,但只能用评论来回答?一般来说,在你的原始问题上添加一个附录是最有意义的,并清楚地标记为这样。这样做了吗?请参见编辑-2-谢谢!请看我的“答案”,它符合你的建议。为什么我不能用完整的细节来“回答”你的回答,但只能用评论?一般来说,在你的原始问题上添加一个附录,并清楚地标记出来是最有意义的。这样做了吗?请参见编辑-2-内存转储按可寻址顺序打印字节。关于英特尔(little-e)