Head First JNA

栏目: Java · 发布时间: 6年前

内容简介:虚拟化项目,需要用到在

问题描述

虚拟化项目,需要用到 Java 调用原生代码的技术,我们使用的是开源库 JNA ( Java Native Access )。

Native ( C/C++ )代码,编译生成动态链接库 Dynamic-link library

Windows 下常见的 .dll 文件。这是我们项目中用到的动态链接库。

而在 unix 环境下,为 .so 文件。这是百度地图的动态链接库。

Head First JNA

与动态链接库配套的,会有相应的头文件,来声明动态链接库中对外暴露的方法。

Head First JNA

百度地图是直接封装好,给了 .so ,但是不给头文件,直接把写好的 jar 包给你,直接调用就行。

Head First JNA

之前也是用过百度地图的 SDK ,现在自己手写代码调用动态链接库才明白,原来之前用的都是别人封装好的,如今自己参照头文件手写,感觉理解还是深刻了不少。

入门

待解决的问题

我们使用 JNA ,主要是去调用动态链接库中已经实现的方法,所以要解决的问题就是:如何在 Java 代码中调用动态链接库的方法?

打开头文件,这个方法要求传输的数据是指针,而 Java 是没有指针的,另一个问题: Java 数据类型与 C/C++ 的数据类型如何映射?

Head First JNA

方法映射

打开 JNA 的官方 README ,点击 Getting Started

直接看代码,里面的 sample ,入门足够了。

Head First JNA

Library
// This is the standard, stable way of mapping, which supports extensive
// customization and mapping of Java to native types.

public interface CLibrary extends Library {
    CLibrary INSTANCE = (CLibrary)
        Native.load((Platform.isWindows() ? "msvcrt" : "c"),
                            CLibrary.class);

    void printf(String format, Object... args);
}

类型映射

默认类型映射

这是官方 README 中给的类型映射。

学习与实践的区别,看着这个表格感觉挺简单的,实际用起来真难。

Head First JNA

结构体映射

结构体 PSA_HOST

typedef struct {
  char   name[33];
  DWORD  context;
} PSA_HOST;

映射类 HostStruct

  1. 编写类 HostStruct ,继承 Structure ,表示这个一个结构体。
  2. 声明字段 namecontext 并且设置访问属性为 public
  3. 重写 getFieldOrder 方法,表示本类中各字段以何顺序映射原生结构体。
/**
 * @author zhangxishuo on 2019-02-16
 * 结构体 PSA_HOST
 */
public class HostStruct extends Structure {

    public byte[] name = new byte[33];

    public int context;

    @Override
    protected List<String> getFieldOrder() {
        return Arrays.asList("name", "context");
    }
}

注意

const char * 才能映射为 String 类型。

char * 只能映射为 byte 数组,然后使用 Native.toString() 方法将 byte 数组转换为 String

方法映射

typedef PSA_STATUS (*LPFN_PSA_ShutdownHost)( PSA_LOGON_HANDLE *handle, IN PSA_HOST *psa_host );

参数中需要 PSA_HOST 结构体的指针。

参考了好多篇文章,最常用的就是下面这种写法。写静态内部类,内部类实现 ByReferenceByValue 接口,分别表示映射指针,与映射值。

/**
 * @author zhangxishuo on 2019-02-16
 * 结构体 PSA_HOST
 */
public class HostStruct extends Structure {

    /**
     * 结构体指针
     */
    public static class ByReference extends HostStruct implements Structure.ByReference {
    }

    /**
     * 结构体具体的值
     */
    public static class ByValue extends HostStruct implements Structure.ByValue {
    }

    public byte[] name = new byte[33];

    public int context;

    @Override
    protected List<String> getFieldOrder() {
        return Arrays.asList("name", "context");
    }
}

映射

/**
 * 关闭计算机
 * @param pointerByReference 认证pointer
 * @param host               主机指针
 * @return 参见枚举类PsaStatus
 */
NativeLong _PSA_ShutdownHost(PointerByReference pointerByReference,
                            HostStruct.ByReference host);

复杂类型

打起精神,重点来了!

开发过程中,有这样一种复杂的数据结构,嵌套关系比较复杂。

typedef struct {
  union {
    DWORD flags;
    struct {
      DWORD rev:23;
      DWORD copy_status:3;
      DWORD timeout:1;
      DWORD disconnect:1;
      DWORD rev1:1;
      DWORD os_logoned:1;
      DWORD logoned:1;
      DWORD online:1;
    };
  };
} PSA_HOST_STATUS_FLAGS;

Head First JNA

知识不用就忘,谁还记得 C 语言里的联合是啥?

Too young

struct {
  DWORD rev:23;
  DWORD copy_status:3;
  DWORD timeout:1;
  DWORD disconnect:1;
  DWORD rev1:1;
  DWORD os_logoned:1;
  DWORD logoned:1;
  DWORD online:1;
};

DWORD 就是 int ,先映射里面的结构体。

把这些属性一写,然后再重写 getFieldOrder 方法。

/**
 * @author zhangxishuo on 2019-02-26
 * 计算机状态结构体
 */
public class HostStatusStruct extends Structure {

    /**
     * 结构体指针
     */
    public static class ByReference extends HostStatusStruct implements Structure.ByReference {
    }

    /**
     * 结构体具体的值
     */
    public static class ByValue extends HostStatusStruct implements Structure.ByValue {
    }

    public int rev;

    public int copy_status;

    public int timeout;

    public int disconnect;

    public int rev1;

    public int os_logoned;

    public int logoned;

    public int online;

    @Override
    protected List<String> getFieldOrder() {
        return Arrays.asList("rev", "copy_status", "timeout", "disconnect", "rev1", "os_logoned", "logoned", "online");
    }
}
union {
  DWORD flags;
  struct {
    DWORD rev:23;
    DWORD copy_status:3;
    DWORD timeout:1;
    DWORD disconnect:1;
    DWORD rev1:1;
    DWORD os_logoned:1;
    DWORD logoned:1;
    DWORD online:1;
  };
};

然后再映射联合,编写一个类继承 Union ,该类即映射到联合。

/**
 * 联合
 */
public static class UNION extends Union {
    public int flags;
    public HostStatusStruct hostStatusStruct;
}

最后映射最外层的 PSA_HOST_STATUS_FLAGS

/**
 * @author zhangxishuo on 2019-02-26
 * 结构体 PSA_HOST_STATUS_FLAGS
 */
public class HostStatusFlagsStruct extends Structure {

    /**
     * 联合
     */
    public static class UNION extends Union {
        public int flags;
        public HostStatusStruct hostStatusStruct;
    }

    /**
     * 结构体指针
     */
    public static class ByReference extends HostStatusFlagsStruct implements Structure.ByReference {
    }

    /**
     * 结构体具体的值
     */
    public static class ByValue extends HostStatusFlagsStruct implements Structure.ByValue {
    }

    public UNION union;

    @Override
    protected List<String> getFieldOrder() {
        return Collections.singletonList("union");
    }
}

看上去好像没什么毛病,一切都这么简单吗?当然不是。

-1073741824

一调用,就炸了。

Head First JNA

API 文档的声明, flags 应该是没什么具体含义的,而结构体中应该是我们想要获取的信息。

那为什么 flags 有数,而结构体中却没有值呢?

联合

struct TEST_STRUCT {
    int a,
    int b
};

Head First JNA

union TEST_UNION {
    int a,
    int b
};

Head First JNA

声明映射类型

重写 read 方法,当读取数据时,设置联合的类型为结构体类型。

@Override
public void read() {
    super.read();
    union.setType(HostStatusStruct.class);
    union.read();
}

怪事

Head First JNA

当时这个问题把我愁坏了,捯饬了一整天才学明白。

数字

一直是这个数字: -1073741824 ,这个数字是不是有什么问题?

-1073741824 转换为 32 机的二进制表示:

1073741824230 次方。

问题

问题还是出在这个上:

struct {
  DWORD rev:23;
  DWORD copy_status:3;
  DWORD timeout:1;
  DWORD disconnect:1;
  DWORD rev1:1;
  DWORD os_logoned:1;
  DWORD logoned:1;
  DWORD online:1;
};

虽然 DWORD 就映射为 int ,但这里不是简单的映射:

rev:23 表示 rev32 位。

copy_status:3 表示 copy_status3 位。

timeout:1 表示 timeout1 位。

内存是倒着存的,所以数据应该是这样。

Head First JNA

映射

原理知道了,那怎么映射呢?怎么映射一个一位的内容呢?

Head First JNA

StackOverflow 上一老哥给出了解决方案,先写个 int 把所有的都映射过来,然后我想要第几位再从里面扒。

/**
 * @author zhangxishuo on 2019-02-26
 * 计算机状态结构体
 */
public class HostStatusStruct extends Structure {

    /**
     * 结构体指针
     */
    public static class ByReference extends HostStatusStruct implements Structure.ByReference {
    }

    /**
     * 结构体具体的值
     */
    public static class ByValue extends HostStatusStruct implements Structure.ByValue {
    }

    public int value;

    public int getRev() {
        return value & 0x3FFFFF;
    }

    public int getCopyStatus() {
        return (value >> 23) & 0x3;
    }

    public int getTimeout() {
        return (value >> 26) & 0x1;
    }

    public int getDisconnect() {
        return (value >> 27) & 0x1;
    }

    public int getRev1() {
        return (value >> 28) & 0x1;
    }

    public int getOsLogoned() {
        return (value >> 29) & 0x1;
    }

    public int getLogoned() {
        return (value >> 30) & 0x1;
    }

    public int getOnline() {
        return (value >> 31) & 0x1;
    }

    @Override
    protected List<String> getFieldOrder() {
        return Collections.singletonList("value");
    }
}

至此,功能完成。

总结

又过去了忙碌的一周,很高兴我们的新项目已经完成大半。

感谢潘佳琦与李宜衡在本项目中的支持,第一次用 Angular ,好多地方我也不懂,我先学着,然后设计一套架构付诸实践,潘佳琦与李宜衡也都能遵从我制定的规范。

起初,我也提出了许多错误的规范,但当我用着用着发现原来那套不行的时候,及时改正,修改架构再重新设计,潘佳琦与李宜衡也在前台经历了大约三次的代码重构。

Head First JNA

前台架构变更多次,感觉最后的设计还让人满意,也能让他人快速理解这种设计理念。

争取下一个项目,不使用 ng-alain ,自己从头到尾搭建一个项目骨架。

最后表扬一下潘佳琦,上周基本我有一半的时间都在上课,我能做的就是前一天晚上把任务建好,然后写一些基础代码或示例代码,然后给潘佳琦讲,再让他去写。

潘佳琦效率还是很高的,我记得周一的时候建了一堆任务,我想怎么着也得写两天吧,当我上课回来,发现“当当当”,潘佳琦都给写完了,代码也十分的规范。

对小组员的开发效率在心中也有了一个重新的定位。


以上所述就是小编给大家介绍的《Head First JNA》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

About Face 3

About Face 3

Alan Cooper、Robert Reimann、David Cronin / John Wiley & Sons / 2007-5-15 / GBP 28.99

* The return of the authoritative bestseller includes all new content relevant to the popularization of how About Face maintains its relevance to new Web technologies such as AJAX and mobile platforms......一起来看看 《About Face 3》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试