如何使用JNA在java中传递包含char *的结构并避免数据复制?

时间:2017-02-08 20:21:32

标签: java c++ c struct jna

我正在编写一个可以访问C ++ dll usnig JNA的java应用程序。所以我准备了一个C dll来在JNA和C ++第三方dll之间进行通信。我有这两个结构:

C代码:

    struct Struct1
    {
    uint32_t Size;
    unsigned char* Data;
    };
    struct Struct2
    {
    uint32_t Struct1_Nbr;
    Struct1* struct1_elements;
    };
    bool Open(char* fileName, Struct2** struct2);

现在我在java应用程序中编写相应的JNA代码,我想访问" unsigned char * Data"没有复制这些数据,因为它是大量的数据。 我怎样才能使用" Memory"或者指针"指针" JNA类型要执行此任务吗?

这是我的尝试:

    public class Test
    {
    public static class Struct1 extends com.sun.jna.Structure {        
    public Struct1(){}
    public Struct1(Pointer pointer){
        super(pointer);
        read();
    }

    public static class Struct1ByValue extends Struct1 implements com.sun.jna.Structure.ByValue{};
    public int Size;
    public Memory Data;
    public static class Struct1ByReference extends Struct1 implements com.sun.jna.Structure.ByReference{}

    @Override
    protected List getFieldOrder() {
        // TODO Auto-generated method stub
        return Arrays.asList("Size", "Data");
    };

public static class Struct2 extends com.sun.jna.Structure {    
    public Struct2 (){}
    public Struct2 (Pointer pointer){
        super(pointer);
        read();
    }
    public int Struct2_Nbr;
    public Struct1.Struct1ByReference struct1_elements = new Struct1.Struct1ByReference();

    public static class Struct2ByValue extends Struct2 implements com.sun.jna.Structure.ByValue{};
    public static class Struct2ByReference extends Struct2  implements com.sun.jna.Structure.ByReference{}

    @Override
    protected List getFieldOrder() {
        // TODO Auto-generated method stub
        return Arrays.asList("Struct1_Nbr", "struct1_elements"));
    };
}
    public interface StructureProtocol extends com.sun.jna.Library{
    Boolean Open(String fileName, PointerByReference struct2);
    }
    public StructureProtocol lib;
    public Test(){
    this.lib = (StructureProtocol) Native.loadLibrary("TestAPI", StructureProtocol.class);
}

    public static void main(String[] args) {

            Test test = new Test();
    PointerByReference pref = new PointerByReference();

    test.lib.Open("filePath", pref);
    Pointer ptr = pref.getValue();
    Struct2 struct2= new Struct2(ptr);
    Struct1[] struct1_array= (Struct1[])(struct2.struct1_elements).toArray(struct2.struct1_Nbr);
    System.out.println("struct1_array[0]: Size = " + struct1_array[0].Size);
    System.out.println("struct1_array[0]: Data= " + struct1_array[0].Data);
    }
    }

非常感谢任何建议。

2 个答案:

答案 0 :(得分:0)

这是我的Solutiuon,第一稿:

  1. 在java中声明一个扩展Structure

    的类
      

    (适用com.sun.jna.Structure)

    (类中的所有字段必须是公共的,否则会出现错误,无法测量结构扩展类的大小)

    public class Struct1 extends Structure{
        public int Size;
        public String Data;  
    }
    
  2. 在C Dll中声明并定义一个方法,它将一个指向结构的指针作为参数(我创建了一个结构并用测试值填充它)

    void __declspec(dllexport) GetStruct(Struct1* a){
    Struct1 s;
    s.Size = 9;
    s.Data = "Output";
    *a = s;
    }
    
  3. 我假设您已经成功将java应用程序连接到c dll,所以我跳过那部分(如果我的假设是错误的,请在评论中告诉我并编辑我的答案)

  4. 如果你将这些行添加到你的java代码中(注意cdll是我的C库的句柄)

    Struct1 test = new Struct1();
    cdll.GetStruct(test);
    System.out.println("Struct1: " + test.Size + " " + test.Data);
    
  5. 您应该从C Dll中的Structure s获取数据。

答案 1 :(得分:0)

如果数据字段指向任意数据,请使用Pointer。如果原生方分配,那么你什么都不做。如果Java端分配,请使用分配给该字段的Memory对象。

对于struct*struct**,看一些使用这些构造的本机代码以告诉它们代表什么是有用的,因为存在一些歧义(struct*可以是指向单个结构的指针,也可以是指向它们的连续数组的指针。 struct**可以是为struct*的返回分配的存储空间,也可能是其他内容。