一个有关于Java通过JNA调用dll程序,一个带数组结构体的接口无法调用的问题。
在尝试调用一个创芯科技公司的CAN通讯的dll程序,有一个接口方法需要放数组,但是这个数组的创建出了问题。
情况1.首先通过正常数组实例化的方式执行,会报异常“java.lang.IllegalArgumentException: Structure array elements must use contiguous memory (bad backing address at Structure array index 1)”,大概是说结构体数组的内存地址不连续。
情况2.后通过网上查阅资料得知要想获得内存地址连续的结构体数组,需要用到JNA包下Structure类的toArray()方法。但是在实际使用中又会报错java.lang.IllegalStateException: Array fields must be initialized,大概是说数组字段必须要实例化。
问题点:怎样才可以解决上面两种情况,或者有第三钟方法可以使之正常调用这个接口方法。
有关于dll文件和使用指引来源
https://www.zhcxgd.com/1.html
以下是当前调试的代码
public class CanUtil {
public interface testDlls extends Library {
// testDlls INSTANCE = (testDlls) Native.loadLibrary("ControlCAN", testDlls.class); // ControlCAN.dll
Integer VCI_OpenDevice(Integer DevType, Integer DevIndex, Integer Reserved);
Integer VCI_CloseDevice(Integer DevType, Integer DevIndex);
Integer VCI_Transmit(Integer DeviceType, Integer DeviceInd, Integer CANInd, VCI_CAN_OBJ[] pSend, Integer Length);
}
public static void main(String[] args) {
try {
testDlls dll = (testDlls) Native.loadLibrary("ControlCAN", testDlls.class); // ControlCAN.dll
System.out.println("2222");
//
// int result = dll.VCI_OpenDevice(4, 0, 0);
// System.out.println("result: " + result);
//
// result = dll.VCI_CloseDevice(4, 0);
// System.out.println("result: " + result);
// 数组容量
int cycle = 2;// 当数组容量为1 且 数组由正常数组实例化构成(method=false)时, 确认可执行通过, 下方result结果为0.
// 表示选择哪种方法
boolean method = true;
VCI_CAN_OBJ[] vco;
if (method) {
// 通过实体类继承的Structure类中的toArray(arraySize)方法获得连续存储地址的数组, 但是会报错说没有被实例化
vco = (VCI_CAN_OBJ[]) new VCI_CAN_OBJ().toArray(cycle);// <<---- 就是在这里发生报错: java.lang.IllegalStateException: Array fields must be initialized
} else {
// 正常的数组实例, 但是会报错说数组内存地址不是连续的
vco = new VCI_CAN_OBJ[cycle];// <<---- 会在下面调用接口方法的时候发生报错: java.lang.IllegalArgumentException: Structure array elements must use contiguous memory (bad backing address at Structure array index 1)
}
// 通过遍历数组进行数据保存
for (int i = 0; i < cycle; i++) {
vco[i] = new VCI_CAN_OBJ();
vco[i].ID = (byte)i;
vco[i].RemoteFlag = (byte)0;
vco[i].ExternFlag = (byte)0;
vco[i].DataLen = (byte)1;
byte[] data = new byte[1];
data[0] = 0x66;
vco[i].Data = data;
}
Integer result = -2;
result = dll.VCI_Transmit(4, 0, 0, vco, cycle);
System.out.println("result: " + result);
} catch (Exception e) {
// TODO: handle exception
System.out.println(e.toString());
e.printStackTrace();
}
}
}
以下是结构体代码:
public class VCI_CAN_OBJ extends Structure {
public byte ID;
public byte RemoteFlag;
public byte ExternFlag;
public byte DataLen;
public byte[] Data;
public VCI_CAN_OBJ() {};
public static class ByReference extends VCI_CAN_OBJ implements Structure.ByReference {}
public static class ByValue extends VCI_CAN_OBJ implements Structure.ByValue {}
//定义取值次序,需要与C/C++中对齐,不然会出现NoSuchFieldError
@Override
protected List getFieldOrder() {
return Arrays.asList(new String[]{"ID", "RemoteFlag", "ExternFlag", "DataLen", "Data"});
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("ID: " + this.ID + ", ");
sb.append("RemoteFlag: " + this.RemoteFlag + ", ");
sb.append("ExternFlag: " + this.ExternFlag + ", ");
sb.append("DataLen: " + this.DataLen + ", ");
if (this.Data != null) {
sb.append(" { ");
for(byte unit : Data) {
sb.append(unit + ", ");
}
sb.replace(sb.length()-2, sb.length(), " } ");
}
return sb.toString();
}
}