2016-06-27 473 views
1

我使用JNA 4.0.0访问从Java某些DLL函数,这个DLL的固有函数声明为以下几点: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作为参数传递给JNA库时,它确实只发送指向本地的指针......但是处理内存分配等。

您应该只需在您的代码中直接引用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文档以查看是否属于这种情况,以及是否需要初始化任何指针。

例如,一个空HANDLE可能是不能接受的方法;它可能需要您通过其他方法初始化HANDLE(并稍后发布它)。

或者,你可能需要做一些事情的TLV结构,其内部指针成员初始化。例如,val字段指向“字节字符串”。 API是否希望您已经分配了该内存,并提供了您分配的内存的长度(例如,Pointer val = new Memory(256); tlv_Appl.val = val; tlv_Appl.len = 256;)? _lenptr指的是什么(注释表示一个int字段,但它是一个字符指针,这看起来很奇怪)?另外,4.0.0是JNA的老版本, 4.2.2是当前的版本,您应该使用它,除非您因某些其他原因需要较旧的版本。

另外,作为另一方,JNA已经包含了一个映射WinNT.HANDLE,这可能比您自己的更好。

+0

你好@Daniel Widdis, 谢谢你的关注。 我按照你的指示。首先我切换到jna-4.2.2.jar和jna-platform-4.2.2.jar。其次,我尝试通过直接使用WinNT.HANDLE类来引用TLV结构,如下所示: 'WinNT.HANDLE myHandle = new WinNT.HANDLE(); TLV tlv_Appl = new TLV(); TLV tlv_AIP = new TLV(); 的System.out.println(AppdefLibrary.INSTANCE.ApplicationInit(myHandle,tlv_Appl,tlv_AIP));'' 但我得到相同的异常 – Bace

+0

@Bace你的方法签名都正确,但如果你仍然获取错误意味着API正在期待你没有给出的值。这通常由API指定。 ApplicationInit()API文档是否指定你初始化结构的任何成员?常见的问题可能是HANDLE预期会使用其他方法初始化,或者您应该预先填充TLV结构的成员。 –

+0

你好@Daniel Widdis,再次感谢你。在我看来,HANDLE预计会使用其他方法初始化。我现在正在测试,在任何情况下我都会回复你。 – Bace

相关问题