a284628487 / JniSample

0 stars 0 forks source link

Other #4

Open a284628487 opened 6 years ago

a284628487 commented 6 years ago

注册本地方法

RegisterNatives

jint RegisterNatives(JNIEnv env, jclass clazz, const JNINativeMethod methods, jint nMethods); 向clazz参数指定的类注册本地方法。methods参数将指定JNINativeMethod结构的数组,其中包含本地方法的名称、签名和函数指针。nMethods参数将指定数组中的本地方法数。JNINativeMethod 结构定义如下所示: typedef struct { char name; char signature; void fnPtr; } JNINativeMethod; 函数指针通常必须有下列签名: ReturnType (fnPtr)(JNIEnv *env, jobject objectOrClass, ...); 参数:env:JNI接口指针。clazz:Java类对象。methods:类中的本地方法。nMethods:类中的本地方法数。 返回值:成功时返回 “0”;失败时返回负数。 抛出:NoSuchMethodError:如果找不到指定的方法或方法不是本地方法。 UnregisterNatives

jint UnregisterNatives(JNIEnv *env, jclass clazz); 取消注册类的本地方法。类将返回到链接或注册了本地方法函数前的状态。该函数不应在常规平台相关代码中使用。相反,它可以为某些程序提供一种重新加载和重新链接本地库的途径。 参数:env:JNI接口指针。clazz:Java类对象。 返回值:成功时返回“0”;失败时返回负数。 监视程序操作

MonitorEnter

jint MonitorEnter(JNIEnv *env, jobject obj); 进入与obj所引用的基本Java对象相关联的监视程序。每个Java对象都有一个相关联的监视程序。如果当前线程已经拥有与obj相关联的监视程 序,它将使指示该线程进入监视程序次数的监视程序计数器增 1。如果与 obj 相关联的监视程序并非由某个线程所拥有,则当前线程将变为该监视程序的所有者,同时将该监视程序的计数器设置为 1。如果另一个线程已拥有与 obj 关联的监视程序,则在监视程序被释放前当前线程将处于等待状态。监视程序被释放后,当前线程将尝试重新获得所有权。 参数:env:JNI接口指针。obj:常规Java对象或类对象。 返回值:成功时返回“0”;失败时返回负数。 MonitorExit

jint MonitorExit(JNIEnv *env, jobject obj); 当前线程必须是与obj所引用的基本Java对象相关联的监视程序的所有者。线程将使指示进入监视程序次数的计数器减 1。如果计数器的值变为 0,当前线程释放监视程序。 参数:env:JNI接口指针。obj:常规Java对象或类对象。 返回值:成功时返回“0”;失败时返回负数。 Java虚拟机接口

GetJavaVM

jint GetJavaVM(JNIEnv *env, JavaVM **vm); 返回与当前线程相关联的Java虚拟机接口(用于调用API中)。结果将放在第二个参数vm所指向的位置。 参数:env:JNI接口指针。vm:指向放置结果的位置的指针。 返回值:成功时返回“0”;失败时返回负数。 调用API 调用API允许软件厂商将Java虚拟机加载到任意的本地程序中。厂商可以交付支持Java的应用程序,而不必链接Java虚拟机源代码。本章首先 概述了调用API。然后是所有调用API函数的引用页。若要增强Java虚拟机的嵌入性,可以用几种方式来扩展JDK 1.1.2中的调用API。 概述

以下代码示例说明了如何使用调用API中的函数。在本例中,C++代码创建Java虚拟机并且调用名为Main.test的静态方法。为清楚起见,我们略去了错误检查。

include

/* 其中定义了所有的事项 */
...
JavaVM *jvm;
/* 表示 Java 虚拟机*/
JNIEnv *env;
/* 指向本地方法接口的指针 */
JDK1_1InitArgs vm_args; /* JDK 1.1 虚拟机初始化参数 */
vm_args.version = 0x00010001; /* 1.1.2 中新增的:虚拟机版本 */
/* 获得缺省的初始化参数并且设置类路径 */
JNI_GetDefaultJavaVMInitArgs(&vm_args);
vm_args.classpath = ...;
/* 加载并初始化 Java 虚拟机,返回env中的JNI 接口指针 */
JNI_CreateJavaVM(&jvm, &env, &vm_args);
/* 用 JNI 调用 Main.test 方法 */
jclass cls = env->FindClass("Main");
jmethodID mid = env->GetStaticMethodID(cls, "test", "(I)V");
env->CallStaticVoidMethod(cls, mid, 100);
/* 结束。*/
jvm->DestroyJavaVM();

本例使用了API中的三个函数。调用API允许本地应用程序用JNI接口指针来访问虚拟机特性。其设计类似于Netscape的JRI嵌入式接口。 创建虚拟机

JNI_CreateJavaVM()函数加载并初始化Java虚拟机,然后将指针返回到JNI接口指针。调用JNI_CreateJavaVM()的线程被看作主线程。 连接虚拟机

JNI接口指针(JNIEnv)仅在当前线程中有效。如果另一个线程需要访问Java虚拟机,则该线程首先必须调用 AttachCurrentThread()以将自身连接到虚拟机并且获得JNI接口指针。连接到虚拟机之后,本地线程的工作方式就与在本地方法内运行的 普通Java线程一样了。本地线程保持与虚拟机的连接,直到调用DetachCurrentThread()时才断开连接。 卸载虚拟机

主线程不能自己断开与虚拟机的连接。而是必须调用DestroyJavaVM()来卸载整个虚拟机。 虚拟机等到主线程成为唯一的用户线程时才真正地卸载。用户线程包括Java线程和附加的本地线程。之所以存在这种限制是因为Java线程或附加的本 地线程可能正占用着系统资源,例如锁,窗口等。虚拟机不能自动释放这些资源。卸载虚拟机时,通过将主线程限制为唯一的运行线程,使释放任意线程所占用系统 资源的负担落到程序员身上。 初始化结构

不同的Java虚拟机实现可能会需要不同的初始化参数。很难提出适合于所有现有和将来的Java虚拟机的标准初始化结构。作为一种折衷方式,我们保 留了第一个域(version)来识别初始化结构的内容。嵌入到JDK 1.1.2中的本地应用程序必须将版本域设置为0x00010001。尽管其它实现可能会忽略某些由JDK所支持的初始化参数,我们仍然鼓励虚拟机实现使 用与JDK一样的初始化结构。0x80000000到0xFFFFFFFF之间的版本号需保留,并且不为任何虚拟机实现所识别。 以下代码显示了初始化JDK 1.1.2中的Java虚拟机所用的结构。 typedef struct JavaVMInitArgs { / 前两个域在 JDK 1.1 中保留,并在 JDK 1.1.2 中正式引入。/ / Java 虚拟机版本 / jint version; / 系统属性。/ char *properties; / 是否检查 Java 源文件与已编译的类文件之间的新旧关系。/ jint checkSource; / Java 创建的线程的最大本地堆栈大小。/ jint nativeStackSize; / 最大 Java 堆栈大小。/ jint javaStackSize; / 初始堆大小。/ jint minHeapSize; / 最大堆大小。/ jint maxHeapSize; / 控制是否校验 Java 字节码:0 无,1 远程加载的代码,2 所有代码。/ jint verifyMode; / 类加载的本地目录路径。/ const char classpath; / 重定向所有虚拟机消息的函数的钩子。/ jint (vfprintf)(FILE fp, const char format, va_list args); / 虚拟机退出钩子。/ void (exit)(jint code); / 虚拟机放弃钩子。/ void (abort)(); / 是否启用类 GC。/ jint enableClassGC; / GC 消息是否出现。/ jint enableVerboseGC; / 是否允许异步 GC。/ jint disableAsyncGC; / 三个保留的域。/ jint reserved0; jint reserved1; jint reserved2; } JDK1_1InitArgs; 在JDK 1.1.2中,初始化结构提供了钩子,这样在虚拟机终止时,本地应用程序可以重定向虚拟机消息并获得控制权。当本地线程与JDK 1.1.2中的Java虚拟机连接时,以下结构将作为参数进行传递。实际上,本地线程与JDK 1.1.2连接时不需要任何参数。JDK1_1AttachArgs 结构仅由C编译器的填充槽组成,而C编译器不允许空结构。 typedef struct JDK1_1AttachArgs { /

JavaVM类型是指向调用API函数表的指针。以下代码示例显示了这种函数表。 typedef const struct JNIInvokeInterface *JavaVM;

const struct JNIInvokeInterface ... = { NULL, NULL, NULL, DestroyJavaVM, AttachCurrentThread, DetachCurrentThread, }; 注意,JNI_GetDefaultJavaVMInitArgs()、JNI_GetCreatedJavaVMs()和JNI_CreateJavaVM() 这三个调用API函数不是JavaVM函数表的一部分。不必先有JavaVM结构,就可以使用这些函数。 JNI_GetDefaultJavaVMInitArgs

jint JNI_GetDefaultJavaVMInitArgs(void *vm_args); 返回Java虚拟机的缺省配置。在调用该函数之前,平台相关代码必须将vm_args->version 域设置为它所期望虚拟机支持的JNI版本。在JDK 1.1.2中,必须将vm_args->version设置为0x00010001。(JDK 1.1不要求平台相关代码设置版本域。为了向后兼容性,如果没有设置版本域,则JDK 1.1.2假定所请求的版本为0x00010001。JDK的未来版本将要求把版本域设置为适当的值。)该函数返回后,将把 vm_args->version设置为虚拟机支持的实际JNI版本。 参数:vm_args:指向VM-specific initialization(特定于虚拟机的初始化)结构的指针,缺省参数填入该结构。 返回值:如果所请求的版本得到支持,则返回“0”;如果所请求的版本未得到支持,则返回负数。 JNI_GetCreatedJavaVMs

jint JNI_GetCreatedJavaVMs(JavaVM *vmBuf, jsize bufLen, jsize nVMs); 返回所有已创建的Java虚拟机。将指向虚拟机的指针依据其创建顺序写入vmBuf缓冲区。最多写入bufLen项。在*nVMs中返回所创建虚拟机的总数。JDK 1.1不支持在单个进程中创建多个虚拟机。 参数:vmBuf:指向将放置虚拟机结构的缓冲区的指针。bufLen:缓冲区的长度。nVMs:指向整数的指针。 返回值:成功时返回“0”;失败则返回负数。 JNI_CreateJavaVM

jint JNI_CreateJavaVM(JavaVM p_vm, JNIEnv p_env, void *vm_args); 加载并初始化Java虚拟机。当前线程成为主线程。将env参数设置为主线程的JNI接口指针。JDK 1.1.2不支持在单个进程中创建多个虚拟机。必须将vm_args中的版本域设置为0x00010001。 参数:p_vm:指向位置(其中放置所得到的虚拟机结构)的指针。p_env:指向位置(其中放置主线程的 JNI 接口指针)的指针。vm_args: Java 虚拟机初始化参数。 返回值:成功时返回“0”;失败则返回负数。 DestroyJavaVM

jint DestroyJavaVM(JavaVM *vm); 卸载Java虚拟机并回收资源。只有主线程能够卸载虚拟机。调用DestroyJavaVM() 时,主线程必须是唯一的剩余用户线程。 参数:vm:将销毁的Java虚拟机。 返回值:成功时返回“0”;失败则返回负数。 JDK 1.1.2 不支持卸载虚拟机。 AttachCurrentThread

jint AttachCurrentThread(JavaVM *vm, JNIEnv *p_env, void thr_args); 将当前线程连接到Java虚拟机。在JNIEnv参数中返回JNI接口指针。试图连接已经连接的线程将不执行任何操作。本地线程不能同时连接到两个Java虚拟机上。 参数:vm:当前线程所要连接到的虚拟机。p_env:指向位置(其中放置当前线程的 JNI 接口指针)的指针。thr_args:特定于虚拟机的线程连接参数。 返回值:成功时返回“0”;失败则返回负数。 DetachCurrentThread

jint DetachCurrentThread(JavaVM *vm); 断开当前线程与Java虚拟机之间的连接。释放该线程占用的所有Java监视程序。通知所有等待该线程终止的Java线程。主线程(即创建Java 虚拟机的线程)不能断开与虚拟机之间的连接。作为替代,主线程必须调用JNI_DestroyJavaVM()来卸载整个虚拟机。 参数:vm:当前线程将断开连接的虚拟机。 返回值:成功时返回“0”;失败则返回负数。 CreateFile

(1)函数原型 HANDLE CreateFile( LPCTSTR lpfileName, DWORD deDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes DWORD dwCreationDesposition, DWORD dwFlagsAndAtrributes, HANDLE hTemplateFile ); (2)函数说明 该函数创建、打开或截断一个文件,并返回一个能够被用来存取该文件的句柄。此句柄允许读书据、写数据以及移动文件的指针。CreateFile函数既可以做为一个宽自负函数使用,也可以作为一个ANSI函数来用。 (3)参数说明 lpFileName:指向文件字符串的指针。dwDesireAccess:制定文件的存取模式,可以取下列值:0:制定可以查询对象。 GENERIC_READ:指定可以从文件中度去数据。GENERIC_WRITE:指定可以向文件中写数据。dwShareMode:指定文件的共享模 式,可以取下列值: 0:不共享。 FILE_SHARE_DELETE:在 Windows NT 系统中,只有为了删除文件而进行的打开操作才会成功。 FILE_SHARE_READ:只有为了从文件中度去数据而进行的打开操作才会成功。 FILE_SHARE_WRITE:只有为了向文件中写数据而进行的打开操作才会成功。 lpSecurityAttributes:指定文件的安全属性。dwCreationDisopsition:指定创建文件的方式,可以取以下值: CREATE_NEW:创建新文件,如果文件已存在,则函数失败。 CREATE_ALWAYS:创建爱内心文件,如果文件已存在,则函数将覆盖并清除旧文件。 OPEN_EXISTING:打开文件,如果文件不存在,函数将失败。 OPEN_ALWAYS:打开文件,如果文件不存在,则函数将创建一个新文件。 TRUNCATE_EXISTING:打开外呢间,如果文件存在,函数将文件的大小设为零,如果文件不存在,函数将失败返回。 dwFlagsAndAtrributes:指定新建文件的属性和标志,它可以取以下值:1. FILE_ATTRIBUTE_ARCHIVE:归档属性。2. FILE_ATTRIBUTE_HIDDEN:隐藏属性。3. FILE_ATTRIBUTE_NORMAL:正常属性。4. FILE_ATTRIBUTE_READONLY:只读属性。5. FILE_ATTRIBUTE_SYSTEM:系统文件。6. FILE_ATTRIBUTE_TEMPORARY:临时存储文件,系统总是将临时文件的所有数据读入内存中,以加速对该文件的访问速度。用户应该尽快删 除不再使用的临时文件。7. FILE_FLAG_OVERLAPPED:用户可以通过一个 OVERLAPPED 结构变量来保存和设置文件读写指针,从而可以完成重叠式的读和写。一般用于数量比较大的读些操作。 hTemplateFile:指向一个具有GENERIC_READ属性的文件的句柄,该文件为要创建的文件提供文件属性和文件扩展属性。 (4)注意事项 函数成功将返回指定文件的句柄,否则返回NULL。 (5)典型示例: ... char szFile[64]; HANDLE handle; unsigned long lWritten,lRead;

handle = CreateFile("c:\\windows\\desktop\\example.txt",GENERIC_READ|GENERIC_W
                    RITE,FILE_SHARE_READ,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);

if(handle==INVALID_HANDLE_VALUE){
    MessageBox(NULL,"Error Create File!","Error",MB_OK);
    break;
}else
    MessageBox(NULL,"Open file Success!","Open file",MB_OK);