2016-08-04 61 views
0

我對JNA編程頗爲陌生。我有一個本地代碼,如下所示JNA結構裏面的結構

int Data(int Number, aaa *Data, int* error); 

typedef struct { 
    uint8 Storage; 
    LStr path; 
    int32 chart; 
    int32 strt; 
    LStr val; 
    int32 timedata; 
    } aaa; 

typedef struct { 
    int32 cnt; /*num of bytes that follow*/  
    uChar str[1]; 
} LStrval, *LStrPtr, **LStr; 

如何使用JNA從Java調用此本機函數。我嘗試了幾個選項,但我沒有得到結果。下面是我嘗試的選項之一。

接口功能

public int SetStorage_Data(int num,Storage_Data.ByReference data, Pointer error); 

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

     public byte storage; 
     public Stringtype.ByReference savepath; 
     public int chart; 
     public int strt; 
     public Stringtype.ByReference val; 
     public int timedata; 

     @Override 
     protected List getFieldOrder() { 
      return Arrays.asList("storage", "savepath","chart", 
        "strt","val","timedata"); 
     } 
    } 



public class Stringtype extends Structure{ 
     public static class ByReference extends Stringtype implements Structure.ByReference { 

      public ByReference(int buffersize) { 
       super(buffersize); 
       // TODO Auto-generated constructor stub 
      }} 

     public int count; 
     public byte[] str; 

     public Stringtype(int buffersize) { 
      str = new byte[buffersize]; 
      count = str.length; 
      allocateMemory(); 
     } 

     @Override 
     protected List getFieldOrder() { 
      return Arrays.asList("count", "str"); 
     } 
    } 

和Java調用

InjectionAnalyzerInterfaces.Storage_Data.ByReference storagedata = new InjectionAnalyzerInterfaces.Storage_Data.ByReference(); 

int len= string.length; 
InjectionAnalyzerInterfaces.Stringtype.ByReference savepath = new InjectionAnalyzerInterfaces.Stringtype.ByReference(len); 

      byte[] stringbyte = string.getBytes(); 
      System.arraycopy(stringbyte, 0, savepath.str, 0, bytes); 
      storagedata.savepath = savepath; 
      storagedata.chart = 1; 
      storagedata.strt =1; 
      String temp= "all"; 
      byte[] strtbyte = temp.getBytes(); 
      int dd = strtbyte.length; 
      InjectionAnalyzerInterfaces.Stringtype.ByReference stra = new InjectionAnalyzerInterfaces.Stringtype.ByReference(dd); 
      System.arraycopy(strtbyte, 0, stra.str,0, dd); 
      storagedata.strt = stra; 


      storagedata.tdata = 0; 

      Pointer error = new Memory(5); 

      int status1 = lib.Set_Config_Storage_Data(deviceNumber, storagedata, error); 

請你幫幫我。預先感謝您

+0

我建議你開始使用'Pointer'這些字段,然後使用各種'指針「訪問方法,以您想要的方式提取和格式化數據。一旦你理解了解引用的級別,你可以找出映射它的最明智的方法。然而,你有一個根本性的問題,因爲你的領域是'struct **',JNA不會識別,所以所有對'Structure。的調用。讀/寫「完全取決於您執行。 – technomage

+0

@technomage是使用'Pointer.getPointer(0)'還是'PointerByReference.getValue()'更好? –

+1

如果您將指針的地址作爲參數傳遞給某個參數,則只應使用'PointerByReference'。如果你在某處使用'void **'作爲字段,使用'Pointer'。 – technomage

回答

0

你在正確的軌道上。

您需要聲明內部結構(LStrVal)作爲其自己的結構類。它看起來像你這樣做,以你的Stringtype結構,但你需要改變一些東西有:

  • 擺脫與INT ARG構造的。您的C結構將byte[]數組的大小指定爲1,只需使用該常量即可。
  • 你需要一個無參數的構造函數調用super()
  • 你需要一個構造函數調用super(p)
  • 你不需要ByReference零件

然後外,你結構的指針ARG p應爲這些結構指針使用PointerByReference類型,然後在主代碼中使用new Stringtype(pbr.getValue())將指針轉換爲必需的類。

或者,如@technomage所示,您可以使用指針類型,然後使用getPointer(0)而不是getValue()。底線是你需要一個指針(指向一個指針)作爲你的實例變量。

+0

'LStr'的類型爲'struct **',它不會映射到'Structure.ByReference'上(它將在struct字段的上下文中成爲'struct *')。 – technomage

+0

剛剛重讀並注意到,並適當地編輯了我的答案。 –

1

在定義你LStrVal,你需要初始化基本類型數組字段,以便JNA知道多少內存分配(至少與啓動):

public byte str = new byte[1]; 

你需要重寫Structure.read()做正確的的事情,並提供基於Pointer從構造本機內存初始化後改爲:

public void read() { 
    count = (int)readField("count"); 
    str = new byte[count]; 
    super.read(); 
} 

public LStr(Pointer p) { 
    super(p); 
    read(); 
} 

最後,你含結構有struct**領域(不知道爲什麼),你就必須映射到Pointer,並提供了一個方便的功能真正轉化爲所需的結構:

public Pointer savepath; 
public LStr getSavepath() { 
    return savepath != null ? new LStr(savepath.getPointer(0)) : null; 
}