简体   繁体   中英

How to pass a struct containing char* in java using JNA and avoiding the data copy?

I am writing a java application that will access to C++ dll usnig JNA. So I prepared a C dll to communicate between the JNA and C++ thrid party dll. I have these two structs:

C code:

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

Now I am writing the corresponding JNA code in java application and I want to access the "unsigned char* Data" without copying this data as it is a large amount of Data. How can I use the "Memory" or the "Pointer" JNA types to do this task?

Here is my attempt:

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

Any advice would be very appreciated.

Here is my Solutiuon, first Draft:

  1. Declare a Class in java that extends Structure

    (com.sun.jna.Structure)

    (all fields in the class must be public or you get an error, that the size of the structure extended class can't be measured)

     public class Struct1 extends Structure{ public int Size; public String Data; } 
  2. Declare and define a method in the C Dll, that takes a pointer to the structure as an argument (I created a structure and filled it with values for testing)

     void __declspec(dllexport) GetStruct(Struct1* a){ Struct1 s; s.Size = 9; s.Data = "Output"; *a = s; } 
  3. I assume that you already successfully connected the java app to the c dll, so i skip that part(if my assumption is wrong, tell me in the comments and i edit my answer)

  4. If you add these lines to your java code (note cdll is the handle to my C library)

     Struct1 test = new Struct1(); cdll.GetStruct(test); System.out.println("Struct1: " + test.Size + " " + test.Data); 

You should get the data from the Structure s in the C Dll.

If the Data field points to arbitrary data, use a Pointer . If the native side allocates, then you do nothing. If the Java side allocates, use a Memory object assigned to that field.

As for the struct* and struct** , it'd be useful to see some native code using those constructs in order to tell what they represent, since there is some ambiguity ( struct* could be a pointer to a single struct, or a pointer to a contiguous array of them). struct** could be storage allocated for the return of a struct* , or it may be something else.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM