Hatena::ブログ(Diary)

diaの備忘録

2011年07月02日

JNAを用いたdllの賢い呼び出し方

DLLがjarに入ってままだと、com.sun.jna.Native.loadLibrary から呼び出しできません。

それのうまい回避方法です。あと、わかりやすい呼び方にします。

まずは、必要なソースを3つ用意します。

tk/dmap/jna/AbstractImport.java

package tk.dmap.jna;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;

import com.sun.jna.Native;

abstract class AbstractImport {
	protected static String getLibraryPath(Class<?> cls) {		
		final String resourcePath = "/"+cls.getName().replace('.', '/').replace('$', '.');
		final String[] libName = resourcePath.substring( resourcePath.lastIndexOf('/')+1 ).split("\\.");
		
		final URL url = Native.class.getResource(resourcePath);

		File libFile = null;
		if (url.getProtocol().toLowerCase().equals("file")) {
			try { libFile = new File(new URI(url.toString())); }
			catch (URISyntaxException e) { libFile = new File(url.getPath()); }
			if (!libFile.exists()) {
				throw new Error("File URL " + url + " could not be properly decoded");
			}
		} else {
			InputStream is = Native.class.getResourceAsStream(resourcePath);
			if (is == null) {
				throw new Error("Can't obtain InputStream");
			}

			FileOutputStream fos = null;
			try {
				libFile = File.createTempFile(libName[0], "." + libName[1]);
				libFile.deleteOnExit();

				fos = new FileOutputStream(libFile);
				int count;
				byte[] buf = new byte[4096];
				while ((count = is.read(buf, 0, buf.length)) > 0) {
					fos.write(buf, 0, count);
				}
			} catch (IOException e) {
				throw new Error("Failed to create temporary file for a library: " + e);
			} finally {
				try { is.close(); }
				catch (IOException e) {}
				if (fos != null) {
					try { fos.close(); }
					catch (IOException e) {}
				}
			}
		}
		
		return libFile.getAbsolutePath();
	}
}

tk/dmap/jna/Hook.java

package tk.dmap.jna;

import com.sun.jna.Library;
import com.sun.jna.Native;

public final class Hook extends AbstractImport {
	public static dll dll = (dll)Native.loadLibrary(getLibraryPath(dll.class) , dll.class );
	
	private Hook() {}
	
	public static final int HOOKED_SCANCODE = /*OS.WM_USER + */1;
	public static final int HOOKED_IME_RESULTSTR = /*OS.WM_USER + */2;

	public interface dll extends Library {
		public boolean begin(int hWnd);
		public void end();
	}
}

tk/dmap/jna/Main.java

package tk.dmap;

import tk.dmap.jna.Hook;

public class Main {
	public static void main(String[] args) {
		Hook.dll.begin(0);
		Hook.dll.end();
	}
}

その他タスク

  1. 「dll」とか妥当な名前で、ソース・フォルダを作成する
  2. tk/dmap/jna/Hook.dll となるようにdllを置く

以下のようになるはずです。

f:id:DianthuDia:20110703001534p:image

まとめ

「Hook.dll.関数名」でネイティブコードにアクセスできます!

※Hookクラスの「dll」というインターフェース名は変更しないように注意。

トラックバック - http://d.hatena.ne.jp/DianthuDia/20110702/1309620043
リンク元