内容简介:虚拟化项目,需要用到在
问题描述
虚拟化项目,需要用到 Java
调用原生代码的技术,我们使用的是开源库 JNA
( Java Native Access
)。
Native
( C/C++
)代码,编译生成动态链接库 Dynamic-link library
。
在 Windows
下常见的 .dll
文件。这是我们项目中用到的动态链接库。
而在 unix
环境下,为 .so
文件。这是百度地图的动态链接库。
与动态链接库配套的,会有相应的头文件,来声明动态链接库中对外暴露的方法。
百度地图是直接封装好,给了 .so
,但是不给头文件,直接把写好的 jar
包给你,直接调用就行。
之前也是用过百度地图的 SDK
,现在自己手写代码调用动态链接库才明白,原来之前用的都是别人封装好的,如今自己参照头文件手写,感觉理解还是深刻了不少。
入门
待解决的问题
我们使用 JNA
,主要是去调用动态链接库中已经实现的方法,所以要解决的问题就是:如何在 Java
代码中调用动态链接库的方法?
打开头文件,这个方法要求传输的数据是指针,而 Java
是没有指针的,另一个问题: Java
数据类型与 C/C++
的数据类型如何映射?
方法映射
打开 JNA
的官方 README
,点击 Getting Started
。
直接看代码,里面的 sample
,入门足够了。
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
中给的类型映射。
学习与实践的区别,看着这个表格感觉挺简单的,实际用起来真难。
结构体映射
结构体 PSA_HOST
:
typedef struct { char name[33]; DWORD context; } PSA_HOST;
映射类 HostStruct
:
- 编写类
HostStruct
,继承Structure
,表示这个一个结构体。 - 声明字段
name
与context
, 并且设置访问属性为public
。 - 重写
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
结构体的指针。
参考了好多篇文章,最常用的就是下面这种写法。写静态内部类,内部类实现 ByReference
与 ByValue
接口,分别表示映射指针,与映射值。
/** * @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;
知识不用就忘,谁还记得 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
一调用,就炸了。
看 API
文档的声明, flags
应该是没什么具体含义的,而结构体中应该是我们想要获取的信息。
那为什么 flags
有数,而结构体中却没有值呢?
联合
struct TEST_STRUCT { int a, int b };
union TEST_UNION { int a, int b };
声明映射类型
重写 read
方法,当读取数据时,设置联合的类型为结构体类型。
@Override public void read() { super.read(); union.setType(HostStatusStruct.class); union.read(); }
怪事
当时这个问题把我愁坏了,捯饬了一整天才学明白。
数字
一直是这个数字: -1073741824
,这个数字是不是有什么问题?
把 -1073741824
转换为 32
机的二进制表示:
1073741824
是 2
的 30
次方。
问题
问题还是出在这个上:
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
表示 rev
占 32
位。
copy_status:3
表示 copy_status
占 3
位。
timeout:1
表示 timeout
占 1
位。
内存是倒着存的,所以数据应该是这样。
映射
原理知道了,那怎么映射呢?怎么映射一个一位的内容呢?
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
,好多地方我也不懂,我先学着,然后设计一套架构付诸实践,潘佳琦与李宜衡也都能遵从我制定的规范。
起初,我也提出了许多错误的规范,但当我用着用着发现原来那套不行的时候,及时改正,修改架构再重新设计,潘佳琦与李宜衡也在前台经历了大约三次的代码重构。
前台架构变更多次,感觉最后的设计还让人满意,也能让他人快速理解这种设计理念。
争取下一个项目,不使用 ng-alain
,自己从头到尾搭建一个项目骨架。
最后表扬一下潘佳琦,上周基本我有一半的时间都在上课,我能做的就是前一天晚上把任务建好,然后写一些基础代码或示例代码,然后给潘佳琦讲,再让他去写。
潘佳琦效率还是很高的,我记得周一的时候建了一堆任务,我想怎么着也得写两天吧,当我上课回来,发现“当当当”,潘佳琦都给写完了,代码也十分的规范。
对小组员的开发效率在心中也有了一个重新的定位。
以上所述就是小编给大家介绍的《Head First JNA》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
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》 这本书的介绍吧!