読者です 読者をやめる 読者になる 読者になる

たぷつきません

おなかがでてきた。もうたぷついてるやん。

JNAなるもの

 eclipse/pluginsの中にcom.sun.jna_3.0.5なるものが。class郡を覗くとJNIを呼ぶためのラッパっぽい感じなので気になって検索かけたら発見。https://jna.dev.java.net
 JNIなしでネイティブライブラリにJavaから直接アクセスできるものらしい。対応OSも充実している*1
 JNAはかなり便利にできている。もうJNI使わなくて良し。ライブラリに対応するインターフェースを用意して、その中に関数を定義しておき、そのインターフェース型を指定してネイティブライブラリをロードするという芸当ができる。メソッドに勝手にマッピングしてくれて実装したクラスインスタンスを作ってくれちゃうのだ!
 以下はWin32APIのメッセージボックスだけの例。

import com.sun.jna.Native;
import com.sun.jna.WString;
import com.sun.jna.win32.StdCallLibrary;

public interface User32 extends StdCallLibrary {

    User32 INSTANCE = (User32)Native.loadLibrary("user32", User32.class);

    int MessageBoxA(int hwnd, String message, String title, int type);
    int MessageBoxA(int hwnd, byte[] message, byte[] title, int type);

    int MessageBoxW(int hwnd, WString message, WString title, int type);
    int MessageBoxW(int hwnd, char[] message, char[] title, int type);
}

 StdCallLibraryを継承するのはWin32の場合だけ。他のプラットフォームではLibraryを継承する。Native.loadLibraryには、ライブラリ名とインターフェース型を渡す。ライブラリ名はWinの場合は拡張子を除いたもの。他のプラットフォームの場合は頭の"lib"と末尾の".so"を除いたものとなる。
 ANSI文字列とWIDE文字列との違いをチェックするために上記例ではメソッドをいくつか用意した。ANSI文字列の場合は日本語はエンコーディングしないとならない。勝手にShift_JISとは見なしてくれない。jnaのドキュメントに書いているけど、StringとWStringは、末尾にヌル文字を自動的に付加してくれる。対応する配列を使う場合は自前でヌル文字をつけなければならない。
 以下が使用例。

import static User32.INSTANCE;
// :    
    public void doubleClick(DoubleClickEvent event) {
        int result = MessageBoxA(0, "like beer?", "confirm", 0x24);
        if (result == 6) {
            MessageBoxW(0, L("よろしい"), L("ほむほむ"), 0x40);
        } else {
            MessageBoxW(0, "なんと…去りなさい\0".toCharArray(), "げげ!\0".toCharArray(), 0x30);
            
            try {
                MessageBoxA(0, "あばよ!\0".getBytes("Windows-31J"), "お別れ\0".getBytes("Windows-31J"), 0x10);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
    }

    public static WString L(String ansiString) {
        return new WString(ansiString);
    }

 svnからソースをチェックアウトすればサンプルコードも豊富なので、↑よりももっと理解しやすい。RCPから気軽にネイティブを叩けるというのはかなり良さげ。

*1:includes support for OSX (ppc/x86/x86_64), Linux (x86/amd64), Windows (x86/x86_64), Solaris (x86/amd64/sparc/sparcv9), freeBSD (x86/amd64), and openBSD (x86).とのこと