JNI (三)

来源:互联网 发布:美国eia数据公布 编辑:程序博客网 时间:2024/05/16 08:18

JNI (三)
     接上一次,大家都知道了jni是sun提供的java与系统中的原生方法交互的技术(在windows\linux系统中,实现java与native method互调)。目前只能由c/c++实现。但前两次我们都自己编写的dll文件,然后再用java程序去调用。那假设要在Java中调用已有的动态库,如 Windows 的 user32.dll 的方法 MessageBox,该如何操作呢?
      (1)在Java 类中声明一个 native 方法,然后用 javah 命令生成JNI样式的头文件.
       (2 )  在vc++中 再自己实现头文件中声明的方法,在实现方法中装载动态库 user32.dll,调用 MessageBoxA 方法,实现功能.
       (3)   再把自己写的这部分 C/C++ 代码封装成一个动态库,如Sample.dll,最后在 java  中装载 Sample.dll,然后执行其中所声明的本地方法。
      可见,用老实的JNI方式,我们在调用一个已知动态库的时候还需要额外生成一个符合JNI规则的动态库作为桥梁,显得有点多余了.
      那怎么办呢?
       在sourceforge上的有几个开源项目,jacob, jawin, jnative, 它们都是基于jni技术的应用库. 前两个都是应用于windows平台上的,而后一个可以应用于windows,linux两个平台.
   Jacob(Java-Com Bridge)提供了java程序调用microsoft的com对象中的方法的能力。而除了com对象外,jawin(Java/Win32 integration project)还可以win32-dll动态链接库中的方法。
   就功能而言:jni >> jawin>jacob,其大致的结构如下图:
        图片
          在windows系统上,一般可执行的应用程序都是基于native的PE结构,windows上的jvm也是基于native结构实现的。Java应用体系都是构建于jvm之上。
  
            图片

      Jni对于应用本身来说,可以看做一个代理模式。对于开发者来说,需要使用c/c++来实现一个代理程序(jni程序)来实际操作目标原生函数,java程序中则是jvm通过加载并调用此jni程序来间接地调用目标原生函数。
                      
图片
下面我们用jnative库来实现一个基于windows平台的本地方法调用的案例:
 (1)当然是下载jnative的jar包了.   地址:   http://sourceforge.net/projects/jnative/?source=dlp
   在这个jar包中,你可以找到  JNativeCpp.dll (用于windows平台动态链接库)    libJNativeCpp.s(用于linux平台动态链接库)两个文件.
 (2) 这次我用eclipse来进行开发。 新建好项目后,将jnative.jar包导入到项目的构建路径下.
     
     首先我们看一下MessageBox函数的签名:    (其它的user32函数请参: http://wenku.baidu.com/view/321f9e621ed9ad51f01df22b.html) 
        返回值  MessageBox(父窗体id, 内容, 标题, 按钮特征号);

       创建一个Test.java的类, 在其中加入一个messageBox方法来调用messagBox函数,将给这个函数传参, 接着写入代码:
       public static final int messageBox(int parentHandle, String message,   String caption, int buttons) throws NativeException,IllegalAccessException {
              JNative n = null;
              try {
                   n = new JNative("User32.dll", "MessageBoxA"); // 常量DLL_NAME的值为User32.dll
                   // 构造JNative时完成装载User32.dll,并且定位MessageBoxA方法
                   n.setRetVal(Type.INT); // 指定返回参数的类型
                   int i = 0;
                   n.setParameter(i++, Type.INT, "" + parentHandle);              //设置父窗体id,
                   n.setParameter(i++, Type.STRING, message);                    //内容
                   n.setParameter(i++, Type.STRING, caption);                      //标题
                   n.setParameter(i++, Type.INT, "" + buttons); // 指定位置上的参数类型和值        //按钮
                   n.invoke(); // 调用方法
                   return Integer.parseInt(n.getRetVal());     
          } finally {
                   if (n != null)
                        n.dispose(); // 记得释放
          }
     }
 public static void main(String[] args) throws NativeException, IllegalAccessException {
          messageBox(0,"a","title",0);
 }
        图片


运行后,ok.
图片

   linx下的做法也不样,只有调用的不是dll,而是 so库.
 --------------------------------------------------------------------------------------------------------------------------------------------------------------
引申:   从这些案例的讲解中,大家应该想到,1.  整个jvm的运行都是调用了底层操作系统的动态链接库来完成操作的。  2. 我们用的swt, swing中的组件也是利用了jni技术调用了底层操作系统的api来实现的( 现在回过头来看上面图片最后输出的对话框是不是与swt的一样啊) 。 3. 通过这三期的讲解,终于打通了java与底层操作系统之间的通信, 以前VC++能做的,java也能做到了,大家想一想,有什么好的应用吗?........................期待你的实现.
0 0
原创粉丝点击