2013-07-09 213 views
0

我想在C DLL中调用一个函数,该函数需要一个指向结构体的指针。这个结构(Data)的定义是这样的:如何使用指向Java指针的指针填充结构?

struct BD 
{ 
    char* Data; 
    int Length; 
}; 

struct EE 
{ 
    char* Key; 
    BD* Value; 
}; 

struct Data 
{ 
    char* Name; 
    BD* Picture; 

    // A NULL-terminated array of pointers to EE structures. 
    EE** Elements; 
}; 

在Java中我已经定义了一些类,像这样:

public static class BD extends Structure implements Structure.ByReference { 
    public byte[] Data; 
    public int Length; 
} 

public static class EE extends Structure implements Structure.ByReference { 
    public String Key; 
    public BD Value; 
} 

public static class Data extends Structure { 
    public String Name; 
    public BD Picture; 
    public PointerByReference Elements; 
} 

但现在我不知道究竟如何填充Data对象正确。我想我可以计算出NamePicture字段,但是我怎样将Elements字段设置为?我可以创建一个EE对象的Java数组,但是如何从中获取PointerByReference?也许我需要将Elements声明为Pointer[],但是接下来我只需要为每个EE对象填充数组的每个元素,即getPointer()对象?虽然这看起来不太合适?

编辑:给的什么,我试图做一个更好的主意:

Data data = new Data(); 
// Fill in Name and Picture fields. 

EE[] elements = new Elements[10]; 
// Fill in the elements array. 

// Now how do I set the Elements field on the data object from the elements array? 
data.Elements = ??? 

EDIT2:这是我如何与technomage的帮助下解决了这个问题:

我改变了我的Data结构看起来像这样:

public static class Data extends Structure { 
    public String Name; 
    public BD Picture; 
    public Pointer Elements; 
} 

而我的BD结构是这样的:

public static class BD extends Structure implements Structure.ByReference { 
    public Pointer Data; 
    public int Length; 
} 

将Java byte[]转换为JNA Pointer我不得不使用ByteBuffer

ByteBuffer buf = ByteBuffer.allocateDirect(bytes.length); 
buf.put(bytes); 
bd.Data = Natvie.getDirectBufferPointer(buf); 

JNA不以struture喜欢ByteBuffer小号不幸。

为了让我的元素的指针,我需要创建的Pointer s到每个EE对象的数组(参见technomage的答案PointerArray实现):

EE e = new EE(); 
// Populate e object. 
// ... 

// Important: ensure that the contents of the objects are written out to native memory since JNA can't do this automatically 
e.write(); 
ptrs.add(e); 

// Once each object is setup we can simply take the array of pointers and use the PointerArray 
data.Elements = new PointerArray(ptrs.toArray(new Pointer[0])); 

我不能使用ByteBufferPointerArray直接在结构定义,所以我不得不依靠Pointer

+0

当您另外传递指针变量的地址时,将使用'PointerByReference',以便为被调用者提供空间以“返回”一个值。 – technomage

+0

如果您的本地'struct'使用'char []'作为相应的字段类型,则只能使用'byte []'作为'Structure'字段。 – technomage

回答

1

制作Elements a Pointer,然后使用Pointer.getPointerArray(0)来检索感兴趣的结构指针。

然后,您需要初始化每个Structure从每个检索的Pointer(不要忘记拨打Structure.read())。

没有办法在指针上自动执行间接寻址,并且结束了一个Structure的数组,但它很容易编码到Structure类中的方法(例如Data.getElements())。

编辑

采样指针数组实现,初始化上写的指针数组(而不是读):

class PointerArray extends Memory {      
     private final Pointer[] original;               
     public PointerArray(Pointer[] arg) {               
      super(Pointer.SIZE * (arg.length+1));             
      this.original = arg;                  
      for (int i=0;i < arg.length;i++) {              
       setPointer(i*Pointer.SIZE, arg[i]);             
      }                      
      setPointer(Pointer.SIZE*arg.length, null);            
     }                       
    } 
} 

您还需要调用本地函数(之前调用Structure.write()你可以这样做,作为PointerArray的一部分),因为当你使用香草Pointer而不是Structure时,JNA不知道内存需要同步。

+0

我需要在Java中填充'Data'对象并将其传递给本机函数。所以我想我需要将'EE []'转换为'Pointer'? – JasonA

+0

请参阅答案编辑中的示例指针数组实现。 – technomage

+0

好吧,看起来很像我需要的东西。但是,我尝试了它,但它仍然无法正常工作。当我用调试器进入本地函数时,data-> Elements有一个值,但data-> Elements [0]为空。也许我还在做错了什么?我现在将元素字段定义为指针,并将'data.Elements'设置为'new PointerArray(arrayOfPointers)'。 – JasonA