英文:
Structure loaded using JNA defining fields wrong
问题
我之前没有使用过JNA,但我打算尝试与我正在使用的第三方DLL一起使用。我希望我能提供我使用JNA调用的函数的源代码,但不幸的是,我不拥有这个软件,所以我不确定我可以分发什么。
我需要的结构相当长/复杂,这只是一个警告。我没有包含加载此结构所需的函数,因为它们似乎在工作并且没有问题。这是原始的C结构:
以下是你提供的Java实现代码中的翻译结果:
@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;
/**
* 无符号字节结构大小。
*/
@Getter public NativeLong unsignedSize = new NativeLong(DATA_SIZE, true);
/**
* 表面类型。
*/
@Getter public int type;
/**
* 表面名称(最大长度为31)。
*/
@Getter public char[] name = new char[31];
/**
* 测量表面的操作员名称(最大长度为31)。
*/
@Getter public char[] operator = new char[31];
/**
* 用于测量表面的传感器类型。
*/
@Getter public short sensorType;
/**
* 测量中使用的跟踪类型。
*/
@Getter public short trackingType;
/**
* 特殊点类型,以及是否存在未测量的点。
*/
@Getter public short specialPointType;
/**
* 定义表面是否具有绝对值。
*/
@Getter public boolean absolute;
/**
* 标尺分辨率值。如果未设置分辨率,则定义为0。
*/
@Getter public float gaugeResolution;
/**
* 最小(重采样)值。
*/
@Getter public NativeLong zMin = new NativeLong();
/**
* 最大(重采样)值。
*/
@Getter public NativeLong zMax = new NativeLong();
/**
* 每列的点数。
*/
@Getter public NativeLong xCount = new NativeLong();
/**
* 每行的点数。
*/
@Getter public NativeLong yCount = new NativeLong();
/**
* 深度方向上的点数(用于高光谱测量)。
*/
@Getter public NativeLong wCount = new NativeLong();
/**
* X轴步长值。
*/
@Getter public float fXStep;
/**
* Y轴步长值。
*/
@Getter public float fYStep;
/**
* Z轴步长值。
*/
@Getter public float fZStep;
/**
* X轴偏移量。
*/
@Getter public float xOffset;
/**
* Y轴偏移量。
*/
@Getter public float yOffset;
/**
* Z轴偏移量。
*/
@Getter public float zOffset;
/**
* X轴名称(最大大小为17字节)。
*/
@Getter public char[] xAxisName = new char[17];
/**
* Y轴名称(最大大小为17字节)。
*/
@Getter public char[] yAxisName = new char[17];
/**
* Z轴名称(最大大小为17字节)。
*/
@Getter public char[] zAxisName = new char[17];
/**
* X轴测量单位。
*/
@Getter public int xAxisUnit;
/**
* Y轴测量单位。
*/
@Getter public int yAxisUnit;
/**
* Z轴测量单位。
*/
@Getter public int zAxisUnit;
/**
* 如果从枚举中未知X轴单位,则单位存在于此字段中(最大大小为17字节)。
*/
@Getter public char[] strXAxisUnknownUnit = new char[17];
/**
* 如果从枚举中未知Y轴单位,则单位存在于此字段中(最大大小为17字节)。
*/
@Getter public char[] strYAxisUnknownUnit = new char[17];
/**
* 如果从枚举中未知Z轴单位,则单位存在于此字段中(最大大小为17字节)。
*/
@Getter public char[] strZAxisUnknownUnit = new char[17];
/**
* 定义研究值是否被倒置。
*/
@Getter public boolean inverted;
/**
* 定义研究是否被校平。
*/
@Getter public short rectified;
/**
* 测量记录时间的秒值。
*/
@Getter public short second;
/**
* 测量记录时间的分钟值。
*/
@Getter public short minute;
/**
* 测量记录时间的小时值。
*/
@Getter public short hour;
/**
* 测量记录时间的日期。
*/
@Getter public short day;
/**
* 测量记录时间的月份。
*/
@Getter public short month;
/**
* 测量记录时间的年份。
*/
@Getter public short year;
/**
* 测量的长度(以秒为单位)。
*/
@Getter public float fMeasureLength;
/**
* 客户信息(最大大小为128字节)。
*/
@Getter public char[] clientInfo = new char[
<details>
<summary>英文:</summary>
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.
</details>
# 答案1
**得分**: 1
你问题最可能的来源是在使用Java的`char`映射到C的`char`时出现了问题。它们并不相同。Java的`char`是字符的2字节UTF-16映射,而在C中,`char`是一个字节。
详见JNA的[类型映射](http://java-native-access.github.io/jna/5.6.0/javadoc/overview-summary.html#marshalling)概述中的更多信息。
一般情况下,你对于在C中使用`long`选择的`NativeLong`是可以的,用于跨平台代码。
我不清楚你的`TUNIT`映射到什么类型,但如果它是一个4字节类型,使用`int`映射是可以的。
<details>
<summary>英文:</summary>
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](http://java-native-access.github.io/jna/5.6.0/javadoc/overview-summary.html#marshalling) 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.
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论