S-JIS[2007-10-07] 変更履歴
“javahによって生成されたヘッダーファイル”内の関数を列挙するタスクです。→タスクのアーカイブ(hmant.jar)
javahによって生成されたヘッダーファイルでは、以下のように関数が宣言されています。
JNIEXPORT jstring JNICALL Java_jp_hishidama_win32_api_WinBase_FormatMessage (JNIEnv *, jclass, jint);
この「JNICALL」がある行の、その部分より後ろをカンマ付きで出力するだけです。…。
属性 | 説明 | 必須 |
---|---|---|
destdir | ファイルの出力先ディレクトリを指定する。 | No; デフォルトは、入力ファイルと同じ場所 |
prefix | 出力ファイルの接頭辞を指定する。 | No; デフォルトは、「jni_func. 」 |
suffix | 出力ファイルの接尾辞を指定する。 | No; デフォルトは、「.txt 」 |
force | (タイムスタンプを比較しない)強制上書きの有無を指定する。 | No; デフォルトは、no |
FileSetは、抽出対象のファイルを指定する。
build.xml:
<typedef resource="typedef.properties" classpath="lib/hmant.jar" />
<target name="jni_function">
<jnif prefix="jni_check." force="no">
<fileset dir="C:\vc2005\hmwin32">
<include name="jp_hishidama_win32_api_*.h" />
</fileset>
</jnif>
</target>
出力結果(jni_check.jp_hishidama_win32_api_WinBase.h):
Java_jp_hishidama_win32_api_WinBase_GetLastError, Java_jp_hishidama_win32_api_WinBase_FormatMessage,
VC++では宣言なしでも関数を定義できるしオーバーロードもできるので、ヘッダーファイルで指定した関数と違う関数を定義してもエラーになりません。(唯一、戻り値の型が違うときだけエラーになるけど)
なので、関数の数が多くて実装漏れがあったり一度作った関数の引数を変えたが修正を間違った場合などにもコンパイルエラーにはならず、実行時に落ちて発覚するという最悪の状態になってしまいます。
解決策としては、C++のコンパイルの範囲で関数を使用してやること。
関数をどこかで使っていれば、その関数が定義されていない場合にリンクエラーになるので分かります。
通常の関数呼び出しの他にグローバルに関数ポインターを保持するだけでも「使う」ことになるので、配列変数を定義して、その初期値として関数ポインターを書いてやればよいということです。
jni_check.cpp:
#ifdef _DEBUG
//javahによって生成されたヘッダーファイル
#include "jp_hishidama_win32_api_WinBase.h"
#include "jp_hishidama_win32_api_WinUser.h"
void *jni_func_check[] = {
//jnifによって生成した関数名
#include "jni_check.jp_hishidama_win32_api_WinBase.h"
#include "jni_check.jp_hishidama_win32_api_WinUser.h"
};
#endif
デバッグビルドのときだけ配列変数を定義します。実装漏れのJNI関数があるとリンクエラーになります。
リリースビルドではコンパイル対象外となるので、余計な領域は消費しません。