2016-08-04 6 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; 

Как я могу назвать эту родную функцию из Java с помощью JNA. Я попробовал несколько вариантов, но я не получаю результатов. один из вариантов, которые я пробовал, приведен ниже.

функция

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' для этих полей, а затем использовать различные' Pointer', чтобы извлекать и форматировать данные так, как вы хотите. Когда вы понимаете уровни разыменования, вы можете найти наиболее разумный способ его отображения. У вас есть фундаментальная проблема, хотя в том, что ваше поле - 'struct **', которое JNA не будет распознавать, поэтому все вызовы 'Structure.read/write' полностью зависит от вас. – technomage

+0

@technomage лучше использовать 'Pointer.getPointer (0)' или 'PointerByReference.getValue()'? –

+1

Вы должны использовать «PointerByReference», если вы передаете адрес указателя в качестве параметра. Если вы только что получили 'void **' как поле где-то, используйте 'Pointer'. – technomage

ответ

0

Вы на правильном пути.

Вам необходимо объявить внутреннюю структуру (LStrVal) как свой собственный класс структуры. Похоже, что вы сделали это с вашей Stringtype структуры, но вы должны изменить некоторые вещи там:

  • Избавиться от конструкторы с Int арг. Ваша структура C определяет размер массива byte[] как 1, просто используйте эту константу.
  • Вам нужен конструктор без аргументов, который вызывает super()
  • Вам нужен конструктор с Pointer агдом р, который вызывает super(p)
  • не нужен интересующие вас ByReference ЧАСТЕЙ

Тогда внешняя структура, которую вы должен использовать тип PointerByReference для этих указателей структуры, а затем в вашем основном коде используйте new Stringtype(pbr.getValue()), чтобы преобразовать указатель в необходимый класс.

В качестве альтернативы, как предлагает @technomage, вы можете использовать тип указателя, а затем вместо getValue() вы должны использовать getPointer(0). Итог - вам нужно указать указатель (на указатель) в качестве переменной экземпляра.

+0

'LStr' имеет тип' struct ** ', который делает _not_ map на' Structure.ByReference' (это будет 'struct *', в контексте поля struct). – technomage

+0

Просто перечитайте и заметите это и отредактируйте мой ответ соответствующим образом. –

1

При определения вашего LStrVal, вам необходимо инициализировать примитивное поле массива, так что ЮНА знает, сколько памяти выделить (по крайней мере для начала):

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

 Смежные вопросы

  • Нет связанных вопросов^_^