`

JNA 教程

阅读更多
JNA 教程
----------

1. JNA介绍
JNA提供JAVA程序访问本地共享库(DLLs), 且不需要编写JNI或本地代码.
JNA允许使用JAVA方法调用方式来直接调用本地函数.它提供了一个动态的C语言编写的转发器,自动实现JAVA类型和C类型的映射.
JNA使用一个小型本地库存根来动态调用本地代码.开发者需要定义一个JAVA接口来描述本地库存的函数,结构.
JNA包括一个平台库. 它提供已描述好本地函数类型的一组工具接口来简化本地访问.
JNA与JNI比较, 它不需要生成DLL, JNA基于JNI技术, 简化了JAVA本地访问的过程, 但性能不如JNI.

官网
http://jna.java.net/

2. 包说明
JNA只有一个组件:jna.jar. 它包括本地库jnidispatch. JNA自己负责抽取与加载本地库支持文件jnidispatch, 如果没有找到, 可以通过System.loadLibrary(java.lang.String)来加载.若还没有找到, 你需要自己来安装本地共享库支持文件.
platform-specific jar: 它也包括本地库jnidispatch, 主要用于Web Start.

3. 示例1
调用 C标准库函数printf.

3.1 配置CLASSPATH, 加入jna.jar
3.2 编写JAVA接口描述C标准库函数printf,并调用
3.2.1 加载本地库并映射. 加载本地库C, 定义接口CLibrary 映射本地库C.
3.2.2 类型映射
3.2.3 调用映射本地函数的JAVA方法

package com.sun.jna.examples;

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

/** JNA interface 映射与用法. */
public class HelloWorld {

    public interface CLibrary extends Library {
        CLibrary INSTANCE = (CLibrary)
            Native.loadLibrary((Platform.isWindows() ? "msvcrt" : "c"),
                               CLibrary.class);
   
       void printf(String format, Object... args);
    }

    public static void main(String[] args) {
        CLibrary.INSTANCE.printf("Hello, World\n");
    }
}

4. 不需要自己一个一个来映射本地库,JNA提供platform.jar, 它映射了大多数的标准库.

5. 映射名规则:
结构:根据头文件名映射
ShlObj.h
ShlObj
函数:根据DLL文件名映射.
Advapi32.dll
Advapi32
工具类:DLL文件名+Util.
Advapi32.dll
Advapi32Util

6. 同步调用与异步调用
JNA本地调用默认是异步的.要同步调用的话:
Kernel32 INSTANCE = (Kernel32)
        Native.loadLibrary("kernel32", Kernel32.class);

Kernel32 SYNC_INSTANCE = (Kernel32)
        Native.synchronizedLibrary(INSTANCE); // 同步

7.  最好将SYNC_INSTANCE 的作用域定义成局部的,方便JAVA垃圾回收.

8. 结构映射
8.1 在接口内部编写一个静态类继承Structure

9. 类型映射表
http://jna.java.net/javadoc/overview-summary.html#marshalling

10. JNAerator 自动本地库映射JAVA代码工具

JNAeratorStudio
http://code.google.com/p/jnaerator/

11. 传引用
// C声明
void allocate_buffer(char **bufp, int* lenp);

// JNA 映射
void allocate_buffer(PointerByReference bufp, IntByReference lenp);

// 用法
PointerByReference pref = new PointerByReference();
IntByReference iref = new IntByReference();
lib.allocate_buffer(pref, iref);
Pointer p = pref.getValue();
byte[] buffer = p.getByteArray(0, iref.getValue());

// 为什么这样就是传引用呢?
因为它传过去的不是对象本身,而是它的地址值.

12. 数组映射
// C声明
void fill_buffer(int *buf, int len);
void fill_buffer(int buf[], int len); // same thing with array syntax

// 等价 JNA 映射
void fill_buffer(int[] buf, int len);

13. Structures/Unions 映射
结构:
映射时需要与结构字段定义的顺序一致.

联合:
与结构类似,但必须设置使用setType表示激活的字段 .

Structures.ByReference
Structures.ByValue
标记型接口.表示结构体是引用或结构体本身.

14. 官方例子
http://java.net/projects/jna/sources/svn/show/trunk/jnalib/contrib

15. 记录用户输入

package cn.bisoft.java.jna;

import com.sun.jna.Structure;
import com.sun.jna.platform.win32.BaseTSD;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinUser;
import com.sun.jna.platform.win32.WinDef.HMODULE;
import com.sun.jna.platform.win32.WinDef.LRESULT;
import com.sun.jna.platform.win32.WinDef.WPARAM;
import com.sun.jna.platform.win32.WinUser.HHOOK;
import com.sun.jna.platform.win32.WinUser.HOOKPROC;
import com.sun.jna.platform.win32.WinUser.KBDLLHOOKSTRUCT;
import com.sun.jna.platform.win32.WinUser.LowLevelKeyboardProc;
import com.sun.jna.platform.win32.WinUser.MSG;

/** 
 * 低级键盘鼠标事件监听
 * 此程序使用JNA实现类似键盘记录器程序或网页游戏傻瓜点击录制 
 */
public class TrackUserInput {
	private static volatile boolean quit;
	private static HHOOK hhkKeyBoard;
	private static HHOOK hhkMouse;
	private static LowLevelKeyboardProc keyboardHook;
	private static HOOKPROC mouseHook;

	public static void main(String[] args) {
		final User32 lib = User32.INSTANCE;
		HMODULE hMod = Kernel32.INSTANCE.GetModuleHandle(null);
		
		keyboardHook = new LowLevelKeyboardProc() {
			public LRESULT callback(int nCode, WPARAM wParam,
					KBDLLHOOKSTRUCT info) {
				if (nCode >= 0) {
					switch (wParam.intValue()) {
						case WinUser.WM_KEYUP:
						case WinUser.WM_KEYDOWN:
						case WinUser.WM_SYSKEYUP:
						case WinUser.WM_SYSKEYDOWN:
							int keyCode = info.vkCode;
	
							System.err.println(keyCode);
							if (info.vkCode == 123) {
								quit = true;
							}
							break;
					}
				}
				return lib.CallNextHookEx(hhkKeyBoard, nCode, wParam,
						info.getPointer());
			}
		};

		mouseHook = new LowLevelMouseProc() {
			public LRESULT callback(int nCode, WPARAM wParam,
					MOUSEHOOKSTRUCT info) {
				if (nCode >= 0) {
					switch (wParam.intValue()) {
					case MouseHook.WM_LBUTTONDOWN:
						System.err.println("mouse left key down");
						break;
					case MouseHook.WM_LBUTTONUP:
						System.err.println("mouse left key up");
						break;
					case MouseHook.WM_MBUTTONDOWN:
						System.err.println("mouse middle key down");
						break;
					case MouseHook.WM_MBUTTONUP:
						System.err.println("mouse middle key up");
						break;
					case MouseHook.WM_RBUTTONDOWN:
						System.err.println("mouse right key down");
						break;
					case MouseHook.WM_RBUTTONUP:
						System.err.println("mouse right key up");
						break;
					case MouseHook.WM_MOUSEMOVE:
						// System.err.println("mouse mouse");
						break;
					}
				}
				return lib
						.CallNextHookEx(hhkMouse, nCode, wParam, info.getPointer());
			}

		};

		hhkKeyBoard = lib.SetWindowsHookEx(WinUser.WH_KEYBOARD_LL,
				keyboardHook, hMod, 0);
		hhkMouse = lib
				.SetWindowsHookEx(WinUser.WH_MOUSE_LL, mouseHook, hMod, 0);

		System.out.println("Enter '<F12>' to quit");
		
		new Thread() {
			public void run() {
				while (!quit) {
					try {
						Thread.sleep(10);
					} catch (Exception e) {
					}
				}
				
				System.err.println("unhook and exit");
				lib.UnhookWindowsHookEx(hhkKeyBoard);
				lib.UnhookWindowsHookEx(hhkMouse);
				System.exit(0);
			}
		}.start();

		// 处理消息
		int result;
		MSG msg = new MSG();
		while ((result = lib.GetMessage(msg, null, 0, 0)) != 0) {
			if (result == -1) {
				System.err.println("error in get message");
				break;
			} else {
				lib.TranslateMessage(msg);
				lib.DispatchMessage(msg);
			}
		}
		
		lib.UnhookWindowsHookEx(hhkKeyBoard);
		lib.UnhookWindowsHookEx(hhkMouse);
	}
	
	public interface LowLevelMouseProc extends HOOKPROC {
		LRESULT callback(int nCode, WPARAM wParam, MOUSEHOOKSTRUCT lParam);
	}
	
	public static class MOUSEHOOKSTRUCT extends Structure {
		public static class ByReference extends MOUSEHOOKSTRUCT implements
				Structure.ByReference {
		};

		public WinUser.POINT pt;
		public WinDef hwnd;
		public int wHitTestCode;
		public BaseTSD.ULONG_PTR dwExtraInfo;
	}
	
}

















4
0
分享到:
评论
1 楼 leodemacondo 2011-12-22  
谢谢!这片文章对我帮助很大啊,本来我一直搞不懂jni的话还真不会写钩子的回调函数。
不过我想做一个WH_GETMESSAGE 的钩子,请问楼主知道怎么做吗?
我查了msdn,GetMsgProc的第三个参数LPARAM是指向MSG结构体的,于是我就用现成的MSG类作为该参数类型,但是不管用,回调函数不会被调用。。。请楼主帮忙,呵呵

相关推荐

    jna技术手册和教程

    **JNA技术手册和教程** Java Native Access (JNA) 是一个Java平台上的库,它允许Java代码直接调用本地(或本机)库的函数,而无需编写JNI(Java Native Interface)代码。JNA通过一种映射机制,将Java方法与C/C++等...

    JNA Jar包和使用教程.rar

    在"JNA Jar包和使用教程.rar"这个压缩包中,包含的是JNA的V3.5.1版本的库文件以及一份PDF使用教程,名为"JNA—快速调用原生函数1.0"。 JNA的核心功能在于提供了一种无需编写C/C++代码的桥梁,使得Java程序员可以...

    com.sun.jna 3.0.9

    然而,用户在别处找到了一个包含非空`examples`包的`jna.jar`,这个版本可能包含了示例代码和教程,帮助开发者更好地理解和使用JNA。 **标签解析:** "jna" 和 "jna-example" 标签明确了讨论的主题。"jna" 指的是...

    android studio 上实现JNA

    本教程将详细讲解如何在Android Studio中使用JNA来实现本地库的调用。 1. **JNA简介** - JNA是一种轻量级的框架,通过动态映射本地函数到Java方法,使得Java可以直接调用C/C++等本地库。 - 它通过提供一个接口...

    Jna调用dll实例

    这个实例是关于如何使用JNA来调用DLL(动态链接库)的教程,特别强调了在调用过程中可能出现的中文乱码问题以及如何解决这个问题。 首先,我们需要理解JNA的工作原理。JNA通过提供一个接口定义,让Java代码能够映射...

    jna控制键盘

    标题中的“jna控制键盘”指的是使用Java Native...在提供的压缩包文件中,可能包含了示例代码或者教程,帮助开发者理解如何使用JNA实现键盘控制。学习这些资源,结合以上讲解,可以帮助你更好地掌握JNA控制键盘的技术。

    jna运行在android上的例子

    9. **文档和教程**:压缩包可能还包含了一份详细的README文件或教程,解释了如何运行和理解这些示例,这对于初学者来说非常有价值。 通过这些示例,开发者可以学习如何在Android应用中有效地利用JNA来扩展功能,...

    JNA-3.1.0.jar.zip

    开发者可以根据自己的需求,查阅JNA的官方文档或相关教程,学习如何充分利用这些特性。 总之,JNA为Java开发者提供了一个高效、易用的桥梁,使得他们能够在不离开Java平台的情况下,便捷地调用本地库,从而实现更...

    jna test【鼠标 键盘钩子】

    **描述分析:** "NULL" 这个描述没有提供额外的信息,但我们可以从标题推测,这个项目或教程可能涉及使用JNA来实现鼠标和键盘的钩子功能,即监听和控制用户的输入行为。 **标签解读:** "源码" 和 "工具" 这两个...

    深入浅出JNA—快速调用原生函数1.0

    ### 深入浅出JNA—快速调用原生函数 #### 为什么需要JNA JNA(Java Native Access)作为一个重要的Java框架,解决了Java开发者长期以来的一个痛点——调用原生函数。Java本身提供了JNI(Java Native Interface)...

    c++ 代码实现 dll 工程 用于java jna调用

    本教程将详述如何使用C++编写DLL动态链接库,并通过Java的Java Native Access (JNA)库进行调用,从而实现Java程序对C++功能的调用。 首先,我们需要了解DLL是什么。DLL(Dynamic Link Library)是Windows操作系统中...

    JNA读硬盘编号(32位系统).rar

    本教程将深入探讨如何使用JNA技术来调用DLL(动态链接库)实现这一功能。 首先,我们需要理解JNA的工作原理。JNA通过映射本地函数调用来使Java能够调用操作系统提供的函数。在Windows系统中,硬盘编号通常由硬件ID...

    libCDynamicDemo.dll

    JNA教程用到所有函数打包 地址:https://mp.csdn.net/mp_blog/creation/editor/134111934

    JNA初识

    这个版本是3.5.2,意味着该教程或示例基于这个稳定版本。 另一个文件 "TestJNA" 可能是一个测试程序,用于演示如何使用JNA调用本地库。通常,这样的测试类会包含对JNA接口的实例化,然后调用本地库函数的Java映射,...

    JNA.jar-JNative.jar-dll创建-JAVA调用-VC调用

    标题中的“JNA.jar-JNative.jar-dll创建-JAVA调用-VC调用”...总的来说,这个压缩包提供了一个全面的教程,涵盖了从创建DLL到在Java和VC++中调用DLL的全过程,对于理解跨语言交互和Java本地化编程具有很高的学习价值。

    JNI--java调用不同平台的动态链接库,dll,so,完美,全教程

    我们知道,使用 JNI 调用 .dll/.so 共享类库是非常非常麻烦和痛苦...使用 JNA ,不需要再编写适配用的 .dll/.so ,只需要在 Java 中编写一个接口和一些代码,作为 .dll/.so 的代理,就可以在 Java 程序中调用 dll/so 。

    JNI介绍及开发i教程.rar

    JNA(JavaNativeAccess)框架是一个开源的Java框架,是SUN公司主导开发的,建立在经典的JNI的基础之上的一个框架。 JNA项目地址:https://jna.dev.java.net/ JNA使Java调用原生函数就像.NET上的P/Invoke一样方便、快捷...

    JNI教程大全集,android开发必看!绝对经典!

    教程可能会对比分析JNA和JNI的优缺点,指导开发者根据实际需求选择合适的方法。 9. **案例实践**:实战项目是学习JNI的最佳方式,教程通常会提供一些示例,如使用JNI进行性能优化、访问硬件设备、实现图形库等,...

    java后端大华摄像头二次开发demo

    2. **导入JNA库**:在Java项目中,我们需要添加JNA和JNA平台库作为依赖,以便能够调用DLL中的函数。 3. **定义DLL接口**:使用JNA的`InterfaceMapper`,根据大华提供的函数原型定义Java接口,映射到DLL的函数。例如...

Global site tag (gtag.js) - Google Analytics