JNA使用总结

这两天工作有一项任务,需要用 java 去调用 c 语言编写的 SDK,用到了 JNA,用的过程中遇到了些问题,在这里总结下使用方法,记录下。

分为几个步骤:编写一个继承了 Library 的接口,在类中声明接口,编写结构体(如果有需要),调用接口。

1. 编写 Library 接口

  在接口中声明的方法要和 SDK 的函数对应上,方法名要对应函数名。

  参数的话,基本类型一样,指针对应 Pointer、XxxByReference,结构体的对应需要自定义 java 类。详情可以参见 https://yq.aliyun.com/articles/606236?utm_content=m_1000018939 中的表格。

  调用接口时,使用 Native.loadLibrary("dll文件路径") 来生成一个代理对象,然后调用代理对象中的方法。

  示例代码如下:

public interface ChengFengSDK extends Library {

    /**
     * 生成一个代理对象,后面使用时,需要调用 INTERFACE 中的接口,然后代理对象来调用 C 语言的实现。
     */
    ChengFengSDK INTERFACE = (ChengFengSDK) Native.loadLibrary("HieClientUnit", ChengFengSDK.class);

    /**
     * 接口声明,方法名和参数列表要与头文件的函数对应起来
     */
    int HieClient_UserLogin  (WinNT.HANDLEByReference hUser, UserLoginPara.ByReference cUserLoginPara);
    int HieClient_Start();
    int HieClient_Stop();

}

2. 自定义结构体

  当函数的参数中存在结构体时,java 里需要自定义一个类来与之对应。

  编写一个类,继承 Structure。

  类中的属性与结构体中的属性要一一对应,并且全都要是 public 权限。

  重写 getFieldOrder 方法,List 中的名称顺序要与函数的参数列表一致。

  注意,如果函数中的参数为指针类型,则传入的结构体类需要继承 Structure.ByReference,否则会抛内存访问错误。

  示例代码如下:

public class UserLoginPara extends Structure {

    public byte[] sServerIP = new byte[256];
    public int dwCommandPort;
    public byte[] sUName = new byte[32];
    public byte[] sUPass = new byte[32];
    public int[] dwReserve = {0, 1};

    // 如果是指针类型,用这个
    public static class ByReference extends UserLoginPara implements Structure.ByReference { }
    public static class ByValue extends UserLoginPara implements Structure.ByValue { }

    protected List getFieldOrder() {
        return Arrays.asList(new String[]{"sServerIP", "dwCommandPort", "sUName", "sUPass", "dwReserve"});
    }
}

3. 调用接口

  要注意,数组需要初始化,大小要与 C 语言中的大小一致。

  示例代码如下:

    WinNT.HANDLE hUserLogin = WinBase.INVALID_HANDLE_VALUE;
    WinNT.HANDLEByReference hUserLoginRef = new WinNT.HANDLEByReference(hUserLogin);

    //配置用户登录参数
    UserLoginPara.ByReference tLoginPara = new UserLoginPara.ByReference();
    tLoginPara.dwCommandPort = port;    //端口
    System.arraycopy(ip.getBytes(), 0, tLoginPara.sServerIP, 0, ip.getBytes().length);  //ip
    System.arraycopy(userName.getBytes(), 0, tLoginPara.sUName, 0, userName.getBytes().length); //用户名
    System.arraycopy(passwd.getBytes(), 0, tLoginPara.sUPass, 0, passwd.getBytes().length);

    //调用登录接口
    nLoginCode = sdk.HieClient_UserLogin(hUserLoginRef, tLoginPara);
原文地址:https://www.cnblogs.com/lighter-blog/p/11060862.html