在Java中调用动态链接库(.dll),不考虑性能的话用JNA比用JNI要方便多了,只需要做数据映射之后再将导出函数声明一下就行了。下面分享一下通过JNA在Java中模拟联合体(Union)的经验。
示例来源于某CAN接口卡的开发库:
typedef struct tagZCAN_CHANNEL_INIT_CONFIG {
UINT can_type; // 0:can 1:canfd
union
{
struct
{
UINT acc_code;
UINT acc_mask;
UINT reserved;
BYTE filter;
BYTE timing0;
BYTE timing1;
BYTE mode;
}can;
struct
{
UINT acc_code;
UINT acc_mask;
UINT abit_timing;
UINT dbit_timing;
UINT brp;
BYTE filter;
BYTE mode;
USHORT pad;
UINT reserved;
}canfd;
};
}ZCAN_CHANNEL_INIT_CONFIG;
根据JNA的帮助文档:
Unions are generally interchangeable with Structures, but require that you indicate which union field is active with the setType method before it can be properly passed to a function call.
我们在模拟联合体时需要用setType方法来指定激活哪一个字段。我个人的理解是由于Java中压根儿就没有共用内存这种做法,所以通过不同内存上的字段来模拟,进而需要先告诉程序我们要用哪段内存(哪一个字段)。
注意:帮助文档中没有提及重写read和write方法,但这是必不可少的,并且setType方法就应该写在这俩里面。
下面给出相应的Java示例代码以供参考:
@Structure.FieldOrder({"can_type", "cfg_union"})
public class ZCAN_CHANNEL_INIT_CONFIG extends Structure {
public int can_type;
public tagCfg_union cfg_union;
public static class ByValue extends ZCAN_CHANNEL_INIT_CONFIG implements Structure.ByValue{}
public static class ByReference extends ZCAN_CHANNEL_INIT_CONFIG implements Structure.ByReference{}
public static class tagCfg_union extends Union {
public tagCan can;
public tagCanfd canfd;
@Structure.FieldOrder({"acc_code", "acc_mask", "reserved", "filter", "timing0", "timing1", "mode"})
public static class tagCan extends Structure {
public int acc_code;
public int acc_mask;
public int reserved;
public byte filter;
public byte timing0;
public byte timing1;
public byte mode;
}
@Structure.FieldOrder({"acc_code", "acc_mask", "abit_timing", "dbit_timing", "brp", "filter", "mode", "pad", "reserved"})
public static class tagCanfd extends Structure {
public int acc_code;
public int acc_mask;
public int abit_timing;
public int dbit_timing;
public int brp;
public byte filter;
public byte mode;
public short pad;
public int reserved;
}
}
@Override
public void read() {
super.read();
switch(can_type) {
case 0:
cfg_union.setType(tagCan.class);
break;
case 1:
cfg_union.setType(tagCanfd.class);
break;
}
cfg_union.read();
}
@Override
public void write() {
super.write();
switch(can_type) {
case 0:
cfg_union.setType(tagCan.class);
break;
case 1:
cfg_union.setType(tagCanfd.class);
break;
}
cfg_union.write();
}
}
类命名不规范(有的首字母未大写),请忽略,hh