詳細は「表5.1「ネイティブレイヤーの型対応表」」と「表5.2「ライブラリがサポートする型(ネイティブレイヤーの処理前の対応)」」を参照ください。
JNAはJavaのプリミティブ型をC言語のデータ型に変換します。型の対応を真剣に考える必要があるJNIと比べると、JNAは比較的直感に近い型マッピングをします。
例えば、Javaのint型は、C言語のint型とマッピングされ、C言語のchar型は、Javaのbyte型にマップされます。このようにポインタ、配列を例外として、プリミティブ型に自動変換されます。
表5.1 ネイティブレイヤーの型対応表
| 型(C) | ネイティブ表現 | 型(Java) | 
| char | 8-bit整数 | byte | 
| wchar_t | プラットフォームに依存 | char | 
| short | 16-bit整数 | short | 
| int | 32-bit整数 | int | 
| int | booleanフラグ | boolean | 
| enum | enumeration型 | int (おおむね) | 
| long long, __int64 | 64-bit整数 | long | 
| float | 32-bit浮動小数点 | float | 
| double | 64-bit浮動小数点 | double | 
| pointer (例: void*) | プラットフォームに依存 (32- または 64-bitポインタ) | Buffer/Pointer | 
| pointer (例: void*),array | 32- or 64-bitポインタ、メモリの連続するブロック(structメンバー) | <P>[] (プリミティブ型配列) | 
またjava.lang.Stringのようなデータ型についても、C言語の「const char*」に変換される等、事後的にキャストや明示的変換を必要としません。
表5.2 ライブラリがサポートする型(ネイティブレイヤーの処理前の対応)
| 型(C) | ネイティブ表現 | 型(Java) | 
| long | プラットフォームに依存 (32- or 64-bit integer) | NativeLong | 
| const char* | NULL終端配列 (ネイティブencodingまたはjna.encoding) | String | 
| const wchar_t* | NULL終端配列 (unicode) | WString | 
| char** | c文字列のNULL終端配列 | String[] | 
| wchar_t** | Cワイド文字列のNULL終端配列 | WString[] | 
| void** | ポインタのNULL終端配列 | Pointer[] | 
| struct* | struct(引数、戻り値)を指すstructポインタ等 | Structure | 
| union | Structureと同じ | Union | 
| struct[] | structの配列, メモリの連続するブロック | Structure[] | 
| void (*FP)() | 関数ポインタ | Callback | 
| pointer (<T> *) | Pointerと同じ | PointerType | 
ポインタや配列を使うには、JNAのPointer型を使います。C言語の関数からポインタを受けた戻り値には抽象クラス「ByReference」を継承したサブクラスとして宣言します。
ByteByReference DoubleByReference FloatByReference IntByReference LongByReference NativeLongByReference PointerByReference ShortByReference
ちなみにこのByReferenceは、PointerTypeクラスのデータ型を指すポインタの機能を継承します。
public abstract class ByReference extends PointerType
このByReferenceのサブクラスであるByteByReferenceは、8ビット整数やchar型のメモリアドレスをポインタで渡す場合に使用できます。
public class ByteByReference extends ByReference
ではポインタを使ったJNAの実装例を見てみましょう。
まずC言語で、helloReplyという関数を作ってみましょう。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char* helloReply(const char* msg) {
        printf("%s\n",msg);
        msg = "I'm from C language!";
        return msg;
}この関数は文字列を引数とし、戻り値をcharを指すポインタとします。次にJavaでこの関数をマッピングしてみます。
interface HelloLib extends Library {
        HelloLib Instance = (HelloLib) Native.loadLibrary("hello", HelloLib.class);
        ByteByReference helloReply(String msg);
}
......
ByteByReference reply = hello.helloReply("Hello World! JNA!");
Pointer ptr = reply.getPointer();
String str = ptr.getString(0);
System.out.println(str);インターフェース内でマップする関数を宣言した後に、ポインタを「getPointer()」関数で取得します。さらにポインタのデータを「getString()」関数で取り出しています。
Copyright 2018-2019, by Masaki Komatsu