免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1223 | 回复: 0
打印 上一主题 下一主题

在Java程序中使用JNI调用平台相关函数 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-10-04 23:01 |只看该作者 |倒序浏览

前一阵子遇到的一个问题是,如何在Java程序中调用Windows DLL的函数。查了查资料,得知使用名为JNI(Java Native Interface)的方式可以让Java调用DLL中的函数。JNI的使用方法如下:
  • 在Java中定义JNI调用,并撰写使用该JNI调用的相关代码。
  • 根据定义好的JNI调用生成相应的C语言头文件。
  • 利用上一步生成的头文件,使用C书写Windows平台上的代码。
  • 编译C代码生成DLL库文件。
  • 执行Java程序中JNI调用的代码。
    我们可以看到,第三步使用C语言书写代码时,须遵从JNI的规范,这就为我们带来了一个问题:如果我们想使用的DLL文件是已经编译好的,它未必遵从JNI规范,怎么办?另一个问题是,在Java程序中需要定义JNI调用,但是我们显然不希望在业务逻辑代码中定义JNI调用。于是产生了下面的结构:
    file:///D:/backup/top/JNI/在Java程序中使用JNI调用平台相关函数%20-%20idv2.files/jni.png
    最上方的Java Application是业务逻辑的实现部分,最下方的Windows DLL是我们拥有的DLL函数库,而中间虚线框的部分即为使用JNI进行开发的部分。
    我们假设Java Application部分的代码如下。文件名为JavaApp.java。
    package jnisample;

    public class JavaApp {
         public static final void main(String args[]) {
             JNIWrapper.Hello();
         }
    }
    这里JNIWrapper类为我们即将进行开发的JNI Wrapper的类名。
    我们先创建一个空的JNIWrapper.java以使得JavaApp.java能够正常编译。
    package jnisample;

    class JNIWrapper {
         static void Hello() {}
    }
    然后我们编译这两个文件:
    javac -d . JNIWrapper.java
    javac -d . JavaApp.java
    编译完成之后我们将在jnisample目录下得到JNIWrapper.class和JavaApp.class两个文件。
    我们再假设现有的DLL函数库的实现代码如下:(文件名HelloDll.c)
    #include

    __declspec(dllexport) BOOL __stdcall Hello();

    BOOL __stdcall Hello() {
         MessageBox(NULL, "Helo, world!", "Hello", MB_OK | MB_ICONINFORMATION);
         return TRUE;
    }
    然后我们使用Microsoft Visual Studio 6.0自带的编译器 cl 进行编译:
    cl HelloDll.c -MD -LD User32.lib
    这样我们将得到HelloDll.dll文件。将该文件与jnisample目录放到同一层次上。
    下面我们来看一下如何使用JNI在JavaApp.java中调用HelloDll.c中的Hello函数。首先我们将JNI Wrapper模块的JNIWrapper.java改成下面的样子:
    package jnisample;

    class JNIWrapper {
         static native void _dll_Hello();

         static {
             try {
                 System.loadLibrary("DllWrapper");
             } catch (Exception e) {
                 System.out.println("DllWrapper.dll load errer");
             }
         }

         static void Hello() {
             _dll_Hello();
         }
    }
    然后再次进行编译:
    javac -d . JNIWrapper.java
    下一步利用J2SE提供的工具来生成必要的头文件。执行下列命令:
    javah -jni jnisample.JNIWrapper
    这样我们得到一个名为jnisample_JNIWrapper.h的文件。打开这个文件之后可以看到,里面定义了这样一个函数:
    JNIEXPORT void JNICALL Java_jnisample_JNIWrapper__1dll_1Hello(JNIEnv *, jclass);
    这就是我们应当在DLL Wrapper模块中实现的函数。
    创建DllWrapper.c文件,内容如下:
    #include "jnisample_JNIWrapper.h"
    #include

    typedef BOOL (*FUNCHELLO)();

    JNIEXPORT void JNICALL Java_jnisample_JNIWrapper__1dll_1Hello(JNIEnv * jenv, jclass jcls)
    {
         HANDLE hDll;
         FUNCHELLO fnHello;

         hDll = LoadLibrary("HelloDll.dll");
         if (hDll) {
             fnHello = (FUNCHELLO)GetProcAddress(hDll, "_Hello@0");
             if (fnHello) fnHello();
             FreeLibrary(hDll);
         }
    }
    然后进行编译:
    cl DllWrapper.c -I"C:\Program Files\java\jdk1.5.0_04\include" -I"C:\Program Files\Java\jdk1.5.0_04\include\win32" -MD -LD
    生成DllWrapper.dll文件。到此为止我们的目录结构如下:
    DllWrapper.dll
    HelloDll.dll
    jnisample/JNIWrapper.class
    jnisample/JavaApp.class
    执行以下命令即可看到执行结果了。
    java jnisample.JavaApp
    以上简单地阐述了如何利用JNI来调用平台相关的本地代码。在实际应用中还会出现很多问题,例如Java和C语言之间的数据类型转换等,这里就不一一详述了。
    (示例程序下载)

    file:///D:/backup/top/JNI/在Java程序中使用JNI调用平台相关函数%20-%20idv2.files/attach.gif
    jnisample.zip




    本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u1/45990/showart_394833.html
  • 您需要登录后才可以回帖 登录 | 注册

    本版积分规则 发表回复

      

    北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
    未成年举报专区
    中国互联网协会会员  联系我们:huangweiwei@itpub.net
    感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

    清除 Cookies - ChinaUnix - Archiver - WAP - TOP