JNA入门

Java Native Access(JNA)是一个开源的Java库,用于在Java中直接调用本地库(Native Library)。通过JNA,您可以使用Java来调用C、C++、Objective-C等语言编写的本地库,而无需编写任何本地代码或使用JNI(Java Native Interface)。

以下是JNA的快速入门指南:

  1. 导入JNA库:首先,您需要在您的Java项目中导入JNA库。您可以通过将JAR文件直接包含到您的项目中,或者通过Maven、Gradle等构建工具来添加依赖。

         <!--官方不提供Maven坐标,这是社区维护的-->
         <dependency>
             <groupId>net.java.dev.jna</groupId>
             <artifactId>jna-platform</artifactId>
             <version>${jna.version}</version>
         </dependency>
    
  2. 定义接口:创建一个Java接口,用于声明您要调用的本地库中的方法。方法的签名应该与本地库中的函数一致。

import com.sun.jna.Library;
import com.sun.jna.Native;

public interface MyNativeLibrary extends Library {
    MyNativeLibrary INSTANCE = (MyNativeLibrary) Native.load("my_native_library", MyNativeLibrary.class);
    
    // Declare native methods here
    void myNativeMethod();
}
  1. 调用本地方法:在您的Java代码中使用接口中声明的方法。JNA会自动将这些方法调用转换为本地函数调用。
public class Main {
    public static void main(String[] args) {
        MyNativeLibrary.INSTANCE.myNativeMethod();
    }
}
  1. 编译和运行:确保您的本地库已经被正确编译,并且JNA可以找到它。您可以通过设置java.library.path系统属性来指定本地库的路径。
java -Djava.library.path=/path/to/native/library -cp your-app.jar Main

这样,您就可以使用JNA在Java中调用本地库了。记得在使用JNA时要注意内存管理和数据类型的转换,以确保代码的正确性和性能。

JNA操作句柄

在使用JNA操控句柄时,您需要了解如何在Java中表示和使用句柄,并且使用JNA提供的方法来操作句柄。通常,句柄在本地库中用整数或指针的形式表示,您可以将其映射到Java中的原生数据类型或者使用JNA提供的数据结构来处理。

以下是一个简单的示例,演示如何使用JNA操控定义接口:

package com.cy.rpa.jna;

import com.sun.jna.platform.win32.User32;

/**
 *User32 接口 书写与windows User32本地库同名的方法,实现本地库调用
 *
 * @author Liang Zhaoyuan
 * @version 2024/02/09 22:05
 */

public interface User32Ext extends User32 {

    /**
     * 查找窗口
     *
     * @param lpParent     需要查找窗口的父窗口
     * @param lpChild      需要查找窗口的子窗口
     * @param lpClassName  类名
     * @param lpWindowName 窗口名
     * @return 找到的窗口的句柄
     */
    HWND FindWindowEx(HWND lpParent, HWND lpChild, String lpClassName, String lpWindowName);

    /**
     * 获取桌面窗口,可以理解为所有窗口的root
     *
     * @return 获取的窗口的句柄
     */
    HWND GetDesktopWindow();

    /**
     * 发送事件消息
     *
     * @param hWnd    控件的句柄
     * @param dwFlags 事件类型
     * @param bVk     虚拟按键码
     * @param lParam  扩展信息,传0即可
     * @return
     */
    int SendMessage(HWND hWnd, int dwFlags, int bVk, int lParam);

    /**
     * 发送事件消息
     *
     * @param hWnd    控件的句柄
     * @param dwFlags 事件类型
     * @param bVk     虚拟按键码
     * @param buffer  扩展信息,传0即可
     * @return
     */
    int SendMessage(HWND hWnd, int dwFlags, int bVk, char[] buffer);

    /**
     * 发送事件消息
     *
     * @param hWnd   控件的句柄
     * @param Msg    事件类型
     * @param wParam 传0即可
     * @param lParam 需要发送的消息,如果是点击操作传null
     * @return
     */
    int SendMessage(HWND hWnd, int Msg, int wParam, String lParam);

    /**
     * 发送键盘事件
     *
     * @param bVk         虚拟按键码
     * @param bScan       传 ((byte)0) 即可
     * @param dwFlags     键盘事件类型
     * @param dwExtraInfo 传0即可
     */
    void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);

    /**
     * 激活指定窗口(将鼠标焦点定位于指定窗口)
     *
     * @param hWnd    需激活的窗口的句柄
     * @param fAltTab 是否将最小化窗口还原
     */
    void SwitchToThisWindow(HWND hWnd, boolean fAltTab);

    /**
     * 移动窗体到指定位置
     * 该函数改变指定窗口的位置和尺寸。对于顶层窗口,位置和尺寸是相对于屏幕的左上角的:对于子窗口,位置和尺寸是相对于父窗口客户区的左上角坐标的。
     *
     * @param hWnd    窗体句柄
     * @param x       需要移动到的x位置
     * @param y       需要移动到的y位置
     * @param width   窗体的宽度
     * @param height  窗体的高度
     * @param repaint 默认为true
     * @return
     */
    boolean MoveWindow(HWND hWnd, int x, int y, int width, int height, boolean repaint);
}

剩下的就不用多说了。