Windows64bitでJNAでJavaからC++コード呼び出そうとしてハマった話

Javaからネイティブコード呼び出そうと思ったんです。
で、あんまりやる気もないんで、JNIじゃなくてJNAでやろうと思ったんです。
Windows7 64bitで。


ということで、まずMinGWインストールしたんです。
http://www.mingw.org/
んで、NetBeans7.1で「オプション」の「C/C++」のところの「ツールコレクション」で「ベースディレクトリ」に「MinGW\bin」を指定したんです。


それから「C/C++動的ライブラリ」プロジェクト作って、「newfile.c」って名前でこんなコード書きました。

#include <stdio.h>

void  hello(){
    printf("test\n");
}

それから「構築」ってやるとDLLができたんです。


あとはJavaからの呼び出しコード書こうと思って、まずはJNAのサイトからjna.jarをダウンロードしたんです。ググるたんびにjava.netのサイトに案内されて、githubにいちいち移動するのはめんどくさかったですけど。
https://github.com/twall/jna


それで、NetBeansで「Javaプロジェクト」を作って、ライブラリにさっきのjna.jarを追加して、Javaコードにこんな感じでJNA呼び出しのコード書いたんです。

package javajnaapplication11;

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

public class JavaJnaApplication11 {
    static String PATH = "C:/Users/naoki/libCppDynamicLibrary_1.dll";
    public static void main(String[] args) {
        Sample lib = (Sample) Native.loadLibrary(PATH , Sample.class);
        lib.hello();
    }
    
    interface Sample extends Library{
        void hello();
    }
}


それで実行したら、こんなエラー出たんです。

Exception in thread "main" java.lang.UnsatisfiedLinkError
    :Unable to load library 'libCppDynamicLibrary_1.dll'
    :指定されたモジュールが見つかりません。

パスの指定を間違えたと思って、/を\\にしたり、dllをc:\windows\system32に置いてみたり、拡張子をはずしてみたり、いろいろやってみたけどダメなんです。


Google先生に泣きついてみたけど「JNAはとっても簡単でみんな幸せ」としか答えてくれないんです。
ぼくは、もうどうしたらいいかわからなくなって、街にとびだしてビール飲んだりラーメン食べたりスーパーでインドの青鬼買って飲んだりしたけど関係ないので省略しますね。


それで、一応Linuxで試してみようと思って、Ubuntu 12.04で試したら、何事もなくうまくいくんです。これでJNAの使い方に問題がないってわかったんで、「ははぁ〜ん、これは64bit Windowsなのに32bit DLLが作られてるな」って思って。


あとはgccの64bitバイナリ吐くオプション調べればいいだけだと思って、ググってDLLプロジェクトの「プロジェクトプロパティ」で「構築」の「Cコンパイラ」の「追加のオプション」に「-m64」ってつけて構築してみたんです。
そしたら、sorryって謝られちゃった >_

newfile.c:1:0: sorry, unimplemented: 64-bit mode not compiled in


それでMinGWGCCの64bitバイナリ作れるようにしようと思って、MinGW64落としてきたんです。
http://sourceforge.net/projects/mingw-w64/
でも、ツールコレクションに追加して構築してもgcc.exeがないって言われるし、なんだか面倒だったのでやめました。


もう、NetBeans+MinGWにこだわっても仕方ないと思って、あきらめてVisual Studio入れることにしたんです。Expressですけど。
http://www.microsoft.com/japan/msdn/vstudio/express/


それで、こんなコード書いてDLL作ってみたんですけど、やっぱりおんなじエラーが出てしまうんです。

#include "stdafx.h"
#include <stdio.h>

extern "C"{

__declspec(dllexport)
void hello(){
    printf("test!\n");
}
};


プロジェクトのプロパティで64bit選ぼうとしても選択肢にWin32しかないんで、調べたらExpressは32bitバイナリしか作れないんですね。
それで、ここを参考に64bitバイナリが作れるようにしてみました。
http://d.hatena.ne.jp/torutk/20100927/p1


そしたら、あっけなく動いたんですね。もう、土曜日ずっと起きて日曜の朝まで作業して、プリキュアみようとしたらゴルフってなによ?じゃなくて、あの作業はなんだったんだ?って感じですよ。
たぶん、エラーメッセージが「指定されたモジュールが見つかりません。」じゃなくて、「モジュールが読み込めません」だったら、こんなに無駄ハマらなかったと思うんです。


そのあと「はは〜ん、32bit JDKなら32bit DLLでも動くのだな」と思って、試してみたら、ちゃんと動いたんです。はは〜ん。
これで作業はNetBeans+MinGWでできますね。もう一台のパソコンにVisual Studioの設定するの面倒なんです。HDDももったいないし。


結論としては、インドの青鬼はアルコール度数高めでおいしいです。欲しい物リストにも突っこんでおいたんで、送りつけてくれてもいいですよ。