如何使用JNA将包含结构数组的结构传递给C ++函数?

时间:2015-04-01 23:51:16

标签: java windows struct jna

我正在构建一个Java应用程序,它使用JNA与特定制造商的API进行通信。我有大量的函数调用映射并且已经有效,但是有一对函数让我有些悲伤。

这两个函数都来回传递数据结构以配置设备。该结构在其中具有嵌套的数据结构数组。

原生定义:

VISION_API_DECL BOOL VISION_API SetDeviceParameters( DWORD DeviceID, DeviceParameters  DeviceParam );
VISION_API_DECL BOOL VISION_API GetDeviceParameters( DWORD DeviceID, DeviceParameters  *DeviceParam );

我在Java中声明它们是这样的:

public interface Driver extends Library {
    ...
    public boolean SetDeviceParameters(int DeviceID, DEVICE_PARAMETERS DeviceParam);
    public boolean GetDeviceParameters(int DeviceID, DEVICE_PARAMETERS DeviceParam);
    ...
}

这些函数调用似乎可以正常工作。当我调用其中任何一个函数时,JNA不会抛出异常。当我调用GetDeviceParameters方法并打印出结构时,我看到其中大部分都填充了我认为是设备默认配置的数据。但是,当我使用刚刚从get调用返回的相同数据调用SetDeviceParameters方法时,设备会返回错误,指出参数错误。

我如何知道我是否正确映射了结构?

本机:

typedef struct _DeviceParameters
{
  BOOL bMICREnable;
  UINT nMICRFont;
  BOOL bMICRSaveSamples;
  UINT nMICRSpaces;
  char cRejectSymbol;
  UINT nReserved;
  BOOL bReserved;
  IMAGE_PROPERTIES  ImagePropertiesFront1;
  IMAGE_PROPERTIES  ImagePropertiesFront2;
  IMAGE_PROPERTIES  ImagePropertiesRear1;
  IMAGE_PROPERTIES  ImagePropertiesRear2;
  SNIPPET_PROPERTIES SnippetProperties[10];
  BOOL bPrintEnable;
  BOOL bOneDoc;
  UINT nFeedingMode;
} DeviceParameters;

typedef struct _SnippetProperties
{
  BOOL Enable;
  BOOL Front;
  Snippet Properties;
} SNIPPET_PROPERTIES;

typedef struct _Snippet
{
  UINT Xposition;
  UINT Yposition;
  UINT Width;
  UINT Height;
  UINT Orientation;
  UINT Color;
  UINT Compression;
  BOOL Millimeters;
} Snippet;

typedef struct _ImageProperties
{
  UINT Format;
  UINT Paging;
  UINT Resolution;
  UINT ColorDepth;
  UINT Threshold;
} IMAGE_PROPERTIES;

爪哇:

public class DEVICE_PARAMETERS extends Structure {
    public boolean bMICREnable;
    public int nMICRFont;
    public boolean bMICRSaveSamples;
    public int nMICRSpaces;
    public byte cRejectSymbol;
    public int nReserved;
    public boolean bReserved;
    public IMAGE_PROPERTIES ImagePropertiesFront1;
    public IMAGE_PROPERTIES ImagePropertiesFront2;
    public IMAGE_PROPERTIES ImagePropertiesRear1;
    public IMAGE_PROPERTIES ImagePropertiesRear2;
    public SNIPPET_PROPERTIES[] SnippetProperties = new SNIPPET_PROPERTIES[10];
    public boolean bPrintEnable;
    public boolean bOneDoc;
    public int nFeedingMode;

    @Override
    protected List getFieldOrder() {
        return Arrays.asList(
                "bMICREnable"
                , "nMICRFont"
                , "bMICRSaveSamples"
                , "nMICRSpaces"
                , "cRejectSymbol"
                , "nReserved"
                , "bReserved"
                , "ImagePropertiesFront1"
                , "ImagePropertiesFront2"
                , "ImagePropertiesRear1"
                , "ImagePropertiesRear2"
                , "SnippetProperties"
                , "bPrintEnable"
                , "bOneDoc"
                , "nFeedingMode"
        );
    }
}

public class IMAGE_PROPERTIES extends Structure {
    public int Format;
    public int Paging;
    public int Resolution;
    public int ColorDepth;
    public int Threshold;

    @SuppressWarnings("RedundantArrayCreation")
    @Override
    protected List getFieldOrder() {
        return Arrays.asList(
                new String[]{
                        "Format"
                        , "Paging"
                        , "Resolution"
                        , "ColorDepth"
                        , "Threshold"
                }
        );
    }
}

public class SNIPPET_PROPERTIES extends Structure {
    public boolean Enable;
    public boolean Front;
    public SNIPPET Properties = new SNIPPET();

    @Override
    protected List getFieldOrder() {
        return Arrays.asList("Enable", "Front", "Properties");
    }
}

public class SNIPPET extends Structure {

    public int Xposition;
    public int Yposition;
    public int Width;
    public int Height;
    public int Orientation;
    public int Color;
    public int Compression;
    public boolean Millimeters;

    @Override
    protected List getFieldOrder() {
        return Arrays.asList("Xposition"
                , "Yposition"
                , "Width"
                , "Height"
                , "Orientation"
                , "Color"
                , "Compression"
                , "Millimeters"
        );
    }
}

输出:

DEVICE_PARAMETERS(auto-allocated@0x16a25938 (520 bytes)) {
  boolean bMICREnable@0=false
  int nMICRFont@4=1
  boolean bMICRSaveSamples@8=false
  int nMICRSpaces@c=2
  byte cRejectSymbol@10=3f
  int nReserved@14=0
  boolean bReserved@18=false
  IMAGE_PROPERTIES ImagePropertiesFront1@1c=IMAGE_PROPERTIES(allocated@0x16a25954 (20 bytes) (shared from auto-allocated@0x16a25938 (520 bytes))) {
    int Format@0=0
    int Paging@4=0
    int Resolution@8=0
    int ColorDepth@c=0
    int Threshold@10=0
  }
  IMAGE_PROPERTIES ImagePropertiesFront2@30=IMAGE_PROPERTIES(allocated@0x16a25968 (20 bytes) (shared from auto-allocated@0x16a25938 (520 bytes))) {
    int Format@0=0
    int Paging@4=0
    int Resolution@8=0
    int ColorDepth@c=0
    int Threshold@10=0
  }
  IMAGE_PROPERTIES ImagePropertiesRear1@44=IMAGE_PROPERTIES(allocated@0x16a2597c (20 bytes) (shared from auto-allocated@0x16a25938 (520 bytes))) {
    int Format@0=0
    int Paging@4=0
    int Resolution@8=0
    int ColorDepth@c=0
    int Threshold@10=0
  }
  IMAGE_PROPERTIES ImagePropertiesRear2@58=IMAGE_PROPERTIES(allocated@0x16a25990 (20 bytes) (shared from auto-allocated@0x16a25938 (520 bytes))) {
    int Format@0=0
    int Paging@4=0
    int Resolution@8=0
    int ColorDepth@c=0
    int Threshold@10=0
  }
  SNIPPET_PROPERTIES SnippetProperties[10]@6c=[Lpanini.data.SNIPPET_PROPERTIES;@fb642f
  boolean bPrintEnable@1fc=false
  boolean bOneDoc@200=false
  int nFeedingMode@204=1
}
memory dump
[00000000]
[01000000]
[00000000]
[02000000]
[3f000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[01000000]
Device Error: Wrong device parameters <-- this is where I try to set params

1 个答案:

答案 0 :(得分:1)

你没有包含你的方法声明,它应该是这样的(假设你没有简单地在声明中输入错误):

boolean SetDeviceParameters(int deviceID, DeviceParameters.ByValue params);
boolean GetDeviceParameters(int deviceID, DeviceParameters params);

确保在传递给Structure.ByValue方法时使用标记为SetDeviceParameters()的结构版本。您需要定义结构的ByValue版本。

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

然后,您可以将struct *转换为struct,如下所示:

DeviceParameters dp = new DeviceParameters();
DeviceParameters.ByValue bv = new DeviceParameters.ByValue(dp.getPointer());