JNI之一:基础 && JAVA调用win dll实例

来源:互联网 发布:淘宝违禁产品暗语 编辑:程序博客网 时间:2024/04/30 00:24

       JNI是Java Native Interface的缩写,译为Java本地接口。它允许Java代码和其他语言编写的代码进行交互。在android中提供JNI的方式,让Java程序可以调用C语言程序。android中很多Java类都具有native接口,这些接口由本地实现,然后注册到系统中。以下这个图可以很好的说明问题:    

        android主要的JNI代码放在以下的路径中:frameworks/base/core/jni/,这个路径中的内容被编译成库libandroid_runtime.so,这是个普通的动态库,被放置在目标系统的/system/lib目录下。此外,android还有其他的JNI库。JNI中的各个文件,实际上就是普通的C++源文件;在android中实现的JNI库,需要连接动态库libnativehelper.so。

(1)以Android源码根目录/frameworks/base/services/jni/目录下有一个onload.cpp文件。onload.cpp文件上部分为注册函数的声明,下部分为注册函数,只有通过这些注册函数,上层才有可能调用注册的JNI方法。这些注册函数是由同目录下的其他.cpp文件中实现,如register_android_server_VibratorService这个函数是在com_android_server_VibratorService.cpp文件中实现的。注册代码如下:

int register_android_server_VibratorService(JNIEnv *env){    return jniRegisterNativeMethods(env, "com/android/server/VibratorService",            method_table, NELEM(method_table));}

其中jniRegisterNativeMethods为注册JNI方法函数,此函数的第二个参数对应着java类即VibratorService.java的文件名(即VibratorService.java (frameworks\base\services\java\com\android\server) ),第三个参数为注册的方法表:

static JNINativeMethod method_table[] = {    { "vibratorExists", "()Z", (void*)vibratorExists },    { "vibratorOn", "(J)V", (void*)vibratorOn },    { "vibratorOff", "()V", (void*)vibratorOff }};

这里定义的三个函数就可以直接在VibratorService.java中被调用,只不过在该文件头部要以native申明函数。这三个函数的实现是在Vibrator.c (hardware\libhardware_legacy\vibrator)中,不同的JNI函数实现方法和地方是不同的。

(2)方法列表说明,static const JNINativeMethod method_table[]方法列表的原型如下:

typedef struct {const char* name;const char* signature;void* fnPtr;} JNINativeMethod;

 Andorid使用了一种Java 和 C 函数的映射表数组,并在其中描述了函数的参数和返回值。第一个变量name是Java中函数的名字;第二个变量signature,用字符串描述了函数的参数和返回值;第三个变量fnPtr是函数指针,指向C函数。其中比较难以理解的是第二个参数,例如:()Z  (J)V  ()V。实际上这些字符是与函数的参数类型一一对应的,"()" 中的字符表示参数,后面的则代表返回值。例如()V 就表示void Func(),(II)V 表示void Func(int, int),具体的每一个字符的对应关系如下:

字符   Java类型      C类型
V      void              void
Z       jboolean     boolean
I        jint                int
J       jlong            long
D      jdouble       double
F      jfloat            float
B      jbyte            byte
C      jchar           char
S      jshort          short

数组则以"["开始,用两个字符表示
[I       jintArray      int[]
[F     jfloatArray    float[]
[B     jbyteArray    byte[]
[C    jcharArray    char[]
[S    jshortArray   short[]
[D    jdoubleArray double[]
[J     jlongArray     long[]
[Z    jbooleanArray boolean[]

如果JAVA类位于一个嵌入类,则用$作为类名间的分隔符,比如:"android/os/FileObserver$ObserverThread"

===========================================================================================================

        下面举一个实例,运行Java程序直接调用WINDOWS的对话框:

(1)新建一个TestNew.java文件,输入以下内容:

public class TestNew {public static native void hello(String msg);static{System.loadLibrary("TestNew");}/** * @param args */public static void main(String[] args) {// TODO Auto-generated method stubhello("hello,kitty!");}}

        在配置好java的环境变量C:\Program Files\Java\jdk1.6.0_13\bin之后,用javac TestNew.java命令就生成了TestNew.class文件。
(2)在命令行中用javah TestNew,在class文件的基础上生成TestNew.h(就是jni代理stub的接口),内容如下:

/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class TestNew */#ifndef _Included_TestNew#define _Included_TestNew#ifdef __cplusplusextern "C" {#endif/* * Class:     TestNew * Method:    hello * Signature: (Ljava/lang/String;)V */JNIEXPORT void JNICALL Java_TestNew_hello  (JNIEnv *, jclass, jstring);#ifdef __cplusplus}#endif#endif

(3)在VC 6.0中新建一个win32 Dynamic-Link Library项目,项目名是TestNew。DLL类型选择a simple dll project,之后打开项目所在的文件目录,把步骤(2)生成的TestNew.h拷贝到此目录。点击左边中间的FileView,切换到文件浏览模式,在Header Files上点击右键,选择Add Files to Folder…。选择TestNew.h文件,点击OK。

      打开StdAfx.h文件,再最后面添加几行语句,#include <jni.h>,#include "TestNew.h",加完如下:

#include <windows.h>#include <jni.h>#include "TestNew.h"

       打开TestNew.cpp,在最后面添加一段代码:

JNIEXPORT void JNICALL Java_TestNew_hello(JNIEnv * env, jclass obj, jstring jMsg) {const char *strMsgPtr = env->GetStringUTFChars( jMsg , 0);    MessageBox( 0, strMsgPtr,"Message box from VC++ ", 0 ); env->ReleaseStringUTFChars( jMsg, strMsgPtr);  }

(4)在VC的菜单上选择Tools-Options…,打开选项对话框。在Directories文件夹,添加上jdk所在文件夹下的include和include\win32文件夹。


点击VC上的菜单项Build-Build All,生成TestNew.dll。

(5)VC项目Debug文件夹中的TestNew.dll复制到TestNew.class所在的文件夹下。在命令行下输入java TestNew,弹出MessageBox对话框。调用win32 api成功。如下:


参考原文:http://www.cnblogs.com/mandroid/archive/2011/06/15/2081093.html

参考原文:http://www.iteye.com/topic/304594#814127

参考原文:http://blog.csdn.net/flydream0/article/details/7088514