SDK Nikon C with JNA

65 Views Asked by At

I'm working on a wrap between a Nikon SDK written in C and a Java program with JNA libruary.

All the process ended in a EntryPoint (MAIDEntryPoint) that is inside a dll. The signature of this EntryPoint in C is:

SLONG CallMAIDEntryPoint( 
    LPNkMAIDObject  pObject,    // module, source, item, or data object
    ULONG       ulCommand,  // Command, one of eNkMAIDCommand
    ULONG       ulParam,        // parameter for the command
    ULONG       ulDataType, // Data type, one of eNkMAIDDataType
    NKPARAM         data,           // Pointer or long integer
    LPNKFUNC    pfnComplete,    // Completion function, may be NULL
    NKREF       refComplete )   // Value passed to pfnComplete

The LPNkMAIDObject pObject is a struct defined in C as:

typedef struct tagNkMAIDObject
{
    ULONG   ulType;         // One of eNkMAIDObjectType
    ULONG   ulID;
    NKREF   refClient;
    NKREF   refModule;
} NkMAIDObject, FAR* LPNkMAIDObject;

the value I'm interesting on is the NKPARAM data that is this next struct:

//stEnum Struct

typedef struct tagNkMAIDEnum
{
    ULONG       ulType;         // one of eNkMAIDArrayType
    ULONG       ulElements;     // total number of elements
    ULONG       ulValue;        // current index
    ULONG       ulDefault;      // default index
    SWORD       wPhysicalBytes;         // bytes per element
    LPVOID  pData;              // allocated by the client
} NkMAIDEnum, FAR* LPNkMAIDEnum;

and the scope of the EntryPoint is to populate the argument LPVOID pData. The pData argument is a pointer that is allocate in this way:

NkMAIDEnum stEnum;
stEnum.pData = malloc(stEnum.ulElements * stEnum.wPhysicalBytes);

what I done is to "translate" whit jna the struct and the EntryPoint, that are this:

//EntryPoint
int MAIDEntryPoint(NkMAIDObject pObject,
                   int kNkMAIDCommand_capGetArray,
                   int ulCapID,
                   int kNkMAIDDataType_enumPtr,
                   NkMAIDEnum nkMAIDEnum,
                   Object o,
                   int i);

And the Struct will be defined as a Java Class:

@Structure.FieldOrder({"ulType","ulID","refClient","refModule"})
public class NkMAIDObject extends Structure {

    public NativeLong ulType;   // One of eNkMAIDObjectType
    public NativeLong ulID;
    public TagRefObj.ByReference refClient;
    //public Pointer refClient;
    public Pointer refModule;
}
@Structure.FieldOrder({"ulType", "ulElements", "ulValue", "ulDefault", "wPhysicalBytes", "pData"})
public class NkMAIDEnum extends Structure {
    public NativeLong ulType;
    public NativeLong ulElements;
    public NativeLong ulValue;
    public NativeLong ulDefault;
    public short wPhysicalBytes;
    public Pointer pData;
}

At this point I initializa the Pointer pData as:

NkMAIDEnum nkMAIDEnum = new NkMAIDEnum ();
nkMAIDEnum.pData = new Memory(nkMAIDEnum.ulElements.longValue()*nkMAIDEnum.wPhysicalBytes);

nResult = INSTANCE.MAIDEntryPoint(
                   pRefMod.pObject,                
                   kNkMAIDCommand_CapGetArray,     
                   ulCapID,                        
                   kNkMAIDDataType_EnumPtr,        
                   nkMAIDEnum,                     
                   null,
                   0);

And then pass it to the EntryPoint, but I receive an Invalid Access Memory . I think the problem is how to initialize the pData in the Java-JNA part or also what kind of data should be the pData in the class NkMAIDEnum

For instance, I don't care about the other EntryPoint's parameter because they're right, and alto the parameters nkMAIDEnum.ulElements and nkMAIDEnum.wPhysicalBytes are number not equals to 0 or null, they are respectively nkMAIDEnum.ulElements = 1 and nkMAIDEnum.wPhysicalBytes = 4 they are initialize in a previously EntryPoint, that is exactly the same as the one written here but instade of initialize the pData, it initialize the nkMAIDEnum.ulElements and nkMAIDEnum.wPhysicalBytes.

Please help me to understan where I'm wrong, I'm stuck

1

There are 1 best solutions below

2
Daniel Widdis On

I see three possible problems:

  1. JNA needs enough type information to be able to allocate the correct number of bytes in structures (for memory allocation) or method/function signatures (for the stack).

    Your use of Object to map the 6th argument in MAIDEntryPoint() is most certainly wrong. JNA has no way to know how many bytes that takes. Since that argument is actually LPNKFUNC pfnComplete it looks like a Pointer would be the correct mapping for it.

  2. Another possibility is if you've incorrectly mapped (or allocated) the NkMAIDObject type that is the first argument to MAIDEntryPoint(). You haven't shown us the mapping, but it could very well be an incorrect allocation.

  3. Finally you indicate the native allocation is done with malloc(stEnum.ulElements * stEnum.wPhysicalBytes) and state

the parameters nkMAIDEnum.ulElements and nkMAIDEnum.wPhysicalBytes are number not equals to 0 or null.

  • However, you don't show where these are assigned. You simply define a new structure with new NkMAIDEnum() and do not assign any values to .ulElements or .wPhysicalBytes so they are, in fact, initialized to zero. (Unless you have code you aren't showing us.)