JNA

Javaを使って悪いことをしようとするとどうしても必要になるのがJNI(Java Native Interface)。JavaからC/C++コードを呼び出す手順は次のようになります。

  • あるクラスに修飾子nativeをつけたメソッドを宣言
  • そのソースをjavahツールに食わせる
  • C/C++用ヘッダファイルができる
  • インクルードしてそこに書かれているプロトタイプに合わせてCコードを書く
  • ダイナミックリンクライブラリとしてビルド(必要なヘッダファイルはJDKの中にある)
  • static initializer等を用いてnativeメソッドが呼ばれる前にSystem.loadLibrary()でネイティブライブラリをロード


それがJNA(Java Native Access)を使うとこの通り。Cコードは一切書いていません。

import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.WinNT.HANDLE;

/**
 * @author yappy
 */
public class Kernel32Ex {

  static {
    Native.register("kernel32");
  }

  public static final int PROCESS_VM_READ = 0x0010;
  public static final int PROCESS_QUERY_INFORMATION = 0x0400;

  public static native HANDLE OpenProcess(int dwDesiredAccess,
      int bInheritHandle, int dwProcessId);

  public static native int ReadProcessMemory(HANDLE hProcess,
      int lpBaseAddress, Pointer lpBuffer, int nSize,
      Pointer lpNumberOfBytesRead);

}

使い方は公式ページ(githubへ移行)からjna.jar(オプションでplatform.jarも)をダウンロードしてクラスパスを通すだけ。Win32APIもいくつかインポートしたものがplatform.jarに入っていますが、他に使いたいものがある場合はこのようにネイティブメソッド宣言を書いてNaitive.register()をstaticイニシャライザに書くだけで使えるようになります。
高速化、という理由では計算処理のループなどはJITコンパイルによってCと同等の速度が出るし、今ではネイティブコードが必要になるのはC関数が呼びたい時くらいしかないと言えるでしょう。
引数・返り値の型を見て適切にマーシャリングされます。それ用にラップされた型もあるのですが…。まあめんどくさくなってより生に近い型にしてしまうのは仕方ないね。


どうでもいいけどここのプログラムコード記法どうなってんだ。Eclipseのフォーマッタで1行80文字以内に抑えてるのにはみ出してるぞ。