2009年12月17日 星期四

JNI

使用 JNI 最保險的方式是透過 LoadLibrary 導入 jvm.dll。
首先設好 include 和 lib path,這個網路上資料很多,可自行查找。

錯誤排解:

[1] 發生 Java 異常 EXCEPTION_ACCESS_VIOLATION (0xc0000005):
表示 jvm.dll 位置有誤。
直接指定到 /jre/bin/client/ 去 LoadLibrary 就行,
任何「多餘」的拷貝、指定動作都可能引起此異常。

[2] JNI_CreateJavaVM 傳回 JNI_ERR:
「可能」是先前安裝過多個 JDK 或 JRE 版本,
因未移除,或未移除乾淨,互相干擾所致。
解法是直接 load jvm.dll。

[3] Dev C++ 如何加 -ljvm?
沒時間試驗,但至少 lib path 要設對。

Test.java
public class Test 
{
    public static void hello () {
         System.out.print ("hello~");
    }    
    public static void main (String[]s) {}
}
以 javap -s -p Test 觀察各 method 的 Signature,
供 GetStaticMethodID 識別調用。
#undef UNICODE
#pragma comment (lib,"jvm.lib")
#include "windows.h"
#include "jni.h"
#include <iostream>
using namespace std;

#define CHECK(o) if(o); else{\
    cout<<__FILE__<<" ("<<__LINE__<<"): not satisfy "<<#o ;\
    exit (getchar());\
    }

typedef jint (WINAPI* PFunCreateJavaVM) (JavaVM**, void**, void*);

int main ()
{
    JavaVMOption   opt[4]  = {
        {"-Djava.compiler=NONE",0},
        {"-Djava.class.path=." ,0},
    };
    JavaVMInitArgs vm_args = {
        JNI_VERSION_1_2, 2, opt, JNI_TRUE      //opt = JRE 運行參數
    };  
    JNIEnv* env = 0;
    JavaVM* jvm = 0;
   

    HINSTANCE hInst = LoadLibrary ("C:/Java/jre/bin/client/jvm.dll");
    CHECK (hInst != 0);

    PFunCreateJavaVM CreateJavaVM = 
        (PFunCreateJavaVM) GetProcAddress (hInst, "JNI_CreateJavaVM");
    
    CreateJavaVM (&jvm, (void**)&env, &vm_args);
    CHECK (env != 0);

    jclass  cls = env->FindClass ("Test");      //查找 Java 類別
    CHECK (cls != 0);

    jmethodID pfn = env->GetStaticMethodID (cls, "hello", "()V");
    CHECK (pfn != 0);
    env->CallStaticVoidMethod (cls, pfn);

    if (env->ExceptionOccurred ()) {
        env->ExceptionDescribe ();
    }
    jvm->DetachCurrentThread ();
    jvm->DestroyJavaVM ();

    return getchar();
}

沒有留言:

張貼留言