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);

セグメンテーション エラーで失敗します。

CBadgeData**私の質問は、 への呼び出しでネイティブの引数として、ここでどの Java タイプを提供する必要があるelc_GetBadgesかです。

編集 -1-

自分で配列を作成しても (null ポインターを終了してもしなくても) 機能せず、さらに Seg がクラッシュしました。次に、technomage が提案したように 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()

読み取り時に segfault が発生した場合は、構造体フィールドが適切に配置または定義されていないか、(可能性は低いですが) 適切に読み取ることができない破損したデータがあることを意味します。これを診断するにはjna.dump_memory=true、呼び出し後に構造体を設定して出力し、構造体Structure.write()の内容が期待どおりに表示されるかどうかを確認します。可能であれば、構造のネイティブ形式と JNA 形式をここに投稿することも役立ちます。

于 2013-01-17T00:02:41.023 に答える