Java Native Interface(2-2)

Javawをコンパイルした後に、JNI用にヘッダファイルを生成します。

# javah wmi/WmiCall.class

で、wmi_WmiCall.hファイルが生成されます。

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class wmi_WmiCall */

#ifndef _Included_wmi_WmiCall
#define _Included_wmi_WmiCall
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     wmi_WmiCall
 * Method:    classinit
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_wmi_WmiCall_classinit
  (JNIEnv *, jclass);

/*
 * Class:     wmi_WmiCall
 * Method:    init
 * Signature: ()Z
 */
JNIEXPORT jboolean JNICALL Java_wmi_WmiCall_init
  (JNIEnv *, jclass);

/*
 * Class:     wmi_WmiCall
 * Method:    term
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_wmi_WmiCall_term
  (JNIEnv *, jclass);

/*
 * Class:     wmi_WmiCall
 * Method:    access
 * Signature: (Ljava/lang/String;Z)Lwmi/WmiResult;
 */
JNIEXPORT jobject JNICALL Java_wmi_WmiCall_access
  (JNIEnv *, jclass, jstring, jboolean);

/*
 * Class:     wmi_WmiCall
 * Method:    link
 * Signature: (Ljava/lang/String;Z)Lwmi/WmiResult;
 */
JNIEXPORT jobject JNICALL Java_wmi_WmiCall_link
  (JNIEnv *, jclass, jstring, jboolean);

#ifdef __cplusplus
}
#endif
#endif

呼び出されるDLLは、WmiCallでSystem.loadLibrary("jniwmi");と記述してあるので、jniwmi.dllという名前で作成します。
ヘッダファイルは
jniwmi.h

#ifndef _JNI_WMI_CALL
#define _JNI_WMI_CALL

#include <windows.h>

#include "wmi.h"

#include "wmi_WmiCall.h"

jclass      wc_class;           /* WmiCall */
jmethodID   wc_ctor;            /* WmiCall() */

jclass      wr_class;           /* WmiResult */
jmethodID   wr_ctor;            /* WmiResult() */
jfieldID    wr_propertiesID;    /* WmiResult.properties */
jfieldID    wr_resultID;        /* WmiResult.result */

jclass      str_class;          /* String */
jclass      vector_class;       /* Vector */
jmethodID   vector_init;        /* Vector() */
jmethodID   vector_add;         /* Vector.add(Object) */

#endif  //  _JNI_WMI_CALL

プログラム本体は

#include "jniwmi.h"

BOOL APIENTRY DllMain(HMODULE hModule,
                      DWORD  ul_reason_for_call,
                      LPVOID lpReserved) {
    return TRUE;
}

static WmiCall wmi;

/*
 *  WmiCallからの結果をJavaのクラスに展開する処理
 */
jobject load_class(JNIEnv *env, jclass cls, WmiResult results) {
    /*
     *  WmiResultオブジェクトの生成
     */
    jobject wmiObj = env->NewObject(wr_class, wr_ctor);

    /*
     *  プロパティ値の設定
     */
    size_t prop_count = results.items();
    jobjectArray properties = env->NewObjectArray((jsize)prop_count, str_class, NULL);
    for (size_t i = 0; i < prop_count; i++) {
        _bstr_t prop = _bstr_t((_TCHAR *)results.getProperty(i).c_str());
        jobject prop_str = env->NewString((const jchar *)((wchar_t *)prop), (jsize)prop.length());
        env->SetObjectArrayElement(properties, (jsize)i, prop_str);
    }
    env->SetObjectField(wmiObj, wr_propertiesID, properties);

    /*
     *  戻り値の設定
     */
    size_t row = results.size();
    if (row > 0) {
        jobjectArray result = env->NewObjectArray((jsize)row, vector_class, NULL);
        for (size_t i = 0; i < row; i++) {
            jobject vector = env->NewObject(vector_class, vector_init);
            for (size_t j = 0; j < prop_count; j++) {
                String prop = results.getProperty(j);
                _bstr_t entry = _bstr_t((_TCHAR *)results.getString(prop, i).c_str());
                jobject entry_str = env->NewString((const jchar *)((wchar_t *)entry), (jsize)entry.length());
                jboolean res = env->CallBooleanMethod(vector, vector_add, entry_str);
            }
            env->SetObjectArrayElement(result, (jsize)i, vector);
        }
        env->SetObjectField(wmiObj, wr_resultID, result);
    }
    return wmiObj;
}

/*
 *  JNIの初期化処理
 */
JNIEXPORT void JNICALL Java_wmi_WmiCall_classinit(JNIEnv *env, jclass cls) {
    wc_class = (jclass)env->NewGlobalRef(cls);
    wc_ctor = env->GetMethodID(wc_class, "<init>", "()V");

    /*
     *  WmiResultクラスの情報を設定
     */
    wr_class = env->FindClass("wmi/WmiResult");
    wr_class = (jclass)env->NewGlobalRef(wr_class);
    wr_propertiesID = env->GetFieldID(wr_class, "properties", "[Ljava/lang/String;");
    wr_resultID = env->GetFieldID(wr_class, "result", "[Ljava/util/Vector;");
    wr_ctor = env->GetMethodID(wr_class, "<init>", "()V");

    /*
     *  Stringクラスの情報を設定
     */
    jclass clazz = env->FindClass("java/lang/String");
    str_class = (jclass)env->NewGlobalRef(clazz);
    env->DeleteLocalRef(clazz);

    /*
     *  Vectorクラスの情報を設定
     */
    clazz = env->FindClass("java/util/Vector");
    vector_class = (jclass)env->NewGlobalRef(clazz);
    vector_init = env->GetMethodID(vector_class, "<init>", "()V");
    vector_add = env->GetMethodID(vector_class, "add", "(Ljava/lang/Object;)Z");
    env->DeleteLocalRef(clazz);
}

/*
 *  public static native boolean init()
 */
JNIEXPORT jboolean JNICALL Java_wmi_WmiCall_init(JNIEnv *env, jclass cls) {
    wmi.init();
    return wmi.initialized();
}

/*
 *  public static native void term()
 */
JNIEXPORT void JNICALL Java_wmi_WmiCall_term(JNIEnv *env, jclass cls) {
    wmi.term();
}

/*
 *  public static native WmiResult access(String query, boolean withValue)
 */
JNIEXPORT jobject JNICALL Java_wmi_WmiCall_access(JNIEnv *env, jclass cls, jstring query, jboolean with_value) {
    const jchar *query_buf  = env->GetStringChars(query, NULL);
    _bstr_t query_stmt = _bstr_t((wchar_t*)query_buf);
    env->ReleaseStringChars(query, query_buf);

    String select_stmt = String((_TCHAR *)query_stmt);
    WmiResult results = wmi.access(select_stmt, (with_value != 0) ? true : false);
    return load_class(env, cls, results);
}

/*
 *  public static native WmiResult link(String query, boolean withValue)
 */
JNIEXPORT jobject JNICALL Java_wmi_WmiCall_link(JNIEnv *env, jclass cls, jstring query, jboolean with_value) {
    const jchar *query_buf  = env->GetStringChars(query, NULL);
    _bstr_t query_stmt = _bstr_t((wchar_t*)query_buf);
    env->ReleaseStringChars(query, query_buf);

    String select_stmt = String((_TCHAR *)query_stmt);
    WmiResult results = wmi.link(select_stmt, (with_value != 0) ? true : false);
    return load_class(env, cls, results);
}

このままだと、SAFEARRAYの処理が出来ていないのと、C++ライブラリのWmiCallをstaticに保存しているのでマルチスレッドには対応できないので、この先頑張って対応していきます。
ただ、明日から遅い夏休みなので、続きは来週以降ということで・・・。