Bootstrap

JNA传入char[][]和具有联合体结构对象数组

工作中根据施工现场需要,我们需要通过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);
}

贴吧啥的求助好几天没人回答,在此发文,希望对同行们有所帮助!

;