• JNI vc6.0 dll


    JNI初步。让大家一看就会哈哈。

    写篇教程吧,网上很多关于JNIhello world,虽然称作哈喽沃德,但是调试起来还是不可避免遇到很多问题。今天在调式成功的这个里程碑时间里,总结下这两天俺的经验,那些希望使用JNI的银们,如果看到这篇小文了,或许可以一站式解决问题,免去东奔西走的麻烦咧~~~~哈哈哈

    开始!

    JNI是啥就不介绍了,最直观的作用就是它可以在java里面调用dll。如果大家伙儿遇到c++写的代码想转向java使用,不妨生成一个dll,再按下面的步骤来。

    1.       编写java代码。文件名:HelloWorld.java

    代码如下:

    public class HelloWorld

    {

    static

    {

    System.loadLibrary("HelloWorldDll");

    }

    public native static int MyMethod();

     

    public static void main(String[] args)

    {

    HelloWorld hw = new HelloWorld();

    hw.MyMethod();

    }

    }

    2.       编译java代码,生成class文件。

    在命令行下输入:javac HelloWorld.java

    完成后,D盘根目录下产生了HelloWorld.class文件。

    PS:如果这里出现问题没有成功,那请检查你的环境变量是否设置正确。以及确认命令提示符是在当前你要编译的java文件的位置。以下是错误举例:

    问题1

     

     

    出错原因:你肯定粗心了,在代码中使用的类名和文件名不一致。图中所示错误是将类名写成了HelloWorlds

    3.       根据class文件生成HelloWorld.h,以供C++调用。

    在命令行下输入:javah HelloWorld

    完成后,D盘根目录下产生了HelloWorld.h文件。

    生成的代码如下:

    /* DO NOT EDIT THIS FILE - it is machine generated */

    #include <jni.h>

    /* Header for class HelloWorld */

     

    #ifndef _Included_HelloWorld

    #define _Included_HelloWorld

    #ifdef __cplusplus

    extern "C" {

    #endif

    /*

     * Class:     HelloWorld

     * Method:    MyMethod

     * Signature: ()I

     */

    JNIEXPORT jint JNICALL Java_HelloWorld_MyMethod

      (JNIEnv *, jclass);

     

    #ifdef __cplusplus

    }

    #endif

    #endif

    这里需要做一点改动,将第二行的#include <jni.h>改成#include “jni.h”。否则vc生成dll编译的时候可能产生问题。

    以下是这一步骤的错误举例:

    问题一:

    出错原因:编写的java程序中出现了包的说明:package com.microsoft.services;将包去掉就中了。关于带包编译的情况,下面分解。

    4.       使用VC++创建dll程序。文件名:HelloWorldDll.dll

    4.1新建一个名叫HelloWorldDlldll工程:

    4.2HelloWorldDll.cpp文件头部加入:#include “HelloWorldDll.h”

    4.3HelloWorldDll.cpp文件中再加入:

    JNIEXPORT jint JNICALL Java_HelloWorld_MyMethod (JNIEnv *, jclass)

    {

    printf("this is helloworld printed in dll");

    return 1;

    }

    代码中的jint是指名java中的返回值类型为int型。Java_后面跟上java文件的类名,然后再用一个_跟上方法名。括号中的参数不必做改动。

    这里需要注意的有两点:

    第一,   如果类带有包。那么Java_HelloWorld_MyMethod的第一个_前面需要把包名加上,改成Java_<包名>_HelloWorld_MyMethod。详细示例一会儿继续往下看。

    第二,   第二,如果希望传入参数,那么在后面继续加就是了,例如,我想传入int型的变量a,那么第一行需要改成:

    JNIEXPORT jint JNICALL Java_HelloWorld_MyMethod (JNIEnv *, jclass,jint a)

    函数体内a就可以拿来随意整了。

    编译生成dll文件吧。

    出错举例:

    错误1

    C:\work\VCProjects\HelloWorldDll\HelloWorldDll.cpp(6) : fatal error C1083: Cannot open include file: 'HelloWorld.h': No such file or directory

    原因:没有把D盘下的HelloWorld.h拷贝到工程目录下面。

    错误2

    c:\work\vcprojects\helloworlddll\helloworld.h(2) : fatal error C1083: Cannot open include file: 'jni.h': No such file or directory

    原因:没有把jni.h拷贝到工程目录下。Jin.h的位置:

    C:\Program Files\Java\jdk1.5.0_06\include

    错误3

    c:\work\vcprojects\helloworlddll\helloworld.h(2) : fatal error C1083: Cannot open include file: 'jni.h': No such file or directory

    原因:呵呵为什么我已经把jni.h拷贝到工程目录下了,还是会报这个错误呢?那是因为HelloWorld.h里面的#include <jni.h>忘了改成#include “jni.h”

    错误4

    c:\work\vcprojects\helloworlddll\jni.h(27) : fatal error C1083: Cannot open include file: 'jni_md.h': No such file or directory

    原因:又是找不到.h。这个jni_md.h藏在

    C:\Program Files\Java\jdk1.5.0_06\include\win32下面。

    5.       运行看效果。

    将刚才生成的HelloWorldDll.dll拷贝到D盘根目录下,从命令行执行:

    Java HelloWorld

    可以看到运行结果了吧。

    恭喜你,成功了。

    但是这样就可以了吗?显然平时过程中大都不是在命令行下执行的。接下来,我们去看看在eclipse里面会不会一帆风顺捏?

    1.       新建一个Web工程。工程名叫做HelloWorld

    PS:为什么要建立的是Web工程呢?因为我们不但要在eclipse里面调通,还希望在浏览器中可用。哇哈哈,眼光真远大。

    2.       新建一个包叫做com.microsoft.services,以及HelloWorld类。

    将刚才的HelloWorld.java中的代码复制进来。最终代码如下:

    package com.microsoft.services;

     

    public class HelloWorld {

        static

        {

        System.loadLibrary("HelloWorldDll");

        }

        public native static int MyMethod();

     

        public static void main(String[] args)

        {

        HelloWorld hw = new HelloWorld();

        hw.MyMethod();

        }

    }

    3.       生成class文件。

    刚才的代码编辑完成后,如果没有错误,在点击保存的时候eclipse会自动在以下目录中生成对应的class文件:

    C:\work\workspace\HelloWorld\WebRoot\WEB-INF\classes\com\microsoft\services

    4.       生成h文件。

    这一步很关键。如果按照刚才那样到class所在目录下生成的话,是不行的。因为这里需要用到带包编译。在命令行中cd

    C:\work\workspace\HelloWorld\WebRoot\WEB-INF\classes\路径下,然后输入:

    Javah com.microsoft.services.HelloWorld

    成功后会在C:\work\workspace\HelloWorld\WebRoot\WEB-INF\classes下发现:

    com_microsoft_services_HelloWorld.h文件。

    5.       Vc中建立dll工程。在cpp中添加的代码也有变动:

    5.1引入的头文件:#include "com_microsoft_services_HelloWorld.h"

    5.2功能实现:

    JNIEXPORT jint JNICALL Java_com_microsoft_services_HelloWorld_MyMethod

      (JNIEnv *, jclass);

    {

    printf("this is helloworld printed in dll");

    return 1;

    }

    6.       编译生成HelloWorldDll.dll。将其放入C:\WINDOWS\system32下,或者放到其他可以让系统通过环境变量找到的位置。

    错误1

    java.lang.UnsatisfiedLinkError: no HelloWorldDll in java.library.path

        at java.lang.ClassLoader.loadLibrary(Unknown Source)

        at java.lang.Runtime.loadLibrary0(Unknown Source)

        at java.lang.System.loadLibrary(Unknown Source)

        at com.microsoft.services.HelloWorld.<clinit>(HelloWorld.java:6)

    Exception in thread "main"

    系统没有找到你生成的dll。那表明你的dll放置的位置不对。这里有一个好办法,可以很省事,不用在system32includebin等地方拷来拷去的试验。我们在java代码中添加一句:

    System.out.println(System.getProperties().get("java.library.path"));然后将一些代码注释掉。

    如下所示:

    package com.microsoft.services;

     

    public class HelloWorld {

        static

        {

        //System.loadLibrary("HelloWorldDll");

        }

        public native static int MyMethod();

     

        public static void main(String[] args)

        {

           System.out.println(System.getProperties().get("java.library.path"));

        //  HelloWorld hw = new HelloWorld();

        //  hw.MyMethod();

        }

    }

    运行java程序的时候会看到:

    已经将java.library.path显示出来了,我们按指引随意拷贝进去,就可以成功咧!

    7.       运行,console里面什么都没出现那么说明成功了,dllprintf的东东是不会显示的。为了验证是否真的成功了,可以打印出方法的返回值,修改HelloWorld.java如下:

     

    package com.microsoft.services;

     

    public class HelloWorld {

        static

        {

        System.loadLibrary("HelloWorldDll");

        }

        public native static int MyMethod();

     

        public static void main(String[] args)

        {

           //System.out.println(System.getProperties().get("java.library.path"));

           HelloWorld hw = new HelloWorld();

           int t = hw.MyMethod();

           System.out.println(t);

        }

    }

     

    在执行,就可以看到1已经乖乖显示在了console里。Yeah

    最后,以上执行都没有问题的话,将其使用在web上也不成问题了哈哈。打完收工!

    http://www.chinaunix.net 作者:ludejun98发表于:2004-03-03 11:16:06 最近项目中设计到JNI的技术,对于VC++我是一知半解.JNI是知道和Native方法的接口,从来没用过.但是摸了一会,还是感觉有点门路,搞定了JNI的难题以后,对于自己这点小小的进步不敢隐瞒,公开出来给还不

     
     
     
    TAG:

     
    http://www.chinaunix.net 作者:ludejun98  发表于:2004-03-03 11:16:06 

    最近项目中设计到JNI的技术,对于VC++我是一知半解.JNI是知道和Native方法的接口,从来没用过.但是摸了一会,还是感觉有点门路,搞定了JNI的难题以后,对于自己这点小小的进步不敢隐瞒,公开出来给还不了解的兄弟们作个参考. 

    Java中使用JNI调用DLL 
    1 编写范例文档 
    public class TestNative{ 
       
      private native int add(int x,int y); 
       
      public static void main(String[] args) { 
        TestNative hh = new TestNative(); 
        int r = hh.add(30,20); 
        System.out.println("result = "+r); 
      } 

      static { 
        System.loadLibrary("DLL_0305"); 
      } 

    其中 
    LoadLibrary中的DLL文件名称可以随便定.只要做好的动态链接库改名成这个字符串就可以了.而native函数的来源就是该动态链接库. 
    2. 做好该步准备以后,用javac TestNative.java生成.class.检验语法. 
    3. 语法检查通过以后,用javah TestNative生成.h的C头文件. 
    4. 打开VC++6.0,新建-> 工程 -> win32 Dynamic-Link Library .在向导中选择空工程. 
    5. 把刚才javah生成的那个头文件加入工程 .然后 文件->新建->textFile 自己做一个.c文件.实现自己的native函数.清单如下: 

    #include 

    JNIEXPORT jint JNICALL Java_TestNative_add 
      (JNIEnv *ev, jobject obj, jint x, jint y) 

    return x+y; 

    备注: 
    A  其中的jni.h通常在 jdk\\include\\ 可以先拷贝到VC安装目录下的include目录下.一劳永逸,以后可以方便使用JNI技术. 
    B  全部的数据类型需要考虑Java和VC的接口问题.用jint  jstring 等. 
    C  函数名称和自动生成的.h文件中规定的一致.命名规则是: Java_使用类_方法名  
    6 全编译一下工程. 
      如果没有出错,则此时生成动态链接库成功. 
      把动态链接库拷贝到TestNative.java所在的目录上. 
    7 运行java TestNative看结果吧.

    ////////////////////////////////////

    /////////////////////////////////////

    eclipse+VC6.0开发JNI  (1) 

    1、eclipse新建一个普通的java project,如下图: 

     

    TestNative.java的具体代码如下: 

    Java代码  收藏代码
    1. package org.hwq.main;  
    2.   
    3. public class TestNative {  
    4.     /**定义本地方法*/  
    5.     public native void print();  
    6.     /**main方法调用本地方法*/  
    7.     public static void main(String[] args) {  
    8.         new TestNative().print();  
    9.     }  
    10.     /**初始时候加载本地库文件,即是上面本地方法的c/c++实现*/  
    11.     static{  
    12.         System.loadLibrary("hello");  
    13.     }  
    14. }  



    上面需要注意的是System.loadLibrary("hello");这个。这里的“hello”就是需要加载的库的名字。这里会面要提及,关键注意。只有加载了库文件,print()这个本地方法才能使用。 

    2、生成.h头文件 

    上面通过eclipse编译后,启动cmd,进入该项目的bin目录下面。我这里是:D:\workspace1\testNative\bin,如下图: 

     

        这里要注意,javah是jdk自带的工具类,能根据现有的类,生成相应的.h头文件。这里后面要跟上类的全名,即包名+类名。 
        这时候就可以通过文件夹,查看D:\workspace1\testNative\bin下的文件。如下图: 



    我们可以看看这个生成头文件的内容: 

    Java代码  收藏代码
    1. /* DO NOT EDIT THIS FILE - it is machine generated */  
    2. #include <jni.h>  
    3. /* Header for class org_hwq_main_TestNative */  
    4.   
    5. #ifndef _Included_org_hwq_main_TestNative  
    6. #define _Included_org_hwq_main_TestNative  
    7. #ifdef __cplusplus  
    8. extern "C" {  
    9. #endif  
    10. /* 
    11.  * Class:     org_hwq_main_TestNative 
    12.  * Method:    print 
    13.  * Signature: ()V 
    14.  */  
    15. JNIEXPORT void JNICALL Java_org_hwq_main_TestNative_print  
    16.   (JNIEnv *, jobject);  
    17.   
    18. #ifdef __cplusplus  
    19. }  
    20. #endif  
    21. #endif  



        看到头文件中声明了一个方法JNIEXPORT void JNICALL Java_org_hwq_main_TestNative_print (JNIEnv *, jobject);,这个就是在java中对应print()方法的本地实现方法名。 

    3、启动VC6.0编写对应c/c++源文件 

        启动VC6.0,“新建”—工程—Win32 Dynamic-Link Libraay,填写工程名,这里就要填写上面提到的库名“hello” 



        工程建完后,将上面生成的org_hwq_main_TestNative.h文件复制到该项目目录下面。我这里是C:\Program Files\Microsoft Visual Studio\MyProjects\hello。如下图: 



        到VC6.0界面,将刚复制过来的头文件添加到项目头文件中。如下: 

     

        接下来,编写本地方法实现的c/c++源文件。如下图: 

     

    TestNative.cpp文件内容如下: 

    Java代码  收藏代码
    1. #include <jni.h>  
    2. #include <stdio.h>  
    3. #include "org_hwq_main_TestNative.h"  
    4.   
    5. JNIEXPORT void JNICALL Java_org_hwq_main_TestNative_print  
    6.   (JNIEnv *env, jobject obj)  
    7. {  
    8.     printf("hello wolrd,the first jni application!!!");  
    9.     return;  
    10. }  



        这个cpp文件中,需要导入jni.h头文件,还有我们生成的头文件org_hwq_main_TestNative.h,然后方法就是org_hwq_main_TestNative.h头文件中声明的那个。编写方法体,OK完毕。编译build就完事。 
        这是后我们到这个C++项目下的Debug目录下面能看到一个hello.dll的文件。将这个文件复制到java项目的bin目录下,和生成的头文件在一个目录。 

     

        这时候就能运行了,我们先到cmd中运行试试。 

     

        运行成功。 

        我们在到eclipse中去运行试试看。 

    Java代码  收藏代码
    1. Exception in thread "main" java.lang.UnsatisfiedLinkError: no hello in java.library.path  
    2.     at java.lang.ClassLoader.loadLibrary(Unknown Source)  
    3.     at java.lang.Runtime.loadLibrary0(Unknown Source)  
    4.     at java.lang.System.loadLibrary(Unknown Source)  
    5.     at org.hwq.main.TestNative.<clinit>(TestNative.java:12)  



        出现这个错误,没找到库文件hello。上面我们在cmd中运行成功了。为什么在eclipse中不能运行?这里的问题,我也不是太了解。不过有个解决方案。在系统的环境变量path中添加该java项目bin目录。这里是D:\workspace1\testNative\bin 

     

        添加成功,确定,重启eclipse,再次运行就ok了。 

     

    如果想图方便,可以直接将生成的.dll动态库文件放到system32文件夹下去,直接就能运行。

  • 相关阅读:
    9. Palindrome Number
    7. Reverse Integer
    650. 2 Keys Keyboard
    646. Maximum Length of Pair Chain
    523. Continuous Subarray Sum
    516. Longest Palindromic Subsequence
    dp问题解题思路
    494. Target Sum
    小波变换网文精粹:小波:看森林,也看树木(一)
    数学、海豚和花朵
  • 原文地址:https://www.cnblogs.com/GoAhead/p/2809944.html
Copyright © 2020-2023  润新知