使用 JNA 加载的结构定义字段错误

Structure loaded using JNA defining fields wrong

我以前没有使用过 JNA,但我想我会用我正在使用的第 3 方 DLL 试一试。我希望我可以提供我用 JNA 调用的函数的源代码,但遗憾的是我没有这个软件,所以我确定我可以分发什么。

我需要的结构比较long/complex,只是一个警告。我没有包含加载此结构所需的功能,因为它们似乎可以正常工作并且没有问题。这是原始的 C 结构:

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;

这是我的 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;

  /**
   * 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 ******************
}

我觉得一切都很好,但在实际加载和查看结构时,唯一正确的字段是 type 成员。从那时起,其他所有字段似乎都是无效数据或垃圾数据。但是,它是一致的,总是输出相同的一组无效数据。

我担心这可能是因为导入功能在内部起作用。您会注意到有一个 ulSize 字段,我猜它可以用于映射结构中的内存?因此,一旦使用 JNA 或 Java 的内存处理,函数内部可能不会将内存映射到正确的位置。虽然因为我对 JNA 还是新手,所以我不太确定这是否是一个可能的问题。

我也在想,也许原生 C long 类型和 JNA NativeLong 类型之间存在转换问题?但我还是不太确定。我什至尝试用 long 替换 NativeLong,但它似乎仍然不起作用。

如果我能提供更多信息,请告诉我。我不想用太多可能毫无用处的信息来超载。

您的问题最可能的来源是使用 Java 的 char 映射 C char。他们不一样。 Java 的 char 是字符的 2 字节 UTF-16 映射,而在 C 中,char 是单个字节。

有关更多信息,请参阅概述中 JNA 的 Type Mapping 参考。

您为 C 的 long 选择的 NativeLong 对于 cross-platform 代码通常是好的。

我不知道你的 TUNIT 映射到什么,但如果它是 4 字节类型,int 映射就可以了。