I haven't used JNA before, but I figured I would give it a shot with a 3rd party DLL I am working with. I wish I could give the source code for the functions that I call with JNA, but I sadly don't own this software so I'm sure what I am allowed to distribute.
The structure I need is rather long/complex, just a warning. I did not include the functions I needed to load this struct, as they appear to be working and have no issue. Here is the original C struct:
struct TSurfObjectInfos
{
unsigned long ulSize; // size of the structure
int Type; // studiable type
char strName[31]; // name of the studiable
char strOperatorName[31]; // name of the operator who
// measured the studiable
short nAcquisitionType; // which kind of sensor has been used
// for the measure
short nTracking; // 0: normal tracking
// 1: extended tracking
short nSpecialPoints; // 0: normal
// 1: non-measured points
int bAbsolute; // FALSE: relatives values
// TRUE: absolutes values
float fGaugeResolution; // 0: resolution not set
long nZMin; // min (resampled) value
long nZMax; // max (resampled) value
long nXCount; // number of points by column
long nYCount; // number of points by row
long nWCount; // number of points by depth (for hyperpectral measurements)
float fXStep; // step
float fYStep; // step
float fZStep; // step
float fXOffset; // offset
float fYOffset; // offset
float fZOffset; // offset
char strXAxisName[17]; // name of the X axis
char strYAxisName[17]; // name of the Y axis
char strZAxisName[17]; // name of the Z axis
TUNIT tXAxisUnit; // X axis unit
TUNIT tYAxisUnit; // Y axis unit
TUNIT tZAxisUnit; // Z axis unit
char strXAxisUnknownUnit[17]; // if unknown X unit, unit is present in this field
char strYAxisUnknownUnit[17]; // if unknown Y unit, unit is present in this field
char strZAxisUnknownUnit[17]; // if unknown Z unit, unit is present in this field
int bInverted; // are the values inverted ?
short nRectified; //
short nSecond; // date-time of the measure
short nMinute;
short nHour;
short nDay;
short nMonth;
short nYear;
float fMeasureLength; // length (in seconds) of the measure
char ClientInfo[128]; // client informations
short nCommentSize; // size in bytes of the comment
// *** T Axis ******************
// *** only used with series ***
float fTStep; // step
float fTOffset; // offset
int tTAxisUnit; // T axis unit
char strTAxisUnknownUnit[14]; // if unknown T unit, unit is present in this field
char strTAxisName[14]; // name of the T axis
// *** T Axis ******************
};
typedef struct TSurfObjectInfos TSurfObjectInfos;
And here is my Java implementation:
@FieldOrder({ "unsignedSize",
"type",
"name",
"operator",
"sensorType",
"trackingType",
"specialPointType",
"absolute",
"gaugeResolution",
"zMin", "zMax",
"xCount", "yCount", "wCount",
"fXStep", "fYStep", "fZStep",
"xOffset", "yOffset", "zOffset",
"xAxisName", "yAxisName", "zAxisName",
"xAxisUnit", "yAxisUnit", "zAxisUnit",
"strXAxisUnknownUnit", "strYAxisUnknownUnit", "strZAxisUnknownUnit",
"inverted",
"rectified",
"second", "minute", "hour", "day", "month", "year", "fMeasureLength",
"clientInfo",
"commentSize",
"tStep", "tOffset", "tAxisUnit", "strTAxisUnknownUnit", "tAxisName"})
public class StudiableInfo extends Structure {
private static final int DATA_SIZE = 339;
/**
* Unsigned byte size of structure.
*/
@Getter public NativeLong unsignedSize = new NativeLong(DATA_SIZE, true);
/**
* Type of surface.
*/
@Getter public int type;
/**
* Name of surface (maximum length of 31).
*/
@Getter public char[] name = new char[31];
/**
* Name of operator who measured the surface (maximum length of 31).
*/
@Getter public char[] operator = new char[31];
/**
* Type of sensor used for measuring the surface.
*/
@Getter public short sensorType;
/**
* Type of tracking used in measurements.
*/
@Getter public short trackingType;
/**
* Special point type, and whether there are non-measured points.
*/
@Getter public short specialPointType;
/**
* Defines if surface has absolute values.
*/
@Getter public boolean absolute;
/**
* Gauge resolution value. Defined as 0 if resolution not set.
*/
@Getter public float gaugeResolution;
/**
* Minimum (resampled) value.
*/
@Getter public NativeLong zMin = new NativeLong();
/**
* Maximum (resampled) value.
*/
@Getter public NativeLong zMax = new NativeLong();
/**
* Number of points by column.
*/
@Getter public NativeLong xCount = new NativeLong();
/**
* Number of points by row.
*/
@Getter public NativeLong yCount = new NativeLong();
/**
* Number of points by depth (for hyperpectral measurements).
*/
@Getter public NativeLong wCount = new NativeLong();
/**
* X-axis step value.
*/
@Getter public float fXStep;
/**
* Y-axis step value.
*/
@Getter public float fYStep;
/**
* Z-axis step value.
*/
@Getter public float fZStep;
/**
* X-axis offset.
*/
@Getter public float xOffset;
/**
* X-axis offset.
*/
@Getter public float yOffset;
/**
* X-axis offset.
*/
@Getter public float zOffset;
/**
* Name of the X-axis (max size of 17 bytes).
*/
@Getter public char[] xAxisName = new char[17];
/**
* Name of the Y-axis (max size of 17 bytes).
*/
@Getter public char[] yAxisName = new char[17];
/**
* Name of the Z-axis (max size of 17 bytes).
*/
@Getter public char[] zAxisName = new char[17];
/**
* X-axis measurement units.
*/
@Getter public int xAxisUnit;
/**
* Y-axis measurement units.
*/
@Getter public int yAxisUnit;
/**
* Z-axis measurement units.
*/
@Getter public int zAxisUnit;
/**
* If unknown X-axis unit from enum, unit is present in this field (max size of 17 bytes).
*/
@Getter public char[] strXAxisUnknownUnit = new char[17];
/**
* If unknown Y-axis unit from enum, unit is present in this field (max size of 17 bytes).
*/
@Getter public char[] strYAxisUnknownUnit = new char[17];
/**
* If unknown Z-axis unit from enum, unit is present in this field (max size of 17 bytes).
*/
@Getter public char[] strZAxisUnknownUnit = new char[17];
/**
* Defines if the studiable values are inverted.
*/
@Getter public boolean inverted;
/**
* Defines if the studiable is levelled.
*/
@Getter public short rectified;
/**
* Seconds value at recorded time of measurement.
*/
@Getter public short second;
/**
* Minutes value at recorded time of measurement.
*/
@Getter public short minute;
/**
* Hour value at recorded time of measurement.
*/
@Getter public short hour;
/**
* Day at recorded time of measurement.
*/
@Getter public short day;
/**
* Month at recorded time of measurement.
*/
@Getter public short month;
/**
* Year at recorded time of measurement.
*/
@Getter public short year;
/**
* Length (in seconds) of the measure.
*/
@Getter public float fMeasureLength;
/**
* Client information (max size of 128 bytes).
*/
@Getter public char[] clientInfo = new char[128];
/**
* Size in bytes of the comment.
*/
@Getter public short commentSize;
// *** T Axis ******************
// *** only used with series ***
/**
* Step value of T-axis.
*/
@Getter public float tStep;
/**
* Offset of T-axis.
*/
@Getter public float tOffset;
/**
* T-axis measurement units.
*/
@Getter public int tAxisUnit;
/**
* If unknown T-axis unit from enum, unit is present in this field (max size of 14 bytes).
*/
@Getter public char[] strTAxisUnknownUnit = new char[14];
/**
* Name of the T-axis (max size of 14 bytes).
*/
@Getter public char[] tAxisName = new char[14];
// *** T Axis ******************
}
Everything on their own looks fine to me, but when actually loading and looking at the structure, the only field that is correct is the type
member. From then on, every other field appears to be invalid or garbage data. However, it is consistent and always outputs the same set of invalid data.
I'm worried that this could be because of the import function works internally. You will notice there is a ulSize
field that I'm guessing could be used for mapping the memory in the structure? So maybe the function internally is not mapping the memory to the correct location once JNA or Java's memory handling is being used. Although since I am still new to JNA, I am not quite sure if that is even a possible issue.
I'm also thinking that maybe there is a conversion issue between the native C long
type and the JNA NativeLong
? But I'm still not quite sure. I even tried replacing the NativeLong
's with long
s and it still didn't seem to work.
Let me know if there is more information I can give. I didn't want to overload with too much information that could've been useless.
The most likely source of your problem is using Java's char
mapping for the C char
. They aren't the same. Java's char
is a 2-byte UTF-16 mapping of characters, while in C, a char
is a single byte.
See JNA's Type Mapping reference in the overview for more.
Your choice of NativeLong
for C's long
is fine in general for cross-platform code.
I don't know what your TUNIT
maps to, but if it's a 4-byte type, the int
mapping is fine.