JNA使用总结
1. JDK版本的位数,必须与DLL的位数相配,否则回如下错误
"Exception in thread “main” Java.lang.UnsatisfiedLinkError: Unable to load library ‘RWBIF.dll’: 找不到指定的模块。"
2. JAVA DLL 路径指定
- sample1:对应的DLL要放在编译的bin目录下
public static String DEFAULT_NXT_DLL_NAME = "RWBIF"; NxtService nxtServiceInstance = Native.loadLibrary(DEFAULT_NXT_DLL_NAME, NxtService.class);
- sample2:指定绝对路径
NxtManager.programName = "C:\\java\\code\\nxt_plus\\RWBIF.dll"; NxtService nxtServiceInstance = (NxtService) Native.loadLibrary(NxtManager.programName, NxtService.class);
3.使用jar包
// https://mvnrepository.com/artifact/net.java.dev.jna/jna
compile group: 'net.java.dev.jna', name: 'jna', version: '4.5.0'
1. Java 与JNA类型映射
http://java-native-access.github.io/jna/4.4.0/javadoc/overview-summary.html#structures
2. Java 与JNA基本类型映射
- char(c,c++,8it) —> byte(java,8bit)
C++
```
typedef struct _tag_RWBIF_PANELIDINFO_EX
{
TCHAR szBarcode[68];//typedefine char TCHAR
INT nLane;
} RWBIF_PANELIDINFO_EX, *PRWBIF_PANELIDINFO_EX;
```
Java:
public static class RWBIF_PANELIDINFO_EX extends Structure {
public byte[] szBarcode = new byte[68];
public int nLane;
@Override
protected List<String> getFieldOrder() {
// TODO Auto-generated method stub
return Arrays.asList(new String[] { "szBarcode", "nLane" });
}
}
[注]:fileOrder 必须按顺序填写
调用结构体结构体指针或结构体引用,要实现Structure.ByReference
直接传值 要实现Structure.ByValue
C++
typedef struct _tag_RWBIF_AUTO_JOB_CHG_RESULT
{
TCHAR szMcName[32];
DWORD dwErrorCode;
} RWBIF_AUTO_JOB_CHG_RESULT, *PRWBIF_AUTO_JOB_CHG_RESULT;
java 实现
public static class RWBIF_AUTO_JOB_CHG_RESULT extends Structure {
public static class ByReference extends RWBIF_AUTO_JOB_CHG_RESULT implements Structure.ByReference {
}
public static class ByValue extends RWBIF_AUTO_JOB_CHG_RESULT implements Structure.ByValue {
}
public byte[] szMcName = new byte[32];
public int dwErrorCode;
@Override
protected List<String> getFieldOrder() {
// TODO Auto-generated method stub
return Arrays.asList(new String[] { "szMcName", "dwErrorCode" });
}
}
复杂结构体,其成员函数包括结构体的指针或引用
C++
typedef struct _tag_RWBIF_HELPS_CHGOVERJOB
{
INT nLane;
RWBIF_JOBINFO_EX stJob;
} RWBIF_HELPS_CHGOVERJOB, *PRWBIF_HELPS_CHGOVERJOB;
其中 RWBIF_JOBINFO_EX 为另一个结构体,此处直接传值
java定义
public static class PRWBIF_HELPS_CHGOVERJOB extends Structure {
public static class ByReference extends PRWBIF_HELPS_CHGOVERJOB implements Structure.ByReference {
}
public static class ByValue extends PRWBIF_HELPS_CHGOVERJOB implements Structure.ByValue {
}
public int nLane;
public RWBIF_JOBINFO_EX stJob;
@Override
protected List<String> getFieldOrder() {
// TODO Auto-generated method stub
return Arrays.asList(new String[] { "nLane", "stJob" });
}
}
-
指针类型使用
int型指针
IntByReference -
3. 函数映射
结构体指针映射,可以用结构体数组代替
java中声明的接口必须与DLL一样,包括 返回值、函数名。类型映射以及参数名称都要一样
C++
typedef INT (*pChangeOverJob)(LPCTSTR szSrv, LPCTSTR szLine, LPCTSTR szEquip, INT nJobChgMode, INT nQty, INT nSize, PRWBIF_HELPS_CHGOVERJOB pArg);
此处 PRWBIF_HELPS_CHGOVERJOB 为结构体指针,在java映射中可以用结构体数组代替
java
int iChangeOverJob(String szSrv, String szLine, String szEquip, int nJobChgMode, int nQty, int nSize,
PRWBIF_HELPS_CHGOVERJOB[] pArg);
PRWBIF_HELPS_CHGOVERJOB[] pArg 为对应的入参
复杂参数:指针的引用,JNA参数替换
C++
typedef INT (*pGetAutoJobChgResult)(PRWBIF_AUTO_JOB_CHG_RESULT &rval);
其中 PRWBIF_AUTO_JOB_CHG_RESULT 为结构体指针,此处要用byReference[]数组代替
int iGetAutoJobChgResult(RWBIF_AUTO_JOB_CHG_RESULT.ByReference[] rval);
- 参考示例
JNA示例:C++类型映射
public interface NxtService extends Library {
/** The default nxt dll name. */
public static String DEFAULT_NXT_DLL_NAME = "RWBIF";
/**
* The Class _tag_RWBIF_PANELIDINFO_EX.
*/
public static class RWBIF_PANELIDINFO_EX extends Structure {
public byte[] szBarcode = new byte[68];
public int nLane;
@Override
protected List<String> getFieldOrder() {
// TODO Auto-generated method stub
return Arrays.asList(new String[] { "szBarcode", "nLane" });
}
}
public static class RWBIF_AUTO_JOB_CHG_RESULT extends Structure {
public static class ByReference extends RWBIF_AUTO_JOB_CHG_RESULT implements Structure.ByReference {
}
public static class ByValue extends RWBIF_AUTO_JOB_CHG_RESULT implements Structure.ByValue {
}
public byte[] szMcName = new byte[32];
public int dwErrorCode;
@Override
protected List<String> getFieldOrder() {
// TODO Auto-generated method stub
return Arrays.asList(new String[] { "szMcName", "dwErrorCode" });
}
}
public static class RWBIF_JOBINFO_EX extends Structure {
public static class ByReference extends RWBIF_JOBINFO_EX implements Structure.ByReference {
}
public static class ByValue extends RWBIF_JOBINFO_EX implements Structure.ByValue {
}
public byte[] szJobName = new byte[128];
public byte[] szRevision = new byte[16];
public int nSide;
@Override
protected List<String> getFieldOrder() {
// TODO Auto-generated method stub
return Arrays.asList(new String[] { "szJobName", "szRevision", "nSide" });
}
}
public static class PRWBIF_HELPS_CHGOVERJOB extends Structure {
public static class ByReference extends PRWBIF_HELPS_CHGOVERJOB implements Structure.ByReference {
}
public static class ByValue extends PRWBIF_HELPS_CHGOVERJOB implements Structure.ByValue {
}
public int nLane;
public RWBIF_JOBINFO_EX stJob;
@Override
protected List<String> getFieldOrder() {
// TODO Auto-generated method stub
return Arrays.asList(new String[] { "nLane", "stJob" });
}
}
int iSendBarcodeIdEx(String szSrv, String szLine, String szEquip, int nJobChgMode, int nQty, int nSize,
RWBIF_PANELIDINFO_EX[] pArg);
int iGetRecipeChgProgress(String szSrv, String szLine, String szEquip, IntByReference rdwStatus);
int iGetAutoJobChgEquipQty(IntByReference rnQty, String szSrv, String szLine, String szEquip);
void iDelGetAutoJobChgResult();
int iGetAutoJobChgResult(RWBIF_AUTO_JOB_CHG_RESULT.ByReference[] rval);
int iChangeOverJob(String szSrv, String szLine, String szEquip, int nJobChgMode, int nQty, int nSize,
PRWBIF_HELPS_CHGOVERJOB[] pArg);
}
JNA测试:
public class NxtManager {
public static String DEFAULT_NXT_PROPERTIES = "nxt.properties";
private static String programName;
private static String m_strRWBSeverPC;
private static String m_strLine;
private static String m_strEquip;
private static String barcodeID;
private static String lane;
private static String szJobName;
private static String version;
private static String nSide;
private static String encode;
static {
InputStream inputStream = Thread.currentThread().getContextClassLoader()
.getResourceAsStream(DEFAULT_NXT_PROPERTIES);
Properties properties = new Properties();
try {
properties.load(inputStream);
programName = properties.getProperty("programName");
m_strRWBSeverPC = properties.getProperty("server");
m_strLine = properties.getProperty("lineName");
m_strEquip = properties.getProperty("equipName");
barcodeID = properties.getProperty("barcodeId");
lane = properties.getProperty("lane");
szJobName = properties.getProperty("jobName");
version = properties.getProperty("revision");
nSide = properties.getProperty("side");
encode = properties.getProperty("encode");
System.setProperty("jna.encoding", encode);
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.format("load nxt properties failed.");
e.printStackTrace();
}
}
public void onChangeoverJob() {
NxtService nxtServiceInstance = (NxtService) Native.loadLibrary(NxtManager.programName, NxtService.class);
int nDataQty = 1;
int nIndex = 1;
System.out.println("init---------->set value:");
System.out.println("nLane:" + Integer.valueOf(NxtManager.lane));
System.out.println("szJobName:" + NxtManager.szJobName);
System.out.println("szRevision:" + NxtManager.version);
System.out.println("nSide:" + Integer.valueOf(NxtManager.nSide));
PRWBIF_HELPS_CHGOVERJOB[] prwbifHelpsChangeoverJob = (PRWBIF_HELPS_CHGOVERJOB[]) new NxtService.PRWBIF_HELPS_CHGOVERJOB()
.toArray(nDataQty);
prwbifHelpsChangeoverJob[0].nLane = Integer.valueOf(NxtManager.lane);
RWBIF_JOBINFO_EX.ByValue stJobRef = new RWBIF_JOBINFO_EX.ByValue();
stJobRef.nSide = Integer.valueOf(NxtManager.nSide);
//不能声明直接进行赋值,java 会截断数组长度
System.arraycopy(NxtManager.szJobName.getBytes(), 0, stJobRef.szJobName, 0, NxtManager.szJobName.getBytes().length);
System.arraycopy(NxtManager.version.getBytes(), 0, stJobRef.szRevision, 0, NxtManager.version.getBytes().length);
prwbifHelpsChangeoverJob[0].stJob = stJobRef;
System.out.println("init---------->set value:end");
int nJobChgMode = 1;
int nSize = 152;
System.out.println("iChangeOverJob---------->start");
int nRet = nxtServiceInstance.iChangeOverJob(NxtManager.m_strRWBSeverPC, NxtManager.m_strLine,
NxtManager.m_strEquip, nJobChgMode, nDataQty, nSize, prwbifHelpsChangeoverJob);
if (0 != nRet) {
System.out.format("API call [iChangeOverJob]: Error Code = %08x )", nRet);
return;
}
System.out.println("iChangeOverJob---------->end");
try {
System.out.format("睡眠7s");
Thread.sleep(TimeUnit.SECONDS.toMillis(7));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
}
while (true) {
IntByReference dwStatus = new IntByReference(0);
System.out.println("iGetRecipeChgProgress---------->LOOP");
nRet = nxtServiceInstance.iGetRecipeChgProgress(NxtManager.m_strRWBSeverPC, NxtManager.m_strLine,
NxtManager.m_strEquip, dwStatus);
if (0 != nRet) {
System.out.format("API call [iGetRecipeChgProgress]: Error Code = %08x )", nRet);
return;
}
int dwStatusValue = dwStatus.getValue();
if (2 == dwStatusValue) {
break;
}
try {
System.out.format("睡眠7s钟,等待状态为complete(2)");
Thread.sleep(TimeUnit.SECONDS.toMillis(7));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
}
}
System.out.println("iGetRecipeChgProgress---------->end,LOOP");
IntByReference rnQty = new IntByReference(0);
System.out.println("iGetAutoJobChgEquipQty---------->start");
nRet = nxtServiceInstance.iGetAutoJobChgEquipQty(rnQty, NxtManager.m_strRWBSeverPC, NxtManager.m_strLine,
NxtManager.m_strEquip);
if (0 != nRet) {
nxtServiceInstance.iDelGetAutoJobChgResult();
}
System.out.println("iGetAutoJobChgEquipQty---------->end");
int rnQtyValue = rnQty.getValue();
if (0 >= rnQtyValue) {
nxtServiceInstance.iDelGetAutoJobChgResult();
System.out.format("Error : Change over Result.(1)");
return;
}
RWBIF_AUTO_JOB_CHG_RESULT.ByReference[] pResult = (ByReference[]) new NxtService.RWBIF_AUTO_JOB_CHG_RESULT.ByReference()
.toArray(rnQtyValue);
System.out.println("iGetAutoJobChgResult---------->start");
nRet = nxtServiceInstance.iGetAutoJobChgResult(pResult);
if (0 != nRet) {
nxtServiceInstance.iDelGetAutoJobChgResult();
System.out.format("API call [iGetAutoJobChgEquipQty]: Error Code = %08x )", nRet);
return;
}
System.out.println("iGetAutoJobChgResult---------->end");
boolean bResultOK = false;
for (int i = 0; i < rnQtyValue; i++) {
System.out.println("iDelGetAutoJobChgResult---------->Loop");
String szMcNameStr = new String(pResult[i].szMcName);
if (NxtManager.m_strEquip.trim().equals(szMcNameStr.trim())) {
if (0 != pResult[i].dwErrorCode) {
nxtServiceInstance.iDelGetAutoJobChgResult();
System.out.format("Error Code = %08x" + pResult[i].dwErrorCode);
return;
}
bResultOK = true;
break;
}
}
System.out.println("iDelGetAutoJobChgResult---------->Loop end");
if (false == bResultOK) {
nxtServiceInstance.iDelGetAutoJobChgResult();
System.out.format("Error : Change over Result.(2)");
return;
}
nxtServiceInstance.iDelGetAutoJobChgResult();
System.out.format("Change over from job complete.");
return;
}
/*
* public static void main(String[] args) { NxtManager nxtManager = new
* NxtManager(); nxtManager.onChangeoverJob(); }
*/
public void OnChangeoverId() throws UnsupportedEncodingException {
System.out.println(System.getProperty("jna.encoding"));
NxtService nxtServiceInstance = (NxtService) Native.loadLibrary(NxtManager.programName, NxtService.class);
// String m_strRWBSeverPC = "10.187.0.54";
// String m_strLine = "H12";
// String m_strEquip = "NXT-H12";
int nJobChgMode = 1;
int nIndex = 1;
int nDataQty = 1;
int nSize = 140;
// set lane and barcode id
RWBIF_PANELIDINFO_EX[] pArg = (RWBIF_PANELIDINFO_EX[]) new NxtService.RWBIF_PANELIDINFO_EX().toArray(1);
pArg[0].szBarcode = NxtManager.barcodeID.getBytes();
pArg[0].nLane = Integer.valueOf(NxtManager.lane);
System.out.println("SendBarcodeId---------->start");
int nRet = nxtServiceInstance.iSendBarcodeIdEx(NxtManager.m_strRWBSeverPC, NxtManager.m_strLine,
NxtManager.m_strEquip, nJobChgMode, nDataQty, nSize, pArg);
if (0 != nRet) {
System.out.format("API call [iSendBarcodeIdEx]: Error Code = %08x )", nRet);
return;
}
System.out.println("SendBarcodeId---------->success");
try {
System.out.format("睡眠7s钟,等待状态为complete(2)");
Thread.sleep(TimeUnit.SECONDS.toMillis(7));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
}
while (true) {
IntByReference dwStatus = new IntByReference(0);
System.out.println("GetRecipeChgProgress---------->Loop");
nRet = nxtServiceInstance.iGetRecipeChgProgress(NxtManager.m_strRWBSeverPC, NxtManager.m_strLine,
NxtManager.m_strEquip, dwStatus);
if (0 != nRet) {
System.out.format("API call [iGetRecipeChgProgress]: Error Code = %08x )", nRet);
return;
}
int dwStatusValue = dwStatus.getValue();
if (2 == dwStatusValue) {
break;
}
try {
System.out.format("睡眠7s钟,等待状态为complete(2)");
Thread.sleep(TimeUnit.SECONDS.toMillis(7));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
}
}
System.out.println("GetRecipeChgProgress---------->loop end");
IntByReference rnQty = new IntByReference(0);
System.out.println("GetAutoJobChgEquipQty---------->start");
nRet = nxtServiceInstance.iGetAutoJobChgEquipQty(rnQty, NxtManager.m_strRWBSeverPC, NxtManager.m_strLine,
NxtManager.m_strEquip);
if (0 != nRet) {
System.out.format("API call [iGetAutoJobChgEquipQty]: Error Code = %08x )", nRet);
return;
}
System.out.println("GetAutoJobChgEquipQty---------->end");
// RWBIF_AUTO_JOB_CHG_RESULT rval = new
// NxtService.RWBIF_AUTO_JOB_CHG_RESULT();
int size = rnQty.getValue();
System.out.println("------------DEBUG------------->size" + size);
if (0 >= size) {
nxtServiceInstance.iDelGetAutoJobChgResult();
System.out.format("Error : Change over Result.(1)");
return;
}
// RWBIF_AUTO_JOB_CHG_RESULT.ByValue[] rval = (ByValue[]) new NxtService.RWBIF_AUTO_JOB_CHG_RESULT.ByValue().toArray(size);
RWBIF_AUTO_JOB_CHG_RESULT.ByReference[] rval = (ByReference[]) new NxtService.RWBIF_AUTO_JOB_CHG_RESULT.ByReference().toArray(size);
System.out.println("GetAutoJobChgResult---------->start");
// nRet = nxtServiceInstance.iGetAutoJobChgResult(rval);
nRet = nxtServiceInstance.iGetAutoJobChgResult(rval);
if (0 != nRet) {
System.out.format("API call [iGetAutoJobChgResult]: Error Code = %08x )", nRet);
return;
}
System.out.println("GetAutoJobChgResult---------->end");
boolean bResultOK = false;
for (int i = 0; i < size; i++) {
System.out.println("debug:current system encode:" + StringUtils.getEncoding(NxtManager.m_strEquip));
String szMcNameStr = new String(rval[i].szMcName,StringUtils.getEncoding(NxtManager.m_strEquip));
System.out.println("debug:szMcNameStr ----->" + szMcNameStr + ":" + szMcNameStr.length());
System.out.println("debug:m_strEquip ----->" + NxtManager.m_strEquip + ":" + NxtManager.m_strEquip.length());
String tempStrEquip = new String(NxtManager.m_strEquip.getBytes(),StringUtils.getEncoding(NxtManager.m_strEquip));
if (NxtManager.m_strEquip.equals(tempStrEquip)) {
if (rval[i].dwErrorCode != 0) {
nxtServiceInstance.iDelGetAutoJobChgResult();
System.out.format("Error Code = %08x", rval[i].dwErrorCode);
return;
}
bResultOK = true;
System.out.println("debug:String equal:ok");
break;
}
}
if (false == bResultOK) {
nxtServiceInstance.iDelGetAutoJobChgResult();
System.out.format("Error : Change over Result.(2)");
return;
}
System.out.println("success");
nxtServiceInstance.iDelGetAutoJobChgResult();
System.out.format("Change over from barcode ID complete.");
}
public static void main(String[] args) {
if (args.length < 1 || args.length > 2) {
System.out.println("参数不能为空");
return;
}
boolean isExit = false;
try {
int model = Integer.valueOf(args[0]);
NxtManager nxtManager = new NxtManager();
switch (model) {
case 0:
System.out.println("OnChangeoverId:根据barcodeId自动换线");
nxtManager.OnChangeoverId();
break;
case 1:
System.out.println("onChangeoverJob:根据jobName自动换线");
nxtManager.onChangeoverJob();
break;
default:
System.out.println("不支持其它命令");
break;
}
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("输入参数解析异常");
e.printStackTrace();
}
}
}