通过JNI实现Java和C++的相互调用

 

通过JNI实现JavaC++的相互调用

一、Java调用C++DLL

1.    创建Java文件

创建名为TestNativeJava文件,注意包名。

package org.druze.test;

publicclass TestNative {

    publicnativevoid sayHello();

    publicvoid sayHello2(){

       System.out.println("Say Hello From Java");

    }

}

如代码所示,对于sayHello方法声明为native,这一部分将由C++的动态库来实现。

2.    生成class文件

使用javac org/druze/test/TestNative.java生成class文件

注意:执行该命令在org所在目录执行。

3.    使用javah命令生成相应的C++头文件

使用javah org.druze.test.TestNative生成名为

org_druze_test_TestNative.h的头文件

注意:执行该命令在org所在目录执行。

该头文件的内容如下:

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

#include <jni.h>

/* Header for class org_druze_test_TestNative */

#ifndef _Included_org_druze_test_TestNative

#define _Included_org_druze_test_TestNative

#ifdef __cplusplus

extern "C" {

#endif

/*

 * Class:     org_druze_test_TestNative

 * Method:    sayHello

 * Signature: ()V

 */

JNIEXPORT void JNICALL Java_org_druze_test_TestNative_sayHello

 (JNIEnv *, jobject);

#ifdef __cplusplus

}

#endif

#endif

4.    创建C++解决方案

此处以VS2008为例。

新建一个VC++Win32项目,选择如图所示的控制台应用程序。项目名称为NativeCode

点击确定后,再点击下一步,出现该页面,应用程序类型选择DLL,附加选项选择DLL

5.    创建号工程之后,将org_druze_test_TestNative.h导入到工程里面,并创建名为source.cpp的源代码,内容如下:

#include"org_druze_test_TestNative.h"  

#include<iostream>  

using namespace std;  

JNIEXPORT void JNICALL Java_org_druze_test_TestNative_sayHello(JNIEnv *env, jobject obj)

{  

    cout<<"Hello World!"<<endl;  

6.    在工具->选项->项目和解决方案->VC++目录菜单中,平台选择Win32,选择“显示以下内容的目录”为“包含文件”,导入jni.hjni_md.h的路径。

7.    编译,生成NativeCode.dll,并将其copy到环境变量PATH的路径下。

8.    修改TestNative.java

package org.druze.test;

publicclass TestNative {

    publicnativevoid sayHello();

    publicstaticvoid main(String[] args) {

        // 加载动态连接库DLL,如果没有找到的话,则会在运行时报错  

        System.loadLibrary("NativeCode");  

          

        TestNative tnt = new TestNative();  

              

        tnt.sayHello();  

    }

    publicvoid sayHello2(){

       System.out.println("Say Hello From Java");

    }

}

运行,显示“Hello World! 

9.    注意头文件jni.hjni_md.h可以直接导入到工程中也可以。

10.注意NativeCode.dll必须放置在java命令能访问的路径中。

二、C++调用Java

1.创建TestNative2.Java

package org.druze.test;

publicclass TestNative2 {

    publicstaticvoid testPrint(){

       System.out.println("this is from static method");

    }

    publicstaticint testReturn(){

       return 22;

    }

    publicstaticint testInput(int number){

       return 22+number;

    }

    publicint testInstance(int number){

       System.out.println("this is from instance method");

       return 11+number;

    }

}

2.VS2008中创建win32控制台的应用程序,命名为NativeCode2,在向导中选择空项目。

3. 在工具->选项->项目和解决方案->VC++目录菜单中,平台选择Win32,选择“显示以下内容的目录”为“包含文件”,导入jni.hjni_md.h的路径。直接把jni.hjni_md.h导入到工程中。

4. 在工具->选项->项目和解决方案->VC++目录菜单中,平台选择Win32,选择“显示以下内容的目录”为“包含文件”,导入jvm.lib的路径,并在项目->NativeCode2属性->配置属性->链接器->命令行中添加jvm.lib(这一步或者使用#pragma comment(lib,"jvm.lib")来代替)。或者将直接将jvm.lib添加到工程中。

5.创建Test.cpp

#include <jni.h>

#include <iostream>

using namespace std;

int main()

{

    JavaVMOption options[1];

    JNIEnv * env;

    JavaVM * jvm;

    JavaVMInitArgs vm_args;

    options[0].optionString = "-Djava.class.path=.";

    vm_args.version = JNI_VERSION_1_6;

    vm_args.nOptions = 1;

    vm_args.options = options;

    vm_args.ignoreUnrecognized = JNI_TRUE;

    long status = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);

    if (status == JNI_ERR)

    {

        cout<<"Can not create JVM"<<endl;

        return -1;

    }

    printf("Created JVM"n");

    jclass cls = env->FindClass("org/druze/test/TestNative2");

    printf("getCls"n");

     cout<<cls<<endl;

    if (cls !=0)

    {

        jmethodID mid = env->GetStaticMethodID(cls, "testReturn", "()I");

        printf("getMid"n");

        if (mid !=0)

        {

            printf("testReturn"n");

            int result=env->CallStaticIntMethod(cls, mid);

            printf("call over result=%d"n",result);

        }

        mid = env->GetStaticMethodID(cls, "testPrint", "()V");

        if (mid !=0)

        {

            printf("testPrint"n");

            env->CallStaticVoidMethod(cls, mid);

        }

        mid = env->GetStaticMethodID(cls, "testInput", "(I)I");

        if (mid !=0)

        {

            printf("testInput"n");

            int result=env->CallStaticIntMethod(cls, mid,22);

            printf("call over result=%d"n",result);

        }

        mid = env->GetMethodID(cls,"<init>","()V");

        if (mid != 0)//获取方法成功

        {

            printf("ctro!=0"n");

            jobject obj=env->NewObject(cls, mid);

            printf("new object"n");

            mid = env->GetMethodID(cls, "testInstance","(I)I");

            if (mid!=0)//获取方法成功

            {

                printf("methodID!=0"n");

                jint result=env->CallIntMethod( obj, mid,22);

                cout<<result<<endl;

            }

        }

    }

    jvm->DestroyJavaVM();

    system("Pause");

    return 0;

}

6.jvm.dll目录添加到PATH环境变量中,将org/druze/test/TestNative2复制到debug目录下执行。

7.头文件和库文件的配置VC6VC2008类似,菜单名称有所改变。

VC6中,配置头文件和库文件的目录在,工具(Tools)->选项(Options)->目录(Directories)里面的头文件”Include files”和库文件”Library files”.添加相应的目录

工程(Project)->设置(Setting)->链接(Link)->object/module library后面添加jvm.lib

CodeBlocksProject->Build options->Linker setting and Search directories中配置相应路径。

8.按如下结构组织可不用配置jvm.dll到环境变量中

创建存放目录Run(下面的文件目录在JDK安装目录中都能找倒):

Run(手工建立目录)

----bin(手工建立目录)

      ----classic(手工建立目录)

            ----jvm.dll(文件,JDK安装目录中有)

            ----自己的JAR包,如果是class文件把包目录和文件一起拷贝过来

                 如果是jar文件,需要在options[1].optionString = "-Djava.class.path=.;./swt.jar";中设置

            ----JniC.exe,C调用JAVA的程序

      ----hpi.dll(文件,JDK安装目录中有)

      ----ioser12.dll(文件,JDK安装目录中有)

      ----java.dll(文件,JDK安装目录中有)

      ----net.dll(文件,JDK安装目录中有)

      ----verify.dll(文件,JDK安装目录中有)

     ----zip.dll(文件,JDK安装目录中有)

----lib(手工建立目录)

      ----zi(目录,JDK安装目录中有,全部拷贝过来)

      ----rt.jar(文件,JDK安装目录中有)

      ----tzmappings(文件,JDK安装目录中有)

三、JNI代码分析(待续)

posted on 2008-07-29 12:48 role0523-- 阅读(11408) 评论(23)  编辑  收藏

评论

# re: 通过JNI实现Java和C++的相互调用 2008-07-29 14:14 Always BaNg.

不错,把字符转换也一并讲了吧,比如UTF-8的处理,USC-2与MBCS转换等。  回复  更多评论   

# re: 通过JNI实现Java和C++的相互调用[未登录] 2008-07-29 14:17 role0523

你是指Java和C++之间的字符转换?
目前还没有研究过字符转换。
  回复  更多评论   

# re: 通过JNI实现Java和C++的相互调用 2008-07-31 23:58 coldsummer

如果是现成的dll呢?比如某硬件提供的开发dll开发包,我如何调用?  回复  更多评论   

# re: 通过JNI实现Java和C++的相互调用[未登录] 2008-08-01 00:05 role0523

@coldsummer
由于JAVA调用C++需要一定的格式,比如在JAVA中声明native方法,然后通过javah生成一个头文件,然后写cpp文件,但必须实现这个头文件中声明的JNIEXPORT方法。这些方法是Java调用C++的入口。所以在这些方法内部填写对你的DLL的调用即可。  回复  更多评论   

# re: 通过JNI实现Java和C++的相互调用 2008-08-26 17:14 lfking

你的这个JAVA调用C++的例子,我试了一整天,没试明白!~~
在最后编译成DLL文件时老是报错,不知道是怎么回事!~~~
错误代码如下:请你帮分析一下!谢谢!~

c:\documents and settings\william\my documents\visual studio 2005\projects\nativecode\nativecode\source.cpp(5) : error C2144: syntax error : 'void' should be preceded by ';'
c:\documents and settings\william\my documents\visual studio 2005\projects\nativecode\nativecode\source.cpp(5) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
c:\documents and settings\william\my documents\visual studio 2005\projects\nativecode\nativecode\source.cpp(5) : error C2146: syntax error : missing ';' before identifier 'Java_org_druze_test_TestNative_sayHello'
c:\documents and settings\william\my documents\visual studio 2005\projects\nativecode\nativecode\source.cpp(5) : error C2182: 'JNICALL' : illegal use of type 'void'
c:\documents and settings\william\my documents\visual studio 2005\projects\nativecode\nativecode\source.cpp(5) : error C2065: 'JNIEnv' : undeclared identifier
c:\documents and settings\william\my documents\visual studio 2005\projects\nativecode\nativecode\source.cpp(5) : error C2065: 'env' : undeclared identifier
c:\documents and settings\william\my documents\visual studio 2005\projects\nativecode\nativecode\source.cpp(5) : error C2065: 'jobject' : undeclared identifier
c:\documents and settings\william\my documents\visual studio 2005\projects\nativecode\nativecode\source.cpp(5) : error C2146: syntax error : missing ')' before identifier 'obj'
c:\documents and settings\william\my documents\visual studio 2005\projects\nativecode\nativecode\source.cpp(5) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
c:\documents and settings\william\my documents\visual studio 2005\projects\nativecode\nativecode\source.cpp(5) : error C2078: too many initializers
c:\documents and settings\william\my documents\visual studio 2005\projects\nativecode\nativecode\source.cpp(5) : error C2059: syntax error : ')'
c:\documents and settings\william\my documents\visual studio 2005\projects\nativecode\nativecode\source.cpp(6) : error C2143: syntax error : missing ';' before '{'
c:\documents and settings\william\my documents\visual studio 2005\projects\nativecode\nativecode\source.cpp(6) : error C2447: '{' : missing function header (old-style formal list?)
Generating Code...
生成日志保存在“file://c:\Documents and Settings\william\My Documents\Visual Studio 2005\Projects\NativeCode\NativeCode\Debug\BuildLog.htm”
NativeCode - 13 个错误,0 个警告
========== 全部重新生成: 0 已成功, 1 已失败, 0 已跳过 ==========
  回复  更多评论   

# re: 通过JNI实现Java和C++的相互调用[未登录] 2008-08-26 17:38 role0523

你没有指定jni.h,jni_md.h的include path,以及 jvm.dll的路径,具体参考文章后半部分  回复  更多评论   

# re: 通过JNI实现Java和C++的相互调用 2008-08-27 10:24 lfking

你说要指定jni.h 和 jni_md.h的include path 这个我都做了,就是少做一个JVM.DLL的路径,试过了,还是一样的错误!~
我做的是JAVA 连接 C++ 需要做这个JVM.DLL的路径吗?  回复  更多评论   

# re: 通过JNI实现Java和C++的相互调用[未登录] 2008-08-27 10:46 role0523

sorry, jvm.dll不用指定,因为我们这里不需要它。

这样好了,你把org_druze_test_TestNative.h和jni.h复制到source.cpp相同的目录下,将#include <jni.h>修改为#include "jni.h" 试试看。

你的问题是jni.h的头文件没有在头文件的搜索路径当中。  回复  更多评论   

# re: 通过JNI实现Java和C++的相互调用 2008-08-27 12:01 lfking

我按照你上面写的步聚建立一个WIN32的工程,建好以后,会自动建立一个stdafx.h的头文件和stdafx.cpp文件!然后运行source.cpp的时候提示错误说必须要用stdafx.h这个头文件,加上去以后就出现这些错误了!

唉!~把jni.h放到source.cpp同一个目录下了,还是不行!~~
我留个QQ号给你吧,Q上聊!47145748!
你这BOLG上面不能发图片!
  回复  更多评论   

# re: 通过JNI实现Java和C++的相互调用 2008-08-27 12:04 lfking

vc以前从来没接触过,只是听说过!所以用起来有点愚纯!~~抱歉!~~  回复  更多评论   

# re: 通过JNI实现Java和C++的相互调用[未登录] 2008-08-27 15:12 role0523

你把stdafx.h的头文件和stdafx.cpp删除掉吧  回复  更多评论   

# re: 通过JNI实现Java和C++的相互调用 2008-08-28 10:31 lfking

无语了都.....
如果把stdafx.h和stdafx.cpp删除的话,会提示错误,说没有加载stdafx.h文件。
大哥,这个例子你试过没啊??是否成功了?你那个版本的VC??我是用VC2005做的!  回复  更多评论   

# re: 通过JNI实现Java和C++的相互调用[未登录] 2008-08-28 11:00 role0523

就如我文中所说,我用的VS2008,VC6,codeBlocks.我没搞定,不会写东西的。你的问题在于你对C++的编译器不是很熟悉,这我帮不了你。

BTW:如果把stdafx.h和stdafx.cpp删除的话,会提示错误,说没有加载stdafx.h文件。

那是你的某个地方#include了这个文件,OK?  回复  更多评论   

# re: 通过JNI实现Java和C++的相互调用 2008-08-28 14:53 lfking

7.编译,生成NativeCode.dll,并将其copy到环境变量PATH的路径下。
10.注意NativeCode.dll必须放置在java命令能访问的路径中。

这个不是很了解。能不能在说的具体点!
我是把NativeCode.dll放在与TestNative.java文件同一个目录下!   回复  更多评论   

# re: 通过JNI实现Java和C++的相互调用[未登录] 2008-08-28 14:58 role0523

NativeCode.dll是由java.exe->jvm.dll->NativeCode.dll这样调用的。你把NativeCode.dll放到与java.exe同目录下,OK?
  回复  更多评论   

# re: 通过JNI实现Java和C++的相互调用 2009-05-21 18:10 Necho

完全按照楼主的做法结果确报这个错误,请楼主帮我看下吧

First-chance exception at 0x00411a20 in NativeCode2.exe: 0xC0000005: Access violation reading location 0x00000000.
Unhandled exception at 0x00411a20 in NativeCode2.exe: 0xC0000005: Access violation reading location 0x00000000.  回复  更多评论   

# re: 通过JNI实现Java和C++的相互调用 2009-05-21 18:21 Necho

补充一下 应该就是不能findclass  回复  更多评论   

# re: 通过JNI实现Java和C++的相互调用 2009-05-21 18:24 Necho

如果可以的话 请加我MSN:necho_leco@yhotmail.com
或者QQ :55128128
想向你请教,谢谢~!   回复  更多评论   

# re: 通过JNI实现Java和C++的相互调用 2009-05-22 10:19 Necho

测试成功了 感谢LZ提供这么详细的说明 谢谢~~!!  回复  更多评论   

# re: 通过JNI实现Java和C++的相互调用[未登录] 2009-09-04 14:43 阿飞

楼主,请问下:我在VC6。0控制台下可以加载JAVA虚拟机了,为什么到了VC6.0的MFC下用同样的方法加载不了(编译不报错,但是调试的时候通不过),盼回复,谢谢!  回复  更多评论   

# re: 通過JNI實現Java和C++的相互調用[未登录] 2009-12-18 13:40 sunny

樓主:
請問我在編譯C++時,出現這個錯誤訊息:
error C2065: 'JNI_VERSION_1_6' : undeclared identifier

我使用的是JDK1.6  回复  更多评论   

# re: 通过JNI实现Java和C++的相互调用 2009-12-18 23:39 nobody

@sunny 看看这个声明在哪个头文件里面,把它include进来
  回复  更多评论   

# re: 通过JNI实现Java和C++的相互调用 2010-01-09 11:52 next

@lfking
朋友,这个连接的最下方是你要的答案
http://www.experts-exchange.com/Programming/Languages/CPP/Q_22048796.html

引用:
phongtran72:
Well, this generates error:

#include "jni.h"
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>

And this is solution:

#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include "jni.h"  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航:
 

导航

<2010年1月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
31123456

统计

常用链接

留言簿(3)

随笔档案

搜索

最新评论