Search code examples
javajna

JNA: Can't create object of structure subclass - Invalid structure field


I am mapping a C typedef to a JNA Struct. Below if the C typedef:

typedef struct _GLYCOUNTERS {
unsigned int ulArraySize;
LPGLYCOUNTER lpCounters;
}GLYCOUNTERS, *LPGLYCOUNTERS;

And this is my JNA Structure subclass:

public class GlyCounters extends Structure{
    public class ByReference extends GlyCounters implements Structure.ByReference {};
    public class ByValue extends GlyCounters implements Structure.ByValue {};
    public int ulArraySize;
    public GlyCounter lpCounters;

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

I am trying to create and object of GlyCounters class with code:

lppCounters = glyTypes.new GlyCounters();

As you can see I am creating the object in another class and GlyCounters is a nested class of yet another class.

This is the error message I receive:

Exception in thread "main" java.lang.IllegalArgumentException: Invalid Structure field in class btc_dll.GloryTypeDef$GlyCounters, field name 'lpCounters' (class btc_dll.GloryTypeDef$GlyCounter): Can't instantiate class btc_dll.GloryTypeDef$GlyCounter (java.lang.InstantiationException: btc_dll.GloryTypeDef$GlyCounter)
at com.sun.jna.Structure.validateField(Structure.java:1038)
at com.sun.jna.Structure.validateFields(Structure.java:1048)
at com.sun.jna.Structure.<init>(Structure.java:179)
at com.sun.jna.Structure.<init>(Structure.java:172)
at com.sun.jna.Structure.<init>(Structure.java:159)
at com.sun.jna.Structure.<init>(Structure.java:151)
at btc_dll.GloryTypeDef$GlyCounters.<init>(GloryTypeDef.java:298)
at btc_gui.Btc_gui.main(Btc_gui.java:54)
Java Result: 1

The field causing the problem is yet another JNA Structure class for another c typedef struct. After googling the error message, I have tried adding no-args constructors to both of these classes but the error still remains.

Has anyone had similar problems?


Solution

  • When you want a field of type struct * within your structure, you need to use a Structure tagged with the interface Structure.ByReference.

    EDITED

    The most common way to do this:

    public class GlyCounter extends Structure {
        public class ByReference extends GlyCounter implements Structure.ByReference {};
        // More definition here...
    }
    public class GlyCounters extends Structure{
        public int ulArraySize;
        public GlyCounter.ByReference lpCounters;
    
        public GlyCounters(Pointer p) {
            super(p);
            read();
        }
    
        @Override
        protected List<String> getFieldOrder() {
            return Arrays.asList(new String[] { "ulArraySize", "lpCounters"});
        }
    }
    
    // To obtain the full array (assuming they're allocated as a block)
    GlyCounters gc = new GlyCounters(pointer);
    GlyCounter[] counters = gc.lpCounters.toArray(gc.ulArraySize());
    

    The field lpCounters is now of pointer type instead of inlined (i.e. sharing the memory of the enclosing struct).