1

我知道这里的一些帖子涵盖了这个问题的一部分,我查看了它们并测试了一些但没有运气。我有这个本机方法签名,它应该用结果填充提供的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);

它因分段错误而失败。

我的问题是这里应该提供什么 Java 类型作为调用中的 native 的CBadgeData**参数elc_GetBadges

编辑-1-

自己填充数组(有或没有终止空指针)不起作用并导致进一步的 Seg 崩溃。然后我使用 Pointer[] 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);

这没有导致错误,但似乎没有对返回的结构进行任何更改,在这种情况下应该包含 4 个项目:

int bid = new CBadgeData(pointers[i]).nBadgeID; // this returns null for all items

在结构上使用显式 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()仍然崩溃。有什么想法吗?

4

1 回答 1

1

我推断 CBadgeData** 输入旨在成为指向 CBadgeData 的指针数组。

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

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

也许您的被调用者期望在数组末尾有一个 NULL 指针?我没有看到被调用者的数组长度的另一个指标。

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;

很确定这行得通。如果出于某种原因存在错误处理Structure.ByReference[],我知道这Pointer[]是可靠的并且会做同样的事情。

编辑

如果您使用Pointer[]而不是(如果不起作用,Structure.ByReference[]请在项目站点发布错误),您将不得不在您的本机函数调用之前/之后手动调用,因为 JNA 不会知道需要同步的指针引用结构本机内存。但是,我敢打赌,使用时崩溃的原因仅仅是 JNA 在调用后自动调用并触发了与您在显式调用时看到的相同的错误。Structure.ByReference[]Structure.write/readStructure.ByReference[]Structure.read()

如果您在读取时遇到段错误,则可能意味着您的结构字段未正确对齐或定义,或者(不太可能)您有无法正确读取的损坏数据。要诊断这一点,jna.dump_memory=true请在调用后设置并打印出您的结构,Structure.write()以查看结构的内容是否如您预期的那样显示。如果可能的话,在此处发布您的结构的本地和 JNA 形式也将有所帮助。

于 2013-01-17T00:02:41.023 回答