JNA (Java Native Access) 2013-08-08 [#u2f5915c]

Javaから直接DLLを使いたいと思っていて,調べていたらJNI (Java Native Interface)とかあるんだけど,ヘッダファイルとかを作成しないと使えないらしく,もっと簡単にDLLを呼び出す方法が,JNAということらしい。

JNAは,JNIより簡単にJavaとC/C++をつなぐ「JNA」とはとかWindows APIをJavaから呼び出す(JNA)とかWindows64bitでJNAでJavaからC++コード呼び出そうとしてハマった話を参考にしつつJNAのサイトhttps://github.com/twall/jnaGetting Startを動作させてみた。

とりあえずテキストというかターミナルで作業してみた。 JNAサイトから落としてきた,jna-4.0.0.jarとjna-platform-4.0.0.jarはソースと同じディレクトリフォルダに置くこととした。

サンプルソース
HelloWorld?.java

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

/** Simple example of JNA interface mapping and usage. */
public class HelloWorld {

    // This is the standard, stable way of mapping, which supports extensive
    // customization and mapping of Java to native types. 

    public interface CLibrary extends Library {
        CLibrary INSTANCE = (CLibrary)
            Native.loadLibrary((Platform.isWindows() ? "msvcrt" : "c"),
                               CLibrary.class); 

        void printf(String format, Object... args);
    }

    public static void main(String[] args) {
        CLibrary.INSTANCE.printf("Hello, World\n");
        for (int i=0;i < args.length;i++) {
            CLibrary.INSTANCE.printf("Argument %d: %s\n", i, args[i]);
        }
    }
}

コンパイル

javac -cp .;jna-4.0.0.jar;jna-platform-4.0.0.jar HelloWorld.java

実行

java -cp .;jna-4.0.0.jar;jna-platform-4.0.0.jar HelloWorld
Hello, World

というわけで,Windows Nativeのprintfを使うことができた。

ちなみにNetBeans?の場合,プロジェクト・プロパティのライブラリにjnaとjna-platformを追加すれば大丈夫

DLLが32bitか64bitか確認する。2013-08-23

  • 調べたいDLLをバイナリ―エディタで開く(秀丸のバイナリ―モードを使った)
  • 0x50450000を探す
  • その隣の2バイトに注目
    • 0x4C01なら32-bit x86 用
    • 0x6486なら64-bit amd64用

はい,こちらの記事のメモです。> Windows 64-bit 実行可能ファイル (EXE, DLL)の判別方法

JavaからJNAでDLLを呼んで,その先でDLLを... JNA DLL 多重 2013-08-23

使いたいNativeなDLLが当然だけど,CやC++から呼び出すので構造体へのポインタを渡している。これをJNAのマッピングに当てはめるのは骨が折れそうなので,もう一段DLLをかませてみた。
そうするとJavaからDLLを呼び出すときに2つのDLLを呼ばないと

Exception in thread "main" java.lang.UnsatisfiedLinkError: Unable to load library 'dll/hello.dll'

とエラーとなってしまう。
とりあえず,init()とか関数を作っておいて呼び出してみたらうまくいったんだけど,

HelloWorld.MyDLLDLL.INSTANCE.getClass();
HelloWorld.MyDLL.INSTANCE.getClass();

INSTANCE.getClass()をコールしておけばよいみたい。(本当はどうするのが正解なんだろう?)

というわけで,こんな感じ。 hello.c

#include <stdio.h>

int hello()
{
    hellohello();
}

hellohello.c

#include <stdio.h>

int hellohello()
{
    printf("Hello World!\n");
}

HelloWorld?.java

public class HelloWorld {
    public interface MyDLL extends Library {
        static String PATH = "dll/mydll.dll";
        MyDLL INSTANCE = (MyDLL)Native.loadLibrary(PATH, MyDLL.class); 

        void hello();
    }
    
    public interface MyDLLDLL extends Library {
        static String PATH = "dll/mydlldll.dll";
        MyDLLDLL INSTANCE = (MyDLLDLL)Native.loadLibrary(PATH, MyDLLDLL.class); 

        void hellohello();
        void init();
    }

    public static void main(String[] args) {
        HelloWorld.MyDLLDLL.INSTANCE.getClass();
        HelloWorld.MyDLL.INSTANCE.getClass();

        HelloWorld.MyDLL.INSTANCE.hello();
    }
}

mydlldll.dllはmydll.dllにstaticにリンクしているはずなんだけどなぁ。 とりあえず,メモ


Last-modified: 2013-08-23 (金) 19:20:36 (2214d)