QA@IT

EclipseでVC++のDLLを呼び出すサーブレットアプリを作成(jnaを使用)

6516 PV

現在Eclipse+Tomcatで、VC++のDLLを呼び出すアプリを作成しようとしています
ところが、DLLの呼び出しがどうにもうまくいきません
ブラウザに表示されるスタックトレースだと、
import com.sun.jna.Native;
が、見えなくなっているというようなエラーに見えるのですが、解釈が間違っているでしょうか

dllファイルは
「c:\dll\smpl.dll」
というファイルを配置しています

jnaファイルは
eclipseのプロジェクトを右クリックし、「ビルドパス」→「ビルドパスの構成」を選択し、
ライブラリータブで「jar追加」「外部jar追加」のどちらも試してみましたが、同じエラーになりました

dllの関数を実行したいだけなのですが、何か勘違いしているところがありましたら教えてください

●環境を追記します
 OS
  Windows7Pro/64bit

 Cアプリ
  VisualStudio 2012 UPDATE3 で 32bit DLLとしてコンパイル
 Javaアプリ(サーブレット)
  Eclipseの日本語版(Pleiades4.4のJava/Fullを32ビット版と64ビット版でそれぞれプロジェクトを作成)
  全部入りなのでそれぞれのTOMCATとJDK/JREは32ビットと64ビットが入っていて、
  32ビットで作成したプロジェクトは32ビットで動作、64ビットで作成したプロジェクトは64ビットで動作する物と思っていたのですが・・・

  32ビット用と64ビット用はワークプレイスを分けて混在しないようにはしています
 ソースを見やすくしてもらいありがとうございました

●追記2(Eclipseでは無く、javaをコマンドラインからコンパイル、実行してみました)
以下のような小さなソースを作って、コマンドラインからコンパイル、実行してみました

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

public class First{
    interface HelloLib extends Library{
        HelloLib INSTANCE=(HelloLib)Native.loadLibrary("c:/dll/smpl.dll",HelloLib.class);

        int ret10();
    }

    public static void main(String[] args){
        HelloLib h=HelloLib.INSTANCE;
        h.ret10();
    }
}

コンパイル
"C:\Program Files\Java\jdk1.8.0_45\bin\javac" -cp jna.jar First.java
実行
java -cp .:jna.jar; First
としたところ、やはり以下のようなエラーになりました
Exception in thread "main" java.lang.NoClassDefFoundError: com/sun/jna/Library
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.security.SecureClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.access$100(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at First.main(First.java:25)
Caused by: java.lang.ClassNotFoundException: com.sun.jna.Library
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 13 more

また、実行環境を以下で試してみても、全く同じエラーになってしまいました
"C:\Program Files\Java\jdk1.8.0_45\bin\java" -cp .:jna.jar; First
"C:\Program Files (x86)\Java\jre1.8.0_45\bin\java" -cp .:jna.jar; First
●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●追記ここまで

ブラウザに表示されたスタックトレースの内容
●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●

javax.servlet.ServletException: サーブレットの実行により例外を投げました
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)

原因
java.lang.NoClassDefFoundError: com/sun/jna/Native
    daysvr.DllJnaEx.<clinit>(DllJnaEx.java:7)
    daysvr.First.doGet(First.java:34)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)

原因
java.lang.ClassNotFoundException: com.sun.jna.Native
    org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1305)
    org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1157)
    daysvr.DllJnaEx.<clinit>(DllJnaEx.java:7)
    daysvr.First.doGet(First.java:34)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)

●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●

VC++側のソースファイル
dllソース●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●
・stdafx.h

#pragma once
#include "targetver.h"
#define WIN32_LEAN_AND_MEAN             // Windows ヘッダーから使用されていない部分を除外します。
// Windows ヘッダー ファイル:
#include <windows.h>
// 自動作成されたソースに関数定義を追加しただけ
int add(int left, int right);
int sub(int left, int right);
int ret10();

cppソース1●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●
・dllmain.cpp(自動作成されたソースはいじっていない)

#include "stdafx.h"
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

cppソース2●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●
・smpl.cpp

#include "stdafx.h"
int add(int left, int right) {//足し算する
    return left + right;
}
int sub(int left, int right) {//引き算する
    return left - right;
}
int ret10(){//固定値10
    return 10;
}

defソース●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●
・sorce.def

LIBRARY smpl
EXPORTS
add
sub 
ret10

exeファイルのソース●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●
//このソース自体はうまく動作する

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
int _tmain(int argc, _TCHAR* argv[])
{
    typedef int(*FUNC)(int x, int y);
    LPCTSTR lpFileName = _TEXT("smpl.dll");
    HMODULE hDll = LoadLibrary(lpFileName);
    if (hDll == NULL) {
        //printError("LoadLibrary", GetLastError());
        printf("sippai");
        return -1;
    }
    FUNC func = (FUNC)GetProcAddress(hDll, "add");
    if (NULL == func)
    {
        return 2;
    }
//うまくいく
    int ret = func(1, 2);
    return 0;
}

//エクリプス側のソース●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●
jna.jarをライブラリとして登録済み
インターフェースファイル●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●
・DllJnaEx.Java

package daysvr;
import com.sun.jna.Native;
public interface DllJnaEx {
    public  DllJnaEx INSTANCE = (DllJnaEx)Native.loadLibrary("c:/dll/smpl.dll",DllJnaEx.class);
    /**     * Cに足し算させます。     */
    int add(int left, int right);
    /**     * Cに引き算させます。     */
    int sub(int left, int right);    
    /**     * 単純に10を返す関数     */
    int ret10();
}

メインのファイル●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●
・First.Java

package daysvr;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/First")
public class First extends HttpServlet {
private static final long serialVersionUID = 1L;
    /**コンストラクタ     */
    public First() {
        super();
    }

    /**  * dllを呼びたい関数  */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //dll呼び込み初期化
        DllJnaEx dll = DllJnaEx.INSTANCE;
         // 1 + 2
        int addResult = dll.add(1, 2);
        // 3 - 2
        int subResult = dll.sub(5, 1);

        response.setContentType("text/html;charset=Windows-31J");
        PrintWriter out = response.getWriter();
        out.println("<html>");
        out.println("<body>");
        out.println("getから呼ばれた<br>");
        out.println(addResult);
        out.print("<br>");
        out.println(subResult);
        out.println("</body>");

        out.println("</html>");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//省略
    }

}
  • 環境が全然書いていないですが、CPUアーキテクチャも問題ないんですか?(64bitと32bitは一致してますか) -

回答

既に時間が経っているので解決されているかもしれませんが、

私の環境で追記2と同じコードで試してみましたが、
問題なく実行できました。

今出先なのでソースは載せられませんが、
Windows 8.1
64bit JDK(1.8.25)と、jna(3.0.9)、
VS2013 update 4
IntelliJ IDEA 14.1.1
で確認しました。

プロジェクトはVC++ / Win32 / Win32プロジェクト

dll を32bitでビルドすると、やはり動作しません。
文字セットはUNICODEでもマルチバイトでも動きました。

とりあえず、報告まで。

編集 履歴 (0)
ウォッチ

この質問への回答やコメントをメールでお知らせします。