工作中根据施工现场需要,我们需要通过API接口获取对方系统内数据,但是API接口方法参数如下:
DWORD getSnapshot(DBPH h, char Names[][80],TVVAL tvs[],int size)
其中包含了char的双重数组,一个包含联合体的对象数组(该数组传入后,返回数据)。
联合体数据对象如下:
typedef struct t_vval //变体结构
{
DWORD vt;
long len;
union
{
long lval;
float fval;
__int64 llval;
double dblval;
};
long time;
short snerr;
}TVVAL,*LPVVAL;
原理我也不多讲(深究我也不会,能用就行2333),我直接说一下char双重数组和联合体对象我是如何解决的:
java实现C接口方法如下:
int DBP_GetSnapshot(Pointer h, byte[] Names, TVVAL tvs[], int nsize);
char[][]:
char[][]传输和char**是不同的,我开始时使用的string[]去尝试,发现对方厂家打印的Names名称居然是表示地址的乱码字符串。
问了下公司C语言部门的同事,他建议:直接用java把每个字符串转化为固定长度的byte[],将byte数组传入,C语言接收char[][]数据的时候要的是值并不是内存地址。经过实践发现该方法是可行的,对方的程序能够正确打印Names字段里的数据内容。
联合体结构:
联合体结构我按照网上搜索的,写出了如下结构:
public class TVVAL extends Structure {// 变体结构
public int vt;
public int len;
public field1_union field1;
public int time;
public short snerr;
public static class field1_union extends Union {
public long lval;
public float fval;
public long llval ;
public double dblval;
}
public static class ByReference extends TVVAL implements Structure.ByReference {
}
public static class ByValue extends TVVAL implements Structure.ByValue {
}
@Override
protected List<String> getFieldOrder() {
return Arrays.asList(new String[] { "vt", "len", "field1", "time", "snerr" });
}
}
但是该结构可以传入,并且拿到前俩个值,但是到联合体结构后数据都没写入,我各种方法尝试老半天也不成功,与此同时协助我的同事突然发现了一个神奇的工具包JNAerator(参考网址:jnaerator:java调用动态库的神器,JNA代码自动生成工具_10km的专栏-CSDN博客),这玩意可以根据dll和so等文件直接生成jna对应的java类,尝试了下其生成的对象就可以让数据写入对象,java可以顺利取到数据,修改后的对象代码如下(相比于我的代码,多了一些声明方法,可能该方法可让jna将对象处理成C语言可写入的形式):
public class TVVAL extends Structure {// 变体结构
public int vt;
public int len;
public field1_union field1;
public int time;
public short snerr;
public static class field1_union extends Union {
public long lval;
public float fval;
public long llval ;
public double dblval;
public field1_union() {
super();
}
public field1_union(int lval) {
super();
this.lval = lval;
setType(Integer.TYPE);
}
public field1_union(float fval) {
super();
this.fval = fval;
setType(Float.TYPE);
}
public field1_union(long llval) {
super();
this.llval = llval;
setType(Long.TYPE);
}
public field1_union(double dblval) {
super();
this.dblval = dblval;
setType(Double.TYPE);
}
public static class ByReference extends field1_union implements Structure.ByReference {
};
public static class ByValue extends field1_union implements Structure.ByValue {
};
}
public static class ByReference extends TVVAL implements Structure.ByReference {
}
public static class ByValue extends TVVAL implements Structure.ByValue {
}
public TVVAL() {
super();
}
public TVVAL(int vt, int len, field1_union field1, int time, short snerr) {
super();
this.vt = vt;
this.field1 = field1;
this.time = time;
this.snerr = snerr;
}
public TVVAL(Pointer peer) {
super(peer);
}
@Override
protected List<String> getFieldOrder() {
return Arrays.asList(new String[] { "vt", "lvlen", "field1", "ltime", "snerr" });
}
}
在对象联合体内取值的方法如下:
private void getvalue(TVVAL tvval) {
int i = (Integer) tvval.readField("vt");
short err = (short) tvval.readField("snerr");
field1_union v = (field1_union) tvval.readField("field1");
System.out.println(v.lval);
System.out.println(v.fval);
System.out.println(v.llval);
System.out.println(v.dblval);
}
贴吧啥的求助好几天没人回答,在此发文,希望对同行们有所帮助!