2016-06-27 237 views
1

Javaからいくつかのdll関数にアクセスするためにJNA 4.0.0を使用していますが、このdllネイティブ関数は次のように宣言されています。スレッド "main"のJNA例外java.lang.Error:無効なメモリアクセス(不明なソース)

int ApplicationInit(HANDLE hEMV, TLV *tlv_Appl, TLV *tlv_AIP); 

入力はタイプが

/* Opaque structure */ 
typedef void *HANDLE; 

typedef struct 
{ 
    unsigned char *_lenptr;  /* pointer to 'len' field (Private member) */ 
    unsigned int _len;   /* 'outer' length, specified by user (Private member) */ 
    unsigned short _offset; 
    unsigned short len;   /* number of bytes (Public member) */ 

    unsigned long tag;   /* Tag tag (Public member) */ 
    unsigned char *val;   /* byte string (Public member) */ 
    unsigned char _tagptr[256]; /* Container for TLV data (Private member) */ 
} TLV; 

ので、以下に記載されるパラメータ、私は、次のようにライブラリインタフェース内側に宣言:

public static class HANDLE extends PointerType { 
     public HANDLE(Pointer address) { 
      super(address); 
     } 
     public EMV_HANDLE() { 
      super(); 
     } 
    } 

public class TLV extends Structure { 
    /** 
    * pointer to 'len' field (Private member)<br> 
    * C type : unsigned char* 
    */ 
    public Pointer _lenptr; 
    /** 'outer' length, specified by user (Private member) */ 
    public int _len; 
    public short _offset; 
    /** number of bytes (Public member) */ 
    public short len; 
    /** Tag tag (Public member) */ 
    public NativeLong tag; 
    /** 
    * byte string (Public member)<br> 
    * C type : unsigned char* 
    */ 
    public Pointer val; 
    /** 
    * Container for TLV data (Private member)<br> 
    * C type : unsigned char[256] 
    */ 
    public byte[] _tagptr = new byte[256]; 
    public TLV() { 
     super(); 
    } 
    protected List<? > getFieldOrder() { 
     return Arrays.asList("_lenptr", "_len", "_offset", "len", "tag", "val", "_tagptr"); 
    } 
    /** 
    * @param _lenptr pointer to 'len' field (Private member)<br> 
    * C type : unsigned char*<br> 
    * @param _len 'outer' length, specified by user (Private member)<br> 
    * @param len number of bytes (Public member)<br> 
    * @param tag Tag tag (Public member)<br> 
    * @param val byte string (Public member)<br> 
    * C type : unsigned char*<br> 
    * @param _tagptr Container for TLV data (Private member)<br> 
    * C type : unsigned char[256] 
    */ 
    public TLV(Pointer _lenptr, int _len, short _offset, short len, NativeLong tag, Pointer val, byte _tagptr[]) { 
     super(); 
     this._lenptr = _lenptr; 
     this._len = _len; 
     this._offset = _offset; 
     this.len = len; 
     this.tag = tag; 
     this.val = val; 
     if ((_tagptr.length != this._tagptr.length)) 
      throw new IllegalArgumentException("Wrong array size !"); 
     this._tagptr = _tagptr; 
    } 
    public static class ByReference extends TLV implements Structure.ByReference { 

    }; 
    public static class ByValue extends TLV implements Structure.ByValue { 

    }; 
} 

int EMV_ApplicationInit(AppdefLibrary_EMVCT.EMV_HANDLE hEMV, TLV.ByReference tlv_Appl, TLV.ByReference tlv_AIP); 

その後、私は次のように呼び出す:

EMV_HANDLE hEMV= new EMV_HANDLE(); 
TLV.ByReference tlv_Appl=new TLV.ByReference(); 
TLV.ByReference tlv_AIP=new TLV.ByReference(); 

System.out.println(AppdefLibrary.INSTANCE.ApplicationInit(hEMV, tlv_Appl, tlv_AIP)); 

が、私は次の例外を取得しています:

Exception in thread "main" java.lang.Error: Invalid memory access 
    at com.sun.jna.Native.invokeInt(Native Method) 
    at com.sun.jna.Function.invoke(Function.java:383) 
    at com.sun.jna.Function.invoke(Function.java:315) 
    at com.sun.jna.Library$Handler.invoke(Library.java:212) 
    at com.sun.proxy.$Proxy1.ApplicationInit(Unknown Source) 
    at test.Test.main(Test.java:192) 

助け、あなたの注意をお願い致します!

答えて

2

正しく割り当てられていないネイティブサイドメモリにアクセスしようとすると、無効なメモリアクセスエラーが発生します。

実際にどのようにメモリが割り当てられるかは、いくつかの方法で発生する可能性があります。問題を理解するためにそれらを狩る必要があります。実際の問題になるためには、タマネギのいくつかのレイヤーをはがす必要があります。

最初に確認するのは、JNAタイプのマッピングです。構造サイズはここではうってつけである。ただし、構造が正しいように見えます。

次に、構造自体にネイティブサイドメモリを割り当てていない可能性があります。これはByReferenceを使用して構造を処理するための選択の副作用です。あなたがこのルートに行くなら、あなたはもっと多くのオーバーヘッドを持っています。しかし、これはすべて不要です。 JNAライブラリの引数としてStructureを渡すと、実際にはネイティブ側へのポインタだけが送信されますが、メモリ割り当てなどを処理します。

TLV構造をコード内で直接参照するだけです。ライブラリで

:あなたのアクセスコードで

int EMV_ApplicationInit(AppdefLibrary_EMVCT.EMV_HANDLE hEMV, TLV tlv_Appl, TLV tlv_AIP); 

TLV tlv_Appl=new TLV(); 
TLV tlv_AIP=new TLV(); 

System.out.println(AppdefLibrary.INSTANCE.ApplicationInit(hEMV, tlv_Appl, tlv_AIP)); 

問題が解決されない固定の場合、別の可能性はあなたが割り当てられたメモリを持っている間ということですあなたのJava構造体では、Cのメソッドは内部的に他のメモリを参照し、APIはあなたが何らかの方法で変数を初期化して他の場所のメモリを指す(割り当てられた)ことを期待しています。初期化されていないポインタは、特に、関数がポピュレートするコールバックではなく、ユーザーからの「入力」として意図されている場合に起こりうる原因です。 APIドキュメントを慎重に見直して、これが当てはまるかどうか、ポインタのいずれかを初期化する必要があるかどうかを確認する必要があります。

たとえば、null HANDLEは、このメソッドでは受け入れられない場合があります。他の方法でHANDLEを初期化する必要があります(後でリリースします)。

または、内部ポインタメンバーを初期化するためにTLV構造に何かをする必要があるかもしれません。たとえば、valフィールドは、「バイト文字列」を指します。 APIは既に割り当て済みで、割り振ったメモリの長さを指定していますか(例:Pointer val = new Memory(256); tlv_Appl.val = val; tlv_Appl.len = 256;)? _lenptrは何を指していますか(コメントはintフィールドを示しますが、それは奇数と思われるcharポインタです)。

また、別として、4.0.0はJNAのかなり古いバージョンです。 4.2.2は現在のバージョンであり、何らかの理由で古いバージョンが必要な場合を除いて使用してください。

また、別の方法として、JNAにはすでにWinNT.HANDLEのマッピングが含まれています。

+0

こんにちは@Daniel Widdis、 ありがとうございました。 私はあなたの指示に従った。まず、jna-4.2.2.jarとjna-platform-4.2.2.jarに切り替えました。次に、私はTLV構造体を直接WinNT.HANDLEクラスを参照して呼び出すことを試みました。 'WinNT.HANDLE myHandle = new WinNT.HANDLE(); TLV tlv_Appl = new TLV(); TLV tlv_AIP =新しいTLV(); のSystem.out.println(AppdefLibrary.INSTANCE.ApplicationInit(myHandle、tlv_Appl、tlv_AIP));あなたはまだしている場合、 '' しかし、私はあなたのメソッドのシグネチャ@Bace同じ例外 – Bace

+0

を取得していますが、今正しいですが、エラーが発生すると、APIが提供していない値をAPIが期待していることを意味します。これは、通常、APIによって指定されます。 'ApplicationInit()' APIドキュメントは、構造体のメンバをすべて初期化するよう指定していますか?一般的な問題は、HANDLEが他のメソッドを使用して初期化されることが期待されるか、TLV構造体のメンバーを事前に設定することが想定されることがあります。 –

+0

こんにちは@Daniel Widdis、もう一度ありがとうございます。ハンドルは他の方法で初期化されると思われます。私は今試している、私はすべての場合にあなたに戻ってきます。 – Bace

関連する問題