Java调用C/C++动态链接库函数,当传递参数为结构体且结构体存在数组的情况时,则传参的数组长度要和C/C++语言定义的长度一致。
import java.util.ArrayList;
import java.util.List;
import com.sun.jna.Structure;
/**
*
* @author XIVA
*
*/
public class DevInfo extends Structure
{
public byte[] pProtocolType = new byte[20];
public int nDevType = 0;
public byte[] pDevIP = new byte[20];
public int nDevPort = 0;
public byte[] pDevUsername = new byte[64];
public byte[] pDevPassword = new byte[64];
public byte[] pVendorType = new byte[20];
public static class ByReference extends HwDevInfo implements Structure.ByReference
{
}
public static class ByValue extends HwDevInfo implements Structure.ByValue
{
}
@Override
protected List<String> getFieldOrder()
{
List<String> fieldOrderList = new ArrayList<String>();
fieldOrderList.add("pProtocolType");
fieldOrderList.add("nDevType");
fieldOrderList.add("pDevIP");
fieldOrderList.add("nDevPort");
fieldOrderList.add("pDevUsername");
fieldOrderList.add("pDevPassword");
fieldOrderList.add("pVendorType");
return fieldOrderList;
}
}
接口声明:
public int Camera_AddDevice(String pTargetDomainCode, String pTargetDevGroupID, DevInfo.ByReference pDevInfo, byte[] pDevCode);
结构体声明:
typedef struct _DevInfo { char pProtocolType[20]; int nDevType; char pDevIP[20]; int nDevPort; char pDevUsername[64]; char pDevPassword[64]; char pVendorType[20]; _DevInfo() { nDevPort = 0; nDevType = 0; ZeroMemory(pProtocolType, sizeof(pProtocolType)); ZeroMemory(pDevIP, sizeof(pDevIP)); ZeroMemory(pDevUsername, sizeof(pDevUsername)); ZeroMemory(pDevPassword, sizeof(pDevPassword)); ZeroMemory(pVendorType, sizeof(pVendorType)); } }DEVINFO, *LPDEVINFO;
#define JNAAPI extern "C" _declspec(dllexport) JNAAPI int Camera_AddDevice(const char * pTargetDomainCode, const char * pTargetDevGroupID, LPDEVINFO pDevInfo, OUT char * pDevCode);
声明了以上函数后,就是JAVA调用了。
DevInfo.ByReference pDevInfo = new DevInfo.ByReference();
byte[] ipBytes = "127.0.0.1".getBytes();
byte[] pDevUsernameBytes = "admin".getBytes();
byte[] pDevPasswordBytes = "admin".getBytes();
byte[] pVendorTypeBytes = "xxx".getBytes();
byte[] pProtocolTypeBytes = "xxx".getBytes();
System.arraycopy(ipBytes, 0, pDevInfo.pDevIP, 0, Math.min(ipBytes.length, pDevInfo.pDevIP.length));
System.arraycopy(pDevUsernameBytes, 0, pDevInfo.pDevUsername, 0, Math.min(ipBytes.length, pDevInfo.pDevUsername.length));
System.arraycopy(pDevPasswordBytes, 0, pDevInfo.pDevPassword, 0, Math.min(ipBytes.length, pDevInfo.pDevPassword.length));
System.arraycopy(pVendorTypeBytes, 0, pDevInfo.pVendorType, 0, Math.min(ipBytes.length, pDevInfo.pVendorType.length));
System.arraycopy(pProtocolTypeBytes, 0, pDevInfo.pProtocolType, 0, Math.min(ipBytes.length, pDevInfo.pProtocolType.length));
pDevInfo.nDevPort = 8080;
pDevInfo.nDevType = 1;
String pDevCode = CommHWService.Camera_AddDevice("xxxx", "0", pDevInfo);
其中最为重要的代码是将值复制到声明的内存区域,
System.arraycopy(ipBytes, 0, pDevInfo.pDevIP, 0, Math.min(ipBytes.length, pDevInfo.pDevIP.length));
,而不是直接赋值:pDevInfo.pDevUsername = "admin".getBytes();
如果使用以下方式实现,内存会发生泄漏,导致JVM报错。
原因就是JVM声明的结构体和C端定义的结构体对应的内存区域大小不一致。
另外:
1、对象pDevInfo初始化的时候没有初始化其属性,则可以使用工具类Arrays的方法public static byte[] copyOf(byte[] original, int newLength)。
2、当传递参数为结构体数组时,我们需要使用连续的内存区域。可以使用反射类Array来初始化对象。如:((DevInfo[])Array.newInstance(DevInfo.class, 10));
参考:http://tcspecial.iteye.com/blog/1665583