Java Native Interface(3)

久々の更新です。
今日まで夏休みなんですが、どうしても気になっていたので作業することにしました。

と言うのは、C++コンパイル時の文字コードを"MBCS"から"UNICODE"にすると漢字が化けてしまったので、これを補正するために修正しました。

変更を加えたのは、jniwmi.cppのload_classの中で戻り値を設定する部分です。

/*
 *  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;
                VARIANT *value = results.getValue(prop, i);
                if (WmiResult::getType(value) == VT_BSTR) {
                    entry = _bstr_t(WmiResult::isByRef(value) ? *value->pbstrVal : value->bstrVal);
                }
                else {
                    entry = _bstr_t((_TCHAR *)WmiResult::getString(value).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;
}

戻りデータのタイプが"VT_BSTR"の時に、WmiResultクラスのgetStringメソッドで文字変換させるのではなく、load_class関数の中で行うことにしました。
テストしたプログラムは、

package wmi.test;

import wmi.WmiCall;
import wmi.WmiResult;

public class WmiCallTest {
    public WmiCallTest() {
        WmiCall wmi = new WmiCall();
        wmi.init();
        WmiResult logical_disk = wmi.access("SELECT * FROM Win32_LogicalDisk WHERE DeviceID = \"C:\"", true);
        System.out.println(logical_disk.print());

        wmi.term();
    }
    
    public static void main(String[] argv) {
        new WmiCallTest();
    }
}

これで、テストプログラムを実行した時に"Description"には正しくデータが表示できました。
C++のプログラムで処理している限りは何も問題なかったんだけど、Javaでアクセスすると文字が化けるんだよなぁ???