JNI mapping for "pointer to byte array"

1,052 views
Skip to first unread message

viv...@gmail.com

unread,
Jul 9, 2012, 9:24:42 PM7/9/12
to jniwrapp...@teamdev.com
Hi,

 As part of our jniwrapper evaluation I've to map the following native structure into java,

struct NativeString {
   uint32 length;
   uint8 *buffer;
}

where,  length - The total length in bytes of the string.
          - buffer - A pointer to the byte array holding the string.  Strings
            are not NULL-terminated.

I tried the generator, but it simply does 
   private Pointer buffer = new Pointer(uint8.class);

which, is not what I want. I tried,
     private UInt32 length = new UInt32();
     private PrimitiveArray byteArr = new PrimitiveArray(UInt8.class, (int)length.getValue());
     private Pointer buffer = new Pointer(byteArr); 

and in my toString(),
    
    public String toString() {
 byte[] byteBuffer = byteArr.getBytes();
 String retVal = new String(byteBuffer);
 return retVal;
     }

but, it's failing - not getting any result and jvm crashes when calling toString(). 

What would be the right mapping for the above C++ struct and how can implement toString() for it?

Thanks,
-vivek

        

Sergei Piletsky

unread,
Jul 11, 2012, 8:38:48 AM7/11/12
to viv...@gmail.com, jniwrapp...@teamdev.com
Hi vivek,

If that 'buffer' pointer should be filled by a native function, then wrapper should use the ExternalArrayPointer type instead of Pointer. So, one of the possible solutions in this case could be the following:

    public class NativeStringStructure extends Structure {

        private UInt32 length = new UInt32();
        private PrimitiveArray buffer = new PrimitiveArray(UInt8.class, 0); // use zero array length, because its size is unknown in advance
        private ExternalArrayPointer bufferPtr = new ExternalArrayPointer(buffer);

        public NativeStringStructure() {
           init(new Parameter[] {length, bufferPtr});
        }

        public String readBuffer() {
            if (bufferPtr.isNull()) {
                return null;
            } else {
                bufferPtr.readArray((int) length.getValue());
                return new String(buffer.getBytes());
            }
        }
    }

Please let me know if you have any further questions.

Sincerely,
Serge



        

--
You are receiving this email because you have joined the "JNIWrapper Forum" group or have been added by request. You may choose not to receive emails from this group or unsubscribe completely on "Edit my membership" page.
Go to http://links.teamdev.com/jniwrapper-forum, choose "Edit my membership" link on the right. Specify your email preferences in suggested options, or click "Unsubscribe" button.

viv...@gmail.com

unread,
Jul 11, 2012, 7:27:39 PM7/11/12
to jniwrapp...@teamdev.com, viv...@gmail.com
Thanks Serge. This seems to work fine. Related questions,

1) In the doc, it says to  use " ResizingPointer " if we want JNIWrapper to manage the memory. If the structure is being set by the native code, which one should I use  ExternalArrayPointer or  ResizingPointer? If using ExternalArrayPointer do I need to anything specific to clean up the object?

2) If in my structure I also have an array of some custom type, where the array size is not known - would it work the same way?

For ex., 

  struct CustString {
        uint16 length;
       NativeString strings[];
   }

Can I do?
 
 public class CustStringStruct
extends Structure
{
     private ComplexArray custArr = new ComplexArray(new NativeString(), 0);
private ExternalArrayPointer custArrPtr = new ExternalArrayPointer( custArr );

}
 
For some reason I'm getting mismatch for the structure. 

Thanks,
-vivek

Sergei Piletsky

unread,
Jul 12, 2012, 9:21:51 AM7/12/12
to viv...@gmail.com, jniwrapp...@teamdev.com
Hi vivek,

1) In this case it should be ExternalArrayPointer. When you use ExternalArrayPointer type you should bear in mind that JNIWrapper does not manage automatically its data, so you may need to call an appropriate native function (from a native library, or a function from Windows API) that releases externally allocated memory.

2) There are two use cases here. First when you allocate such structure on a Java side then pass it to a native function. And second, when you read such data type after a native function call. In second case you can use the same approach that uses ExternalArrayPointer type.

In order to fix that mismatch error you will need to add the clone() method to each structure type, for example:

public class NativeString extends Structure {
     ...
     public Objec clone() {
         NativeString clone = new NativeString();
         clone.initFrom(this);
         return clone;

     }
}

public class CustStringStruct extends Structure {
     private ComplexArray custArr = new ComplexArray(new NativeString(), 0);
     private ExternalArrayPointer custArrPtr = new ExternalArrayPointer(custArr);
     ...
     public Objec clone() {
         CustStringStruct clone = new CustStringStruct();
         clone.initFrom(this);
         return clone;
     }
   
}


Please try this solution and let me know the results.

Sincerely,
Serge

viv...@gmail.com

unread,
Jul 12, 2012, 11:11:22 PM7/12/12
to jniwrapp...@teamdev.com, viv...@gmail.com
Thanks Serge. Couple of related questions,

1) If the native function is simply copying data in the memory (basically, putting the clone of the structure in the buffer) then is ExternalArrayPointer still the right type for this? Also, there is no cleanup function on the native side as they are not holding up to any memory space after the return.

2) In case of " CustStringStruct  "  I want to get the ComplexArray so I can go over the elements in it,

public ComplexArray getElements(){
if ( bufferPtr .isNull()) {
return null;
} else {
bufferPtr .readArray((int) length.getValue());
return (ComplexArray) bufferPtr  .getReferencedObject();
}
}

but, this seem to failing - I'm getting stack dump pointing to this function,
 

Stack: [0x623e8000,0x62be9000],  sp=0x62be7730,  free space=8189k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [libjvm.so+0x5ed9c9]
j  sun.misc.Unsafe.getInt(J)I+0
j  java.nio.DirectByteBuffer.getInt(J)I+10
j  java.nio.DirectByteBuffer.getInt(I)I+11
j  com.jniwrapper.g.readPointer(I)J+20
j  com.jniwrapper.Pointer.readPointer(Lcom/jniwrapper/DataBuffer;I)V+2
j  com.jniwrapper.Pointer.read(Lcom/jniwrapper/DataBuffer;IZ)V+3
j  com.jniwrapper.ExternalArrayPointer.read(Lcom/jniwrapper/DataBuffer;IZ)V+9
j  com.jniwrapper.bg.doPointerIO(Lcom/jniwrapper/Pointer;Lcom/jniwrapper/DataBuffer;IZ)V+5
j  com.jniwrapper.Pointer.acceptIOPerformer(Lcom/jniwrapper/IOPerformer;Lcom/jniwrapper/DataBuffer;IZZ)V+6
j  com.jniwrapper.Structure.acceptIOPerformer(Lcom/jniwrapper/IOPerformer;Lcom/jniwrapper/DataBuffer;IZZ)V+54
j  com.jniwrapper.Structure.acceptIOPerformer(Lcom/jniwrapper/IOPerformer;Lcom/jniwrapper/DataBuffer;IZZ)V+54
j  com.jniwrapper.ComplexArray.acceptIOPerformer(Lcom/jniwrapper/IOPerformer;Lcom/jniwrapper/DataBuffer;IZZ)V+20
j  com.jniwrapper.Pointer.readReferencedObject(Z)V+21
j  com.jniwrapper.ExternalArrayPointer.readArray(I)V+61
j  com.xx.xx. getElements()Lcom/jniwrapper/ComplexArray;+24

How do I get the elements from the ComplexArray?

Thanks,
-vivek

Sergei Piletsky

unread,
Jul 13, 2012, 3:56:35 AM7/13/12
to viv...@gmail.com, jniwrapp...@teamdev.com
Hi,

1) It does not matter how a native function allocates the memory for a pointer, in any case if data size is not known for Java side beforehand, such parameter should be ExternalArrayPointer type. If there is no any cleanup function for deleting the memory buffer, then you may need to use a corresponding standard native function for freeing that memory.

For example, if a memory buffer is allocated with 'malloc' C function, then it should be released with the 'free' function, if with 'LocalAlloc' function, then freeing should be performed with 'LocalFree' and so on. The idea is using the same memory manager for allocation and freeing the memory.
 
2) If 'bufferPtr' is the Pointer to ComplexArray parameter, then there is no need to use such " (ComplexArray) bufferPtr  .getReferencedObject();" construction and use can simply return a 'buffer' variable, if it's defined as following:

    ComplexArray buffer = new ComplexArray(new <DataType>, 0);

    ExternalArrayPointer bufferPtr = new ExternalArrayPointer(buffer);


To get element from a ComplexArray parameter you can use its .getItem(int index) method; http://www.teamdev.com/downloads/jniwrapper/javadoc/com/jniwrapper/ComplexArray.html#getElement(int)

We can help you out to solve that crash issue if you can send us a complete Java example and the required native library to reproduce the problem in our environment.

Sincerely,
Serge

viv...@gmail.com

unread,
Jul 13, 2012, 7:31:00 PM7/13/12
to jniwrapp...@teamdev.com, viv...@gmail.com
Thanks Serge. I'm still have problem with this structure,

struct NativeString {
   uint32 length;
   uint8 *buffer;
}

struct ProcessStruct {
    NativeString  processName;
    NativeString  processHash;
    uint16   eventCount;
    NativeString   eventIds[];
}

Now the wrapper for NativeString works fine,

 private UInt32 length = new UInt32();
private PrimitiveArray buffer = new PrimitiveArray(UInt8.class, 0); 
private ExternalArrayPointer bufferPtr = new ExternalArrayPointer(buffer);

but, I'm not sure how to set the ProcessStruct as it has an array of NativeString whose size is not known. If I try to use ExternalArrayPointer then it fails (native function is not setting up the data in the structure). If I simply create a complex array with some predefined size then it works, but I don't want to set the size to some arbitrary number. Is there a way to dynamically set the array size without using pointer?

Here is what works,
 
  private  NativeString  processName = new  NativeString  ();
private  NativeString  processHash = new  NativeString  ();
private UInt16 numEvents = new UInt16();
private ComplexArray eventsArr = new ComplexArray(new  NativeString(), 50);

this doesn't work,

   private ComplexArray  eventsArr  = new ComplexArray(new  NativeString (), 0);
   private ExternalArrayPointer eventsPtr = new ExternalArrayPointer( eventsArr);
     
 The caller (java side) sends the ptr to this structure to the native code and the native code sets data in the struct. Any ideas?

Thanks,
-vivek

Sergei Piletsky

unread,
Jul 16, 2012, 7:40:07 AM7/16/12
to viv...@gmail.com, jniwrapp...@teamdev.com
Hi vivek,

Supposing that the 'eventIds' member of ProcessStruct is the array parameter, it can also be considered as a pointer parameter. In other words, "NativeString   eventIds[]" parameter can also be declared as "NativeString   *eventIds". So, in this case you can also use the same technique as in case with NativeString structure, for example:

    public class ProcessStruct extends Structure {

        private NativeString processName = new NativeString();
        private NativeString processHash = new NativeString();
        private UInt16 eventCount = new UInt16();
        private ComplexArray eventIds = new ComplexArray(new NativeString(), 0);
        private ExternalArrayPointer eventIdsPtr = new ExternalArrayPointer(eventIds);

        public ProcessStruct() {
            init(new Parameter[] {
                processName,
                processHash,
                eventCount,
                eventIdsPtr,
            }, (short) 8);
        }

        public NativeString[] readEventIds() {
            if (eventIdsPtr.isNull()) {
                return new
NativeString[0];
            } else {
                int numberOfEvents = (int) eventCount.getValue();
                eventIdsPtr.readArray(numberOfEvents);
                NativeString result[] = new NativeString[numberOfEvents];
                for (int i = 0; i < numberOfEvents; i++) {
                    result[i] = (NativeString) eventIds.getItem(i);
                }
                return result;
            }
        }
    }

Please try this solution and let me know the results.

Sincerely,
Serge



vivek saraogi

unread,
Jul 16, 2012, 9:32:01 PM7/16/12
to Sergei Piletsky, jniwrapp...@teamdev.com
Hi Serge,

  I did try that before as I mentioned in my post, but I kept getting this in stack,

Stack: [0x4e0c0000,0x4e8c1000],  sp=0x4e8bf720,  free space=8189k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [libjvm.so+0x5ed9c9]
j  sun.misc.Unsafe.getInt(J)I+0
j  java.nio.DirectByteBuffer.getInt(J)I+10
j  java.nio.DirectByteBuffer.getInt(I)I+11
j  com.jniwrapper.g.readPointer(I)J+20
j  com.jniwrapper.Pointer.readPointer(Lcom/jniwrapper/DataBuffer;I)V+2
j  com.jniwrapper.Pointer.read(Lcom/jniwrapper/DataBuffer;IZ)V+3
j  com.jniwrapper.ExternalArrayPointer.read(Lcom/jniwrapper/DataBuffer;IZ)V+9
j  com.jniwrapper.bg.doPointerIO(Lcom/jniwrapper/Pointer;Lcom/jniwrapper/DataBuffer;IZ)V+5
j  com.jniwrapper.Pointer.acceptIOPerformer(Lcom/jniwrapper/IOPerformer;Lcom/jniwrapper/DataBuffer;IZZ)V+6
j  com.jniwrapper.Structure.acceptIOPerformer(Lcom/jniwrapper/IOPerformer;Lcom/jniwrapper/DataBuffer;IZZ)V+54
j  com.jniwrapper.Structure.acceptIOPerformer(Lcom/jniwrapper/IOPerformer;Lcom/jniwrapper/DataBuffer;IZZ)V+54
j  com.jniwrapper.ComplexArray.acceptIOPerformer(Lcom/jniwrapper/IOPerformer;Lcom/jniwrapper/DataBuffer;IZZ)V+20
j  com.jniwrapper.Pointer.readReferencedObject(Z)V+21
j  com.jniwrapper.ExternalArrayPointer.readArray(I)V+61
j  com.xx.xx.ProcessStruct.readEventIds()[Lcom/xx/NativeString;+26

 If I directly set the size in ComplextArray (without using ExternalArrayPointer) it works fine, but the problem is I want to dynamically set the size. Is there a way to do that without using ExternalArrayPointer or do you know why the ExternalArrayPointer method isn't working here? Could the array in native code be defined any differently?

Thanks,
-vivek 

viv...@gmail.com

unread,
Jul 18, 2012, 1:36:30 PM7/18/12
to jniwrapp...@teamdev.com, Sergei Piletsky
Hi Serge, 

  any suggestion on this? I'm kind of stuck here.

Thanks,
-vivek

Sergei Piletsky

unread,
Jul 18, 2012, 1:43:42 PM7/18/12
to vivek saraogi, jniwrapp...@teamdev.com
Hi Vivek,

Thank you for letting me know the results. Now it's clear that in this case the ExternalArrayPointer type should not be used there, because ProcessStruct contains an open array rather than a pointer to an externally allocated buffer for the array.

In this case you can try using the following approach:

1) Declare the wrapper for 'ProcessStruct' without its array part:
    public class ProcessStruct extends Structure {
        private NativeString processName = new NativeString();
        private NativeString processHash = new NativeString();
        private UInt16 eventCount = new UInt16();

        public ProcessStruct() {
            init(new Parameter[]{
                    processName,
                    processHash,
                    eventCount,
            }, (short) 8);
        }
    }

2) Read data by two phases:
        // perform a native function call that returns a pointer (processStructHandle) to process struct
        Pointer.Void processStructHandle = new Void();
        // for example:  readProcessStruct.invoke(null, new Pointer(processStructHandle));

        // 1) now we can read data (ProcessStruct) from that pointer using casting pointers:
        ProcessStruct processStruct = new ProcessStruct();
        Pointer processStructPtr = new Pointer(processStruct);
        processStructHandle.castTo(processStructPtr);
        // now 'processStructPtr' refers to the same address that 'processStructHandle' handler
        // and 'processStruct' contains the 'header' part of the structure

        // the next step is reading the array part of open array structure
        // first we need to change the address of 'processStructHandle' handle so that it points to the beginning of an open array:
        processStructHandle.setValue(processStructHandle.getValue() + processStruct.getLength());

        //
2) now we can read array
        int numberOfEvents = (int) processStruct.eventCount.getValue();
        ComplexArray eventIds = new ComplexArray(new NativeString(), numberOfEvents);
        Pointer eventIdsPtr = new Pointer(eventIds);
        processStructPtr.castTo(eventIdsPtr);
        // now 'eventIds' array should contains the required data and we can read its elements

        NativeString result[] = new NativeString[numberOfEvents];
        for (int i = 0; i < numberOfEvents; i++) {
            result[i] = (NativeString) eventIds.getItem(i);
        }

Could you please try this solution and let me know the results?

Sincerely,
Serge

Sergei Piletsky

unread,
Jul 18, 2012, 1:57:16 PM7/18/12
to viv...@gmail.com, jniwrapp...@teamdev.com
Hi Vivek,

I have just replied to your question in the previous message. I understand that such solution may look a little bit complicated, but this is one of the best approaches in case when a size of a structure is unknown in advance.

Another possible and quick solution is to declare 'ComplexArray eventIds = new ComplexArray(new NativeString(), numberOfEvents);' field big enough to fit any presumptive number of elements, just like you do in your working approach.

Alternative solution would be to perform two native function calls (as they usually do in Windows API), when first function call returns the size of a buffer, and second one allocates the buffer of required size and then reads the data from that buffer.


Please let me know if you have any further questions.

Sincerely,
Serge


viv...@gmail.com

unread,
Jul 18, 2012, 6:07:32 PM7/18/12
to jniwrapp...@teamdev.com, viv...@gmail.com
Hi Serge,

  I tried the code you suggested, but that's crashing too (no stack even). The alternative approach you suggested may not work for me because the first call I make I get the buffer size for the whole structure, but not the number of elements in the array. 

Currently, I'm using the fixed array size, but that doesn't seem like the right approach. Any other ideas?

Thanks,
-vivek

Sergei Piletsky

unread,
Jul 19, 2012, 11:49:25 AM7/19/12
to viv...@gmail.com, jniwrapp...@teamdev.com
Hi vivek,

Could you please provide me with the complete Java code so I can see the whole picture? Thanks.

Sincerely,
Serge

vivek saraogi

unread,
Dec 4, 2012, 9:07:59 PM12/4/12
to Sergei Piletsky, jniwrapp...@teamdev.com
Hi Serge,

   This is an old issue, but I'm trying to fix the dynamic array problem. I tried your suggested solution, but jvm is crashing when trying to do the casting.  I've tried with and without adding the padding to the structure, but it's the same problem. 

The stack dump shows the following,

Stack: [0x6d2ae000,0x6daaf000],  sp=0x6daad700,  free space=8189k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [libjvm.so+0x5ed9c9]
j  sun.misc.Unsafe.getInt(J)I+0
j  java.nio.DirectByteBuffer.getInt(J)I+10
j  java.nio.DirectByteBuffer.getInt(I)I+11
j  com.jniwrapper.g.readPointer(I)J+20
j  com.jniwrapper.Pointer.readPointer(Lcom/jniwrapper/DataBuffer;I)V+2
j  com.jniwrapper.Pointer.read(Lcom/jniwrapper/DataBuffer;IZ)V+3
j  com.jniwrapper.ExternalArrayPointer.read(Lcom/jniwrapper/DataBuffer;IZ)V+9
j  com.jniwrapper.bg.doPointerIO(Lcom/jniwrapper/Pointer;Lcom/jniwrapper/DataBuffer;IZ)V+5
j  com.jniwrapper.Pointer.acceptIOPerformer(Lcom/jniwrapper/IOPerformer;Lcom/jniwrapper/DataBuffer;IZZ)V+6
j  com.jniwrapper.Structure.acceptIOPerformer(Lcom/jniwrapper/IOPerformer;Lcom/jniwrapper/DataBuffer;IZZ)V+54
j  com.jniwrapper.Structure.acceptIOPerformer(Lcom/jniwrapper/IOPerformer;Lcom/jniwrapper/DataBuffer;IZZ)V+54
j  com.jniwrapper.Pointer.readReferencedObject(Z)V+21
j  com.jniwrapper.Pointer.read(Lcom/jniwrapper/DataBuffer;IZ)V+23
j  com.jniwrapper.Pointer$Void.castTo(Lcom/jniwrapper/Pointer;)V+19
j  com.xxx.em.handler.ExNetworkHandler2.getProcessInfo(Lcom/xxx/em/wrapper/epsec/ExProcessHandle;)Lcom/xxx/em/wrapper/epsec/ExProcessBasicInfo;+389
j  com.xxx.em.handler.EPSecNetworkHandler2.internalCallback(Lcom/xxx/em/wrapper/epsec/ExNetworkEventType;Lcom/xxx/em/wrapper/epsec/ExHandle;Lcom/jniwrapper/Pointer$Void;)J+810
j  com.xxx.em.handler.ExNetworkHandler2.callback([Lcom/jniwrapper/Parameter;Lcom/jniwrapper/Parameter;)V+87
j  com.jniwrapper.Callback.enterPoint(JI)J+66

Here is my code,

//structure
public class ExProcessBasicInfo2 extends Structure {
private ExString processName = new ExString();
private ExString cmdLine = new ExString();
private UInt16 numGroups = new UInt16();
private PrimitiveArray padding;
public ExProcessBasicInfo2(int paddingSize) {
padding = new PrimitiveArray(UInt8.class, paddingSize); 
init(new Parameter[] { processName, cmdLine, numGroups,padding}, (short) 1);
}
...
}
...
...

Pointer.Void processStructHandle = new Pointer.Void();

Function epsecProcessInfo = epSecLib.getFunction("EPSecQueryProcessInfo");
epsecProcessInfo.setCallingConvention(Function.CDECL_CALLING_CONVENTION);

EPSecStatus status = new EPSecStatus();
Parameter[] parameters = { processHandle, processType, new Pointer(processStructHandle),
infoSize };
epsecProcessInfo.invoke(status, parameters);


logger.trace("ProcessInfo padding: " + paddingSize);
ExProcessBasicInfo2 processInfo = new ExProcessBasicInfo2(paddingSize);        
Pointer processInfoPtr = new Pointer(processInfo);
processStructHandle.castTo(processInfoPtr);            ===> fails here (sometimes just hangs here)
logger.trace("casting done");

Any other suggestions?

Thanks,
-vivek

Sergei Piletsky

unread,
Dec 5, 2012, 5:52:02 AM12/5/12
to vivek saraogi, jniwrapp...@teamdev.com
Hi Vivek,

From your code snippet it's not clear how 'paddingSize' value is calculated before you pass it to ExProcessBasicInfo2 constructor. When I used such technique I usually calculated a padding size using following formula: padding size = memory block size - fixed size of a structure. In your case the "fixed size of a structure" is a sum of 'processName', 'cmdLine' and 'numGroups' structure field lengths.

Sincerely,
Serge

vivek saraogi

unread,
Dec 5, 2012, 2:57:40 PM12/5/12
to Sergei Piletsky, jniwrapp...@teamdev.com
Thanks Serge. 

How do you get the fixed size of a structure? In my case the properties of the structure are also structures containing dynamic arrays (using ExternalArrayPointers). I don't think I can use instrumentation for that as the object is not even populated at the time of passing the padding in the init. 

We are also seeing some random jvm crashes due memory corruption - not sure if that could be related to padding. Without padding I'm not able to copy the C structure(using pointers) into the jni structure(using ExternalArrayPointer) - the jvm simply crashes after the invoke. Is there a good way of getting around the padding issue?

Thanks,
-vivek

Sergei Piletsky

unread,
Dec 6, 2012, 10:28:41 AM12/6/12
to vivek saraogi, jniwrapp...@teamdev.com
Hi,

I have never suggested you to use the solution with padding, at least in this thread. I do not think that it's an proper solution in this case.

The padding in structure wrappers can be used for those structures which content varies depending on some conditions, and when that content is not required to be used on a Java side. A typical illustration of such type in Windows API is WM_MEDIA_TYPE structure. The following example is simplified version of such use case:

    struct MyStruct {
       int type;
       int elementCount;
       byte data[];
    }

Fixed part of the structure in this case is its first two members, and fixed size of MyStruct structure is accordingly the sum of lengths of 'type' and 'elementCount' members. The length of each structure member can be obtained using sizeof(<type>) macro in C. And in JNIWrapper the length of any Parameter object can be obtained using its Parameter.getLength() method. It returns the length of a parameter in bytes. The length of all pointer parameters such as Pointer, ExternalArrayPointer, etc. is 4 bytes in 32-bit context, and 8 bytes in 64-bit context.

So, if you got a handle to a native memory block that is bigger than initial size of MyStruct structure, the padding can be used as following:

    class MyStruct extends  {
       Int type = new Int();
       Int elementCount = new Int();
      
       MyStruct(int requiredSize) {
           int paddingSize = requiredSize - (type.getLength() + elementCount.getLengh());
           PrimitveArray padding  = new PrimitiveArray(UInt8.class, paddingSize);
           init(new Parameter[] {type, elementCount, padding}, (short) 1);
       }
   }

When you use such approach you should also remember that it is very demanding for proper type mappings, so those JVM crashes in your case indicate that mapping was incorrect.

Sometime ago I have already suggested you how to solve this issue, of course without padding, just using pointers arithmetic.

Here is that solution again, but now it's a little bit simplified:


1) Declare the wrapper for 'ProcessStruct' without its array part:
    public class ProcessStruct extends Structure {
        private NativeString processName = new NativeString();
        private NativeString processHash = new NativeString();
        private UInt16 eventCount = new UInt16();

        public ProcessStruct() {
            init(new Parameter[]{
                    processName,
                    processHash,
                    eventCount,
            }, (short) 8);
        }
    }
  

This structure will be used just to get an element count value.

2) Declare the wrapper for 'ProcessStruct' with array part:

    public class ProcessStructWithArray extends Structure {

        private NativeString processName = new NativeString();
        private NativeString processHash = new NativeString();
        private UInt16 eventCount = new UInt16();
        private ComplexArray eventIds;

        public ProcessStructWithArray(int elementCount) {

            eventIds = new ComplexArray(new NativeString(), numberOfEvents);
            init(new Parameter[]{
                    processName,
                    processHash,
                    eventCount,
                    eventIds,
            }, (short) 8);
        }
    }
  

This structure will be used to read array elements.

3) Reading data:

        // perform a native function call that returns a pointer to a ProcessStruct structure
        Pointer.Void processStructHandle = ...;

        // read
ProcessStruct from that pointer to get a number of events

        ProcessStruct processStruct = new ProcessStruct();
        Pointer processStructPtr = new Pointer(processStruct);
        processStructHandle.castTo(processStructPtr);

        int eventCount = (int) processStruct.eventCount.getValue()

        // read
ProcessStructWithArray again from the same pointer to get elements of array
        ProcessStructWithArray processStruct2 = new ProcessStructWithArray(eventCount);
        Pointer processStruct2Ptr = new Pointer(processStruct2);
        processStructHandle.castTo(processStruct2Ptr);

        // now its 'eventIds' array should contain the required data so we can read its elements
        NativeString result[] = new NativeString[numberOfEvents];
        for (int i = 0; i < numberOfEvents; i++) {
            result[i] = (NativeString) processStruct2.eventIds.getItem(i);
        }

Could you please try this approach and let me know if it helps?

If problem persists I can help you out to solve this issue, but in that case I will need a complete Java sample in order to reproduce the problem.

Thanks,
Serge

Reply all
Reply to author
Forward
0 new messages