使用JNA调用本地方法

本文详细介绍了JNA(Java Native Access)与JNI(Java Native Interface)的区别,以及如何使用JNA调用本地方法。通过实例展示了如何查询Windows API、定义接口、加载DLL文件,并编写测试程序进行调用。同时,文章还讨论了数据类型的自定义、内存对齐问题及保护机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JNA全称是Java Native Access,Sun推出的一种调用本地方法技术,比起它的同门师兄JNI,JNA大大简化了调用本地方法的过程,使用也比较方便, JNA是在JNI的基础上完善的,用青出于蓝而胜于蓝来形容一点不为过,下面看一下JNI的调用过程:    


      

      使用JNI你得完成上面这些步骤,比较麻烦,而是用JNA就省事多了,基本上不需要脱离Java环境就可以完成。
  
   JNA项目主页是https://jna.dev.java.net/, 目前最新的版本是3.2.4 。下载时记得将自带的Example.jar 也下载下来,这个里面提供了一些JNA的例子,通过这个能够更快的了解JNA

    使用JNA的调用本地方法的时候需要自定义数据结构,下面我们通过调用Windows提供的的锁定工作站方法来了解一下JNA

    1首先查询Windows API知道锁定工作站的方法在user32.dll中定义,接下来定义一个接口来继承JNALibrary.java接口,用作声明DLL库文件,这里我们就把它命名为User32:      

  public   interface  User32  extends  Library {}

    2查询user32.dll提供的API得知锁定工作方法是LockWorkStation,返回类型是boolean型,在User32.java中新增相应的方法:

boolean  LockWorkStation();

         这样我们的User32.java这个类就定义好了。接下来我们写测试程序进行调用。

    3、编写测试类比如LockWorkStation.java,首先通过JNANative类加载对应的dll:     

User32 user32  =  (User32) Native.loadLibrary( " user32 " , User32. class );

        然后就可以调用LockWorkStation方法了,完整代码如下:      

public   class  LockWorkStation {
    
public   static   void  main(String[] args) {
       User32 user32 
=  (User32) Native.loadLibrary( " user32 " , User32. class );
       user32.LockWorkStation();
    }
}

  这里说明一下loadLibrary方法中第一个参数是需要加载的dll文件名称,第二个参数的作用是让JNA使用这个类的加载器去加载DLL文件,加载顺序是,先从Users.class类的当前文件夹找,如果没有找到,再在工程当前文件夹下面找win32/win64文件夹,找到后搜索对应的dll文件,如果找不到再到WINDOWS下面去搜索,再找不到就会抛异常了。以TWAINDSM.dll将文件放到工程的根文件夹可以按照下面这个格式放:

   上面的User32定义的是dll库文件,有时会碰到比如HANDLE、POINT、WORD和MSG等数据类型,有些数据类型JNA中没有提供,需要自己定义,根据作用的不同,定义的时候继承的父类也不一样,比如HANDLE定义方法是:

  class  HANDLE  extends  PointerType {
        
private   boolean  immutable;
        
public  HANDLE() { }
        
public  HANDLE(Pointer p) { setPointer(p); immutable  =   true ; }
       
public  Object fromNative(Object nativeValue, FromNativeContext context) {
            Object o 
=   super .fromNative(nativeValue, context);
            
if  (INVALID_HANDLE_VALUE.equals(o))
                
return  INVALID_HANDLE_VALUE;
            
return  o;
        }
        
public   void  setPointer(Pointer p) {
            
if  (immutable)
                
throw   new  UnsupportedOperationException( " immutable reference " );
            
super .setPointer(p);
        }
    }

    HANDLE被定义为类型安全的指针。而POINT用作表示坐标,不需要这么复杂,定义方式为:

  class  POINT  extends  Structure {
        
public   int  x, y;
        
public  POINT() { }
        
public  POINT( int  x,  int  y) {  this .x  =  x;  this .y  =  y; }
  }

   
     使用JNA的过程中也不一定会一帆风顺,比如会抛出”非法内存访问”,这时候检查一下变量是否==null。还有内存对齐的问题,当从内存中获取图片信息进行保存的时候,如果内存对齐处理不好,就会抛出很严重的异常,导致JVM异常退出,JNA提供了四种内存对齐的方式,分别是:ALIGN_DEFAULTALIGN_NONEALIGN_GNUCALIGN_MSVCALIGN_DEFAULT采用平台默认的对齐方式(推荐);ALIGN_NONE是不采用对齐方式;ALIGN_GNUC为针对linux/gcc操作系统的对齐方式。ALIGN_MSVC为针对win32/msvc架构的内存对齐方式。

     JNA也提供了一种保护机制.比如防止JNA出现异常不会导致JVM异常退出,默认是开启这个功能的,开启方式为System.setProperty(“jna.protected”,”true”); 记得要在JNA加载dll文件之前调用,然后try {...} catch(Throwable e)异常,不过你也不要期望过高,不要以为加上这个就万事大吉,出现”非法内存访问”的时候还是会束手无策。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值