java - 错误的输出来自 JNA 中的结构字段值

标签 java jna

我正在尝试使用 Vector XL Driver Library (vxlapi64.dll)使用java代码。我创建了一个 JNA 项目来读取 vxlapi64.dll 并映射数据类型,但输出为结构元素生成错误的值。

C代码结构:

    typedef struct s_xl_channel_config {
          char                name [XL_MAX_LENGTH + 1];
          unsigned char       hwType;                               
          unsigned char       hwIndex;                              
          unsigned char       hwChannel;                           
          unsigned short      transceiverType;                    
          unsigned short      transceiverState;                   
          unsigned short      configError;                          
          unsigned char       channelIndex;                        
          XLuint64            channelMask;                          
          unsigned int        channelCapabilities;                  
          unsigned int        channelBusCapabilities;             
                                                                    

          // Channel          
          unsigned char       isOnBus;                              
          unsigned int        connectedBusType;                  
          XLbusParams         busParams;
          unsigned int        _doNotUse;                            
                                                        
          unsigned int        driverVersion;            
          unsigned int        interfaceVersion;                     
          unsigned int        raw_data[10];
                              
          unsigned int        serialNumber;
          unsigned int        articleNumber;

          char                transceiverName [XL_MAX_LENGTH +1]

          unsigned int        specialCabFlags;                      
          unsigned int        dominantTimeout;                    
          unsigned char       dominantRecessiveDelay;         
          unsigned char       recessiveDominantDelay;          
          unsigned char       connectionInfo;                      
          unsigned char       currentlyAvailableTimestamps;  
          unsigned short      minimalSupplyVoltage;             
          unsigned short      maximalSupplyVoltage;            
          unsigned int        maximalBaudrate;                     
          unsigned char       fpgaCoreCapabilities;               
          unsigned char       specialDeviceStatus;               
          unsigned short      channelBusActiveCapabilities;   s)
          unsigned short      breakOffset;                          
          unsigned short      delimiterOffset;                    
          unsigned int        reserved[3];
        } XL_CHANNEL_CONFIG; 

Java映射结构:

  public static class XLchannelConfig extends Structure{
      public byte[] name = new byte[XL_MAX_LENGTH + 1];
      public byte hwType;
      public byte hwIndex;
      public byte hwChannel;
      public short transceiverType;
      public short transceiverState;
      public short configError;     
      public byte channelIndex;
      public UnsignedInt channelMask;
      public UnsignedInt channelCapabilities;
      public UnsignedInt channelBusCapabilities;
      public byte isOnBus;
      public UnsignedInt connectedBusType;
      public XLbusParams busParams;
      public UnsignedInt _doNotUse;  
      public UnsignedInt driverVersion;
      public UnsignedInt interfaceVersion;
      public UnsignedInt[] raw_data = new UnsignedInt[10];
      public UnsignedInt serialNumber;
      public UnsignedInt articleNumber;
      public byte[] transceiverName = new byte[XL_MAX_LENGTH +1];
      public UnsignedInt specialCabFlags;
      public UnsignedInt dominantTimeout;
      public byte dominantRecessiveDelay;  
      public byte recessiveDominantDelay;
      public byte connectionInfo;
      public byte currentlyAvailableTimestamps;
      public short minimalSupplyVoltage;
      public short maximalSupplyVoltage;
      public UnsignedInt maximalBaudrate;   
      public byte fpgaCoreCapabilities; 
      public byte specialDeviceStatus;
      public short channelBusActiveCapabilities;
      public short breakOffset;       
      public short delimiterOffset; 
      public UnsignedInt[] reserved = new UnsignedInt[3];
      
      @Override
      protected List getFieldOrder() {
          return Arrays.asList(
                  "name",
                  "hwType",
                  "hwIndex",
                  "hwChannel",
                  "transceiverType",
                  "transceiverState",
                  "configError",
                  "channelIndex",
                  "channelMask",
                  "channelCapabilities",
                  "channelBusCapabilities",
                  "isOnBus",
                  "connectedBusType",
                  "busParams",
                  "_doNotUse",
                  "driverVersion",
                  "interfaceVersion",
                  "raw_data",
                  "serialNumber",
                  "articleNumber",
                  "transceiverName",
                  "specialCabFlags",
                  "dominantTimeout",
                  "dominantRecessiveDelay",  
                  "recessiveDominantDelay",
                  "connectionInfo",
                  "currentlyAvailableTimestamps",
                  "minimalSupplyVoltage",
                  "maximalSupplyVoltage",
                  "maximalBaudrate",   
                  "fpgaCoreCapabilities",
                  "specialDeviceStatus",
                  "channelBusActiveCapabilities",
                  "breakOffset",       
                  "delimiterOffset",
                  "reserved");
      }
      public XLchannelConfig() {
          super();
          read();
      }
       @Override
          protected void allocateMemory() {
              super.allocateMemory();
          }
      public XLchannelConfig(Pointer pointer) {
          super();
          useMemory(pointer);
          read();
      }
      
      public static class ByReference extends XLchannelConfig implements Structure.ByReference {
          public ByReference(){
              super();
              read();
          }
          public ByReference(Pointer p) { super(p);
          ensureAllocated();
          useMemory(p);
          byte[] buffer = new byte[size()];
          this.getPointer().read(0, buffer, 0, buffer.length);
          getPointer().write(0, buffer, 0, buffer.length);
          read();}
      };

      public static class ByValue extends XLchannelConfig implements Structure.ByValue {
          public ByValue() {
              super();
              read();
          }
          public ByValue(Pointer p) { super(p);
          useMemory(p);
          read();}
      };
  }

public class UnsignedInt extends IntegerType {
      public UnsignedInt() {
           super(4, false);
      }
  }

public static class XLbusParams extends Structure{
      public int busType;
      public Data data;
}
public static class Data extends Union{
        public Can can;
}

public static class Can extends Structure{
      public int bitRate;
      public byte sjw;
      public byte tseg1;
      public byte tseg2;
      public byte sam; // 1 or 3
      public byte outputMode;
      public byte[] reserved = new byte[7];
      public byte canOpMode;
}

我有示例 c 代码,它读取 dll 并且它获取正确的值,但使用 JNA 它没有给出正确的输出值。结构映射正确还是我遗漏了什么?

C 代码的实际输出:

  • 02 channel 硬件配置 -
  • Ch:00,CM:0x001,虚拟 channel 1,无出租车!
  • Ch:01,CM:0x002,虚拟 channel 2,无 Cab!

上述映射的输出:

  • 2 channel 硬件配置 -

  • Ch:01,CM:0x000,虚拟 channel 1 无出租车!

  • Ch:00,CM:0x000,虚拟 channel 2 无 Cab!

    Daniel Widdis 建议您,如果我可以将 UnsignedInt 更改为 int,将 XLuint64 更改为 long,输出如下

  • 2 channel 硬件配置 -

  • Ch:00,CM:0x1000000070000,虚拟 channel 1 无出租车!

  • Ch:700,CM:0x1010001000100,所有 channel 2

合并代码:

package load;
import java.util.Arrays;
import java.util.List;

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.Union;

public interface VxLib extends Library{
    public static int XL_CONFIG_MAX_CHANNELS = 64;
    public static int XL_MAX_LENGTH          = 41;
    VxLib INSTANCE = (VxLib) Native.load((Platform.isWindows() ? "vxlapi64" : "vxlapi64Port"), VxLib.class);
    int xlOpenDriver();
    int xlGetDriverConfig(s_xl_driver_config pDriverConfig);
    String xlGetErrorString(int status);
    public static class s_xl_driver_config extends Structure {
        public int dllVersion;
        public int channelCount;
        public int[] reserved = new int[4];
        public XLchannelConfig[] channel = new XLchannelConfig[XL_CONFIG_MAX_CHANNELS];
        public s_xl_driver_config() {
            super();
            read();
        }
        public s_xl_driver_config(Pointer p) {
            super(p);
            read();
        }
        protected List<String> getFieldOrder() {
            return Arrays.asList("dllVersion", "channelCount", "reserved", "channel");
        }
        /**
         * @param channelCount total number of channels<br>
         * @param reserved C type : unsigned int[10]<br>
         * @param channel [channelCount]<br>
         * C type : XLchannelConfig[64]
         */
        public s_xl_driver_config(int dllVersion, int channelCount, int reserved[], XLchannelConfig channel[]) {
            super();
            this.dllVersion = dllVersion;
            this.channelCount = channelCount;
            if ((reserved.length != this.reserved.length)) 
                throw new IllegalArgumentException("Wrong array size !");
            this.reserved = reserved;
            if ((channel.length != this.channel.length)) 
                throw new IllegalArgumentException("Wrong array size !");
            this.channel = channel;
        }
        public static class ByReference extends s_xl_driver_config implements Structure.ByReference {
            
        };
        public static class ByValue extends s_xl_driver_config implements Structure.ByValue {
            
        };
    };
    
    public static class XLchannelConfig extends Structure {
        public byte[] name = new byte[XL_MAX_LENGTH + 1];
        public byte hwType;
        public byte hwIndex;
        public byte hwChannel;
        public short transceiverType;
        public int transceiverState;
        public byte channelIndex;
        public long channelMask;
        public int channelCapabilities;
        public int channelBusCapabilities;
        public byte isOnBus;
        public int connectedBusType;
        public XLbusParams busParams;
        public int driverVersion;
        public int interfaceVersion;
        public int[] raw_data = new int[7];
        public int serialNumber;
        public int articleNumber;
        public byte[] transceiverName = new byte[XL_MAX_LENGTH + 1];
        public int specialCabFlags;
        public int dominantTimeout;
        public int[] reserved = new int[7];
        public XLchannelConfig() {
            super();
            read();
        }
        public XLchannelConfig(Pointer p) {
            super(p);
            read();
        }
        protected List<String> getFieldOrder() {
            return Arrays.asList("name", "hwType", "hwIndex", "hwChannel", "transceiverType", "transceiverState", "channelIndex", "channelMask", "channelCapabilities", "channelBusCapabilities", "isOnBus", "connectedBusType", "busParams", "driverVersion", "interfaceVersion", "raw_data", "serialNumber", "articleNumber", "transceiverName", "specialCabFlags", "dominantTimeout", "reserved");
        }
        public static class ByReference extends XLchannelConfig implements Structure.ByReference {
            
        };
        public static class ByValue extends XLchannelConfig implements Structure.ByValue {
            
        };
    };
    
    public static class XLbusParams extends Structure {
        public int busType;
        /** C type : data_union */
        public data_union data;
        /** <i>native declaration : line 23</i> */
        public static class data_union extends Union {
            /** C type : can_struct */
            public can_struct can;
            /** C type : canFD_struct */
            public canFD_struct canFD;
            /** C type : most_struct */
            public most_struct most;
            /** C type : flexray_struct */
            public flexray_struct flexray;
            /** C type : ethernet_struct */
            public ethernet_struct ethernet;
            /** C type : a429_struct */
            public a429_struct a429;
            /** C type : unsigned char[28] */
            public byte[] raw = new byte[28];
            /** <i>native declaration : line 24</i> */
            public static class can_struct extends Structure {
                public int bitRate;
                public byte sjw;
                public byte tseg1;
                public byte tseg2;
                /** 1 or 3 */
                public byte sam;
                public byte outputMode;
                /** C type : unsigned char[7] */
                public byte[] reserved = new byte[7];
                public byte canOpMode;
                public can_struct() {
                    super();
                    setAlignType(ALIGN_GNUC);
                    read();
                }
                public can_struct(Pointer p) {
                    super(p);
                    read();
                }
                protected List<String> getFieldOrder() {
                    return Arrays.asList("bitRate", "sjw", "tseg1", "tseg2", "sam", "outputMode", "reserved", "canOpMode");
                }
                /**
                 * @param sam 1 or 3<br>
                 * @param reserved C type : unsigned char[7]
                 */
                public can_struct(int bitRate, byte sjw, byte tseg1, byte tseg2, byte sam, byte outputMode, byte reserved[], byte canOpMode) {
                    super();
                    this.bitRate = bitRate;
                    this.sjw = sjw;
                    this.tseg1 = tseg1;
                    this.tseg2 = tseg2;
                    this.sam = sam;
                    this.outputMode = outputMode;
                    if ((reserved.length != this.reserved.length)) 
                        throw new IllegalArgumentException("Wrong array size !");
                    this.reserved = reserved;
                    this.canOpMode = canOpMode;
                }
                public static class ByReference extends can_struct implements Structure.ByReference {
                    
                };
                public static class ByValue extends can_struct implements Structure.ByValue {
                    
                };
            };
            /** <i>native declaration : line 34</i> */
            public static class canFD_struct extends Structure {
                public int arbitrationBitRate;
                public byte sjwAbr;
                public byte tseg1Abr;
                public byte tseg2Abr;
                public byte samAbr;
                public byte outputMode;
                public byte sjwDbr;
                public byte tseg1Dbr;
                public byte tseg2Dbr;
                public int dataBitRate;
                public byte canOpMode;
                public canFD_struct() {
                    super();
                }
                protected List<String> getFieldOrder() {
                    return Arrays.asList("arbitrationBitRate", "sjwAbr", "tseg1Abr", "tseg2Abr", "samAbr", "outputMode", "sjwDbr", "tseg1Dbr", "tseg2Dbr", "dataBitRate", "canOpMode");
                }
                public static class ByReference extends canFD_struct implements Structure.ByReference {
                    
                };
                public static class ByValue extends canFD_struct implements Structure.ByValue {
                    
                };
            };
            /** <i>native declaration : line 47</i> */
            public static class most_struct extends Structure {
                public int activeSpeedGrade;
                public int compatibleSpeedGrade;
                public int inicFwVersion;
                public most_struct() {
                    super();
                }
                protected List<String> getFieldOrder() {
                    return Arrays.asList("activeSpeedGrade", "compatibleSpeedGrade", "inicFwVersion");
                }
                public most_struct(int activeSpeedGrade, int compatibleSpeedGrade, int inicFwVersion) {
                    super();
                    this.activeSpeedGrade = activeSpeedGrade;
                    this.compatibleSpeedGrade = compatibleSpeedGrade;
                    this.inicFwVersion = inicFwVersion;
                }
                public static class ByReference extends most_struct implements Structure.ByReference {
                    
                };
                public static class ByValue extends most_struct implements Structure.ByValue {
                    
                };
            };
            /** <i>native declaration : line 52</i> */
            public static class flexray_struct extends Structure {
                public int status;
                public int cfgMode;
                public int baudrate;
                public flexray_struct() {
                    super();
                }
                protected List<String> getFieldOrder() {
                    return Arrays.asList("status", "cfgMode", "baudrate");
                }
                public flexray_struct(int status, int cfgMode, int baudrate) {
                    super();
                    this.status = status;
                    this.cfgMode = cfgMode;
                    this.baudrate = baudrate;
                }
                public static class ByReference extends flexray_struct implements Structure.ByReference {
                    
                };
                public static class ByValue extends flexray_struct implements Structure.ByValue {
                    
                };
            };
            /** <i>native declaration : line 57</i> */
            public static class ethernet_struct extends Structure {
                /** C type : unsigned char[6] */
                public byte[] macAddr = new byte[6];
                public byte connector;
                public byte phy;
                public byte link;
                public byte speed;
                public byte clockMode;
                public byte bypass;
                public ethernet_struct() {
                    super();
                }
                protected List<String> getFieldOrder() {
                    return Arrays.asList("macAddr", "connector", "phy", "link", "speed", "clockMode", "bypass");
                }
                /** @param macAddr C type : unsigned char[6] */
                public ethernet_struct(byte macAddr[], byte connector, byte phy, byte link, byte speed, byte clockMode, byte bypass) {
                    super();
                    if ((macAddr.length != this.macAddr.length)) 
                        throw new IllegalArgumentException("Wrong array size !");
                    this.macAddr = macAddr;
                    this.connector = connector;
                    this.phy = phy;
                    this.link = link;
                    this.speed = speed;
                    this.clockMode = clockMode;
                    this.bypass = bypass;
                }
                public static class ByReference extends ethernet_struct implements Structure.ByReference {
                    
                };
                public static class ByValue extends ethernet_struct implements Structure.ByValue {
                    
                };
            };
            /** <i>native declaration : line 66</i> */
            public static class a429_struct extends Structure {
                public short channelDirection;
                public short res1;
                /** C type : dir_union */
                public dir_union dir;
                /** <i>native declaration : line 69</i> */
                public static class dir_union extends Union {
                    /** C type : tx_struct */
                    public tx_struct tx;
                    /** C type : rx_struct */
                    public rx_struct rx;
                    /** C type : unsigned char[24] */
                    public byte[] raw = new byte[24];
                    /** <i>native declaration : line 70</i> */
                    public static class tx_struct extends Structure {
                        public int bitrate;
                        public int parity;
                        public int minGap;
                        public tx_struct() {
                            super();
                        }
                        protected List<String> getFieldOrder() {
                            return Arrays.asList("bitrate", "parity", "minGap");
                        }
                        public tx_struct(int bitrate, int parity, int minGap) {
                            super();
                            this.bitrate = bitrate;
                            this.parity = parity;
                            this.minGap = minGap;
                        }
                        public static class ByReference extends tx_struct implements Structure.ByReference {
                            
                        };
                        public static class ByValue extends tx_struct implements Structure.ByValue {
                            
                        };
                    };
                    /** <i>native declaration : line 75</i> */
                    public static class rx_struct extends Structure {
                        public int bitrate;
                        public int minBitrate;
                        public int maxBitrate;
                        public int parity;
                        public int minGap;
                        public int autoBaudrate;
                        public rx_struct() {
                            super();
                        }
                        protected List<String> getFieldOrder() {
                            return Arrays.asList("bitrate", "minBitrate", "maxBitrate", "parity", "minGap", "autoBaudrate");
                        }
                        public rx_struct(int bitrate, int minBitrate, int maxBitrate, int parity, int minGap, int autoBaudrate) {
                            super();
                            this.bitrate = bitrate;
                            this.minBitrate = minBitrate;
                            this.maxBitrate = maxBitrate;
                            this.parity = parity;
                            this.minGap = minGap;
                            this.autoBaudrate = autoBaudrate;
                        }
                        public static class ByReference extends rx_struct implements Structure.ByReference {
                            
                        };
                        public static class ByValue extends rx_struct implements Structure.ByValue {
                            
                        };
                    };
                    public dir_union() {
                        super();
                    }
                    /** @param raw C type : unsigned char[24] */
                    public dir_union(byte raw[]) {
                        super();
                        if ((raw.length != this.raw.length)) 
                            throw new IllegalArgumentException("Wrong array size !");
                        this.raw = raw;
                        setType(byte[].class);
                    }
                    /** @param tx C type : tx_struct */
                    public dir_union(tx_struct tx) {
                        super();
                        this.tx = tx;
                        setType(tx_struct.class);
                    }
                    /** @param rx C type : rx_struct */
                    public dir_union(rx_struct rx) {
                        super();
                        this.rx = rx;
                        setType(rx_struct.class);
                    }
                    public static class ByReference extends dir_union implements Structure.ByReference {
                        
                    };
                    public static class ByValue extends dir_union implements Structure.ByValue {
                        
                    };
                };
                public a429_struct() {
                    super();
                }
                protected List<String> getFieldOrder() {
                    return Arrays.asList("channelDirection", "res1", "dir");
                }
                /** @param dir C type : dir_union */
                public a429_struct(short channelDirection, short res1, dir_union dir) {
                    super();
                    this.channelDirection = channelDirection;
                    this.res1 = res1;
                    this.dir = dir;
                }
                public static class ByReference extends a429_struct implements Structure.ByReference {
                    
                };
                public static class ByValue extends a429_struct implements Structure.ByValue {
                    
                };
            };
            public data_union() {
                super();
            }
            public data_union(Pointer p) {
                super(p);
                read();
            }
            /** @param raw C type : unsigned char[28] */
            public data_union(byte raw[]) {
                super();
                if ((raw.length != this.raw.length)) 
                    throw new IllegalArgumentException("Wrong array size !");
                this.raw = raw;
                setType(byte[].class);
            }
            /** @param most C type : most_struct */
            public data_union(most_struct most) {
                super();
                this.most = most;
                setType(most_struct.class);
            }
            /** @param a429 C type : a429_struct */
            public data_union(a429_struct a429) {
                super();
                this.a429 = a429;
                setType(a429_struct.class);
            }
            /** @param canFD C type : canFD_struct */
            public data_union(canFD_struct canFD) {
                super();
                this.canFD = canFD;
                setType(canFD_struct.class);
            }
            /** @param flexray C type : flexray_struct */
            public data_union(flexray_struct flexray) {
                super();
                this.flexray = flexray;
                setType(flexray_struct.class);
            }
            /** @param ethernet C type : ethernet_struct */
            public data_union(ethernet_struct ethernet) {
                super();
                this.ethernet = ethernet;
                setType(ethernet_struct.class);
            }
            /** @param can C type : can_struct */
            public data_union(can_struct can) {
                super();
                this.can = can;
                setType(can_struct.class);
            }
            public static class ByReference extends data_union implements Structure.ByReference {
                
            };
            public static class ByValue extends data_union implements Structure.ByValue {
                
            };
        };
        public XLbusParams() {
            super();
        }
        public XLbusParams(Pointer p) {
            super(p);
            read();
        }
        protected List<String> getFieldOrder() {
            return Arrays.asList("busType", "data");
        }
        /** @param data C type : data_union */
        public XLbusParams(short busType, data_union data) {
            super();
            this.busType = busType;
            this.data = data;
        }
        public static class ByReference extends XLbusParams implements Structure.ByReference {
            
        };
        public static class ByValue extends XLbusParams implements Structure.ByValue {
            
        };
    };
}

输出:

--------------------------------------------------
- 2 channels       Hardware Configuration       -
--------------------------------------------------
- Ch:00 , CM: 0x001 , Virtual Channel 1    no Cab!   
- Ch:01 , CM: 0x000 , Virtual Channel 2    no Cab!  

最佳答案

正如我在评论线程中指出的,您错误地对 8 字节结构元素 XLuint64 使用 4 字节映射 (UnsignedInt)。应将其替换为 8 字节变量(例如 long)。虽然技术上是正确的,但为每个无符号 int 值创建一个对象会产生大量开销,因此简化结构并仅放置 int 结构通常是一个好主意元素,并在解释值时处理无符号性。

您的示例输出显示第二个元素的 name 省略了字符 Virtu,这表明您的映射存在 5 个字节的偏差。

但是,您对 XLbusParams 的映射肯定是错误的。您正在使用 Union 来存储数据,但您只列出了一个恰好有 17 个字节的元素,因此这就是 JNA 用于确定 Union 大小的元素。鉴于添加了 4 字节 _donotuse 元素以使您的结构与新版本兼容,您需要一个 32 字节 XLbusParams 结构。 busType 占 4 个字节,这意味着您的 Union 需要占用 28 个字节。

“快速修复”是在联合体中添加第二个元素,即 28 字节数据字段,例如 public byte[] data = new byte[28];。这假设您始终处理 Can 内部类型,这可能适合您的用例。正确地,您应该映射联合内的所有不同类型并测试 busType 的值以了解您正在读取哪一种类型。此外,对于联合,您可能需要采取额外的步骤来实际读取数据。

要进一步进行故障排除,请使用 JNA StructuretoString() ,它将输出结构中所有原始元素的值(使用 int 的另一个优点long),并允许您将值逐个元素与预期的 C 输出对齐,以确定字节不匹配的位置。

关于java - 错误的输出来自 JNA 中的结构字段值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58839290/

相关文章:

java - 使用 JNA 设置 ProgramData 子文件夹的写入权限

java - 按给定四元数旋转单位 vector

java - Java如何创建主线程

java - JNA 无法加载模块 - 输出调试信息(依赖项)

java - JNA 中 SHChangeNotify 的正确映射

jvm - JNA 调用适用于 32 位 JRE,但不适用于 64 位 JRE

java - 具有结构 JNA 数组的结构

java - 如何等待任何工作线程完成?

Java.lang.String.contains() 方法与 ""字符串

java - 为什么当我在“你想订购多少”下有 "valid = true;"时,在 Debug模式下代码可以工作,但运行却不能?