用java做个小玩意,需要调用windows操作系统的动态链接库提供的API函数。
选来选去最终决定用jna实现调用,简单方便。
这个过程中遇到的最大障碍就是怎么传递函数的参数!
ps:原生代码在本文中指x86cpu下运行的c\c++代码。
jre也必须是32位的jre,否则可能发生不明原因的错误。
整理了一个jna与windous API(__stdcall调用约定)的库的数据类型对应表
其中值得注意的:
1:
c\c++中有无符号整数,java中没有,传递接受无符号的数据时要做转换。
例子:unsigned int xx(unsigned int);
你传递参数-1(0xffffffff),函数xx中会认为你传递的参数的值为4294967295
函数返回2147483648(0x80000000),java会认为函数返回的是-2147483648
2:
windows系统提供的api一般都有两个版本:asci 和 Unicode版本,在调用这些api时可能要明确指定调用哪个版本的api.
例如:GetClassName函数就分别有
int GetClassNameA(HWND hWnd, LPSTR IpClassName, int nMaxCount);
int GetClassNameW(HWND hWnd, LPTSTR IpClassName, int nMaxCount);
两个函数,其中的形参IpClassName就分别是asci 编码和 Unicode编码,都可以支持中文。
jna的人已经在jna-platform中定义了大部分windows API、windows数据类型。用起来很方便。
3:
windows API asci版以java的String替换本地的char。
windows API Unicode版以java的WString替换本地的wchar。
windows API 接受的字符数据默认都是用小端模式存储的,java程序中所有的字符和字符串都被utf-16be转码为java的char储存。
强烈建议严格遵循数据类型的替换表。自己实现这些转换很麻烦。
eclipse可以指定源文件的编码,但编码改变后有可能改不回来,建议保持eclipse的默认设置。
4:
c\c++的结构在java中用Structure表示,如果我想用HWND WindowFromPoint(POINT Point)这个函数,
需要在java代码文件中某接口中定义函数HWND WindowFromPoint(POINT Point);
并定义一个结构,最精简的定义为:
import java.util.ArrayList;
import java.util.List;
import com.sun.jna.Structure;
public class POINT extends Structure{
public int x;
public int y;
@Override
protected List<String> getFieldOrder() {
// 元素的添加顺序必须与结构元素声明的顺序相同,添加的顺序一定不能写错(不管是基本变量还是结构体变量,或者是数组什么的,只需要添加名称就可以
// 这个list返回的是封装结构体中的变量名称
List<String> a = new ArrayList<String>();
a.add("x");
a.add("y");
return a;
}
}
注意:getFieldOrder()返回的List集合存储的字符串代表的属性的访问权限必须是public,
在本例中体现为int x; int y;的访问权限必须是public。
5:
在实际使用jna的过程中中,请严格按照表替换,否则容易出现让人恼火弱智问题。
我就曾出过一些很弱智的问题,
例如:c\c++中定义了一种BOOL类型,jna也定义了一个BOOL类,但如果java中声明BOOL类型为某函数的返回值类型,这个函数对应c\c++返回值为BOOL的函数。
调用这个函数,无论接不接收返回值,都会报错 java.lang.IllegalArgumentException: Unsupported size: 0。正确的java函数的返回值类型可以是int或 boolean。
例如:原生代码有一种与平台相关的long类型,jna也定义了一种LONG类型,这很容易混淆,但正确的匹配类型是jna的NativeLong。
如果原生代码类型没有相应的java类型替换,或者嫌麻烦不想用相应的java类型可以用数组类型代替。
java数组类型可以替换大部分的本地代码的参数的数据类型,但是相应的就必须自行完成部分大小端的转换。不推荐
jna到本地代码函数的过程中可能涉及到数据在java大端模式(BIG-ENDIAN)到x86cpu小端模式(LITTLE-ENDIAN)的相互转换。
6:
jna还可以支持函数指针和回调函数,回调函数在jan-platform中有定义。
其余的我没有用到,不做讨论。
本文介绍了如何使用Java Native Access (JNA) 调用Windows API,特别是关注参数传递的注意事项。内容包括:无符号整数的转换、ASCII与Unicode版本API的选择、Structure的使用、数据类型匹配问题,以及函数指针和回调函数的简要提及。
1万+

被折叠的 条评论
为什么被折叠?



