JNA (Java Native Access)
JNA(Java Native Access)是一个改进了JNI的开源(GPL)的Java框架,曾经由SUN公司主导开发的,用于使Java调用原生接口。
使用JNA调用Win32 API
本示例使用Kotlin环境和Gradle(Kotlin DSL)构建
1.添加JNA依赖
在build.gradle.kts中添加
implementation("net.java.dev.jna:jna:latest.release")
2.查阅Win32 API
我们以GetCursorPos这个Win32API为例,它接收一个结构体指针,将其修改为鼠标指针的位置:
//代码经过部分修改以显得更直观
typedef struct {
int x;
int y;
} POINT, *PPOINT;
BOOL GetCursorPos(LPPOINT lpPoint);
映射数据结构
首先,我们将结构体POINT映射为Kotlin代码
import com.sun.jna.Native
import com.sun.jna.Structure
import com.sun.jna.Library
open class POINT() :Structure() {
@JvmField var x: Int = 0
@JvmField var y: Int = 0
override fun getFieldOrder(): MutableList<String>?
= mutableListOf("x","y")
}
注意:
- 由于Kotlin和Java的类略有不同,需加@JvmField注解,否则会遇到
class has unknown or zero size (ensure all fields are public)
和Structure.getFieldOrder() on class X returns names XXXX which do not match declared field names ([])
这样的错误 - C语言的结构体成员在内存中是有顺序的,在Kotlin中需重载getFieldOrder函数来表述顺序信息
然后将他的指针(引用)LPPOINT映射为Kotlin代码,只需继承POINT类和Structure.ByReference接口即可
class LPPOINT :POINT(), Structure.ByReference
映射函数接口
需在jna.Library的子类中建立一个同名同类型的函数:
interface MyLib :Library {
fun GetCursorPos(lpPoint :LPPOINT) :Boolean
}
加载DLL
val LIBRARY :MyLib = Native.load("user32", MyLib::class.java)
调用API
var lpPoint = LPPOINT()
val r = LIBRARY.GetCursorPos(lpPoint)
print("${lpPoint.x},${lpPoint.y}\r")
完整代码
import com.sun.jna.Native
import com.sun.jna.Structure
import com.sun.jna.Library
open class POINT(@JvmField var x: Int = 0, @JvmField var y: Int = 0) :Structure() {
override fun getFieldOrder(): MutableList<String>? = mutableListOf("x","y")
}
class LPPOINT :POINT(), Structure.ByReference
interface MyLib :Library {
fun GetCursorPos(lpPoint :LPPOINT) :Boolean
}
fun main() {
val LIBRARY :MyLib = Native.load("user32", MyLib::class.java)
var lpPoint = LPPOINT()
while (true) {
val r = LIBRARY.GetCursorPos(lpPoint)
print("${lpPoint.x},${lpPoint.y}\r")
}
}
附
参考资料
环境
项目 | 版本 |
---|---|
Kotlin | 1.6.10 |
JDK | OpenJDK 17 |
Gradle | 7.3 |
JNA | 5.10.0 |