Search code examples
javacpointersstructjna

JNA multiple void pointers inside a C struct by reference


In my current project I have to implement the function of native c libs in a java project. I'm using JNA. And reached some good results so far. Now I'm stuck on the following problem.

I have to call the native c function:

int retrieveResult(ResultStruct * pResult)

Where the Struct is defined like followed:

typedef struct tag_ResultStruct
{
const void *pBuffer;
int sizeX;
int sizeY;
} ResultStruct;

In Java I created a class representing the struct:

public class ResultStruct extends Structure{
   public Pointer pBuffer;
   public int sizeX;
   public int sizeY;

   @Override
   protected List<String> getFieldOrder(){
      return Arrays.asList(new String[] {"pBuffer", "sizeX", "sizeY"});
   }

   public ResultStruct(){

   }
}

I'm calling the Native C Method with

private interface MyCLib extends Library{
   MyCLib INSTANCE = Native.load("myclib", MyCLib.class);
   int retrieveResult(ResultStruct pResult);
}
ResultStruct resultStruct = new ResultStruct();
resultStruct.pBuffer = new Memory(bufferLen);
int res = MyCLib.INSTANCE.retrieveResult(resultStruct);

Now I'm able to retrieve the expected values from sizeX, sizeY and pBuffer with

resultStruct.pBuffer.getByteArray(0, bufferLen);

Now I' extending my struct like the following:

typedef struct tag_ResultStruct
{
const void* pContext;
const void *pBuffer;
int sizeX;
int sizeY;
} ResultStruct;

And my Java Structure:

public class ResultStruct extends Structure{
   public Pointer pContext;
   public Pointer pBuffer;
   public int sizeX;
   public int sizeY;

   @Override
   protected List<String> getFieldOrder(){
      return Arrays.asList(new String[] {"pContext", "pBuffer", "sizeX", "sizeY"});
   }

   public ResultStruct(){

   }
}

Problem is, i don't want to make use of pContext. So I don't know which size it should have and therefore i don't initialize the pointer. Now when i try to retrieve the values from the buffer by calling:

resultStruct.pBuffer.getByteArray(0, bufferLen);

I don't get the expected values from buffer.

Question

How to deal with more than dynamic memory field inside a Structure passed by reference when using JNA? It is possible to leave Pointer uninitialized inside the Structure?

I Appreciate any help. Thank you in advance.


Solution

  • Thanks to all, who replied to my question. You set me on the right track.

    Answer

    Here is the answer to my question. Maybe it may help someone other encountering the same or a similar problem.

    Problem

    In the library which I use (Pylon C API from Basler) it is mentioned that you have to register one or more output buffers. It is done by allocating the buffer and register the pointer of that array.

    Usually I map a byte array (byte[] buffer = new byte[size]) to a uchar* or void* buffer. This works, when the buffer is filled directly in you c function (like in the sample that Oo.oO gave me).

    But in the context of the API that I'm using, the pointer gets filled a bit later after it was registeres (it gets filled, when image data is available). I'm not an expert, but I think the java byte array, doesn't work like a real pointer.

    Solution

    I changed the buffer allocation in Java to

    Pointer pBuffer = new Memory(size)
    

    and mapped this Pointer to the void* buffer pointer, when registering it. Now the buffer Pointer works as expected and I can retrieve the content of the buffer later by using

    byte[] data = pBuffer.getByteArray(0, size)
    

    This also works, when the pointer returned by the function retrieveResult(...) is inside a struct.