2

EclipseのJavaアプリケーションでdllを使用しようとしていますが、そのdllに関連付けられているメソッドを呼び出そうとすると、ランタイム例外が発生します。

dllは、Eclipseの実行/デバッグ設定で渡した次のアドレスに存在します。

-Djava.library.path="C:\Program Files\NPortAdminSuite\ipserial\lib\x86;${env_var:PATH}"

コード:

クラステスト{

  public native int nsio_init();

  public static void main(String[] args) {
          System.loadLibrary("ipserial");
          new Test().nsio_init(); //This part is throwing an exception
  }
}

エラー:

Exception in thread "main" java.lang.UnsatisfiedLinkError: NPortConnection.nsio_init()I
    at Test.nsio_init(Native Method)
    at Test.main(Test.java:27)

このコマンドdumpbin /exports "C:\Program Files\NPortAdminSuite\ipserial\lib\x86\IPSerial.dll"は、そのdllから呼び出そうとしているメソッドの名前も返します。 ここに画像の説明を入力してください

誰かがこの問題を解決する方法を教えてもらえますか?

4

2 に答える 2

4

Javaコードから直接dll関数を呼び出そうとしているようです。これは(直接)不可能です。Javaとネイティブdllの間で変換するレイヤーを作成する必要があります。

これらのリソースをご覧ください。


この問題を回避するもう1つの方法は、JNAを使用することです。たとえば、ウィキペディアの記事を確認してください。

于 2012-07-02T05:56:05.233 に答える
2

編集:下部のプリプロセッサマクロの代わりに関数を使用したこのエレガントな回答   も参照してください。


JNIを実装したい場合は、次のようにします。

ファイル内の以下のクラスを想像してみましょうexample.java

package my.group.mypackage;

public class Example {
  static {
    System.loadLibrary("my-DLL-name");
  }

  public Example() {
    /* ... */
  }

  private native int    function1(int); //declare DLL functions
  private native String function2(int); //using the keyword
  private native void   function3(int); //'native'

  public void dosomething(int value) {
    int result = function1(value);  
    String str = function2(value);  //call your DLL functions
    function3(value);               //as any other java function
  }
}

(またはEDIまたはMavenを使用して...)example.classから生成します。次に、を使用してC /C++ヘッダーファイルを生成します。example.javajavacJava_my_group_mypackage_example.hexample.classjavah

C /C++関数の宣言はにありJava_my_group_mypackage_example.hます。ここで、たとえば、これらの関数の定義(本体)を実装Java_my_group_mypackage_example.cppします。他のDLLからの例外をキャッチするには、(Cではなく)C++を使用することをお勧めします。

JNIEXPORT jlong JNICALL Java_my_group_mypackage_example_function1
  (JNIEnv *env, jobject object, jlong value)
{
  try 
  {
    /* ... my processing ... */
    return jlong(result);
  }
  CATCH_CPP_EXCEPTION_AND_THROW_JAVA_EXCEPTION
  return 0;
}

JNIEXPORT jstring JNICALL Java_my_group_mypackage_example_function2
  (JNIEnv *env, jobject object, jlong value)
{
  try 
  {
    /* ... my processing ... */
    jstring jstr = env->NewStringUTF("my result");
    return  jstr;
  }
  CATCH_CPP_EXCEPTION_AND_THROW_JAVA_EXCEPTION
  return 0;
}

JNIEXPORT void JNICALL Java_my_group_mypackage_example_function3
  (JNIEnv *env, jobject object, jlong value)
{
  try 
  {
    /* ... my processing ... */
  }
  CATCH_CPP_EXCEPTION_AND_THROW_JAVA_EXCEPTION
}

CプリプロセッサマクロCATCH_CPP_EXCEPTION_AND_THROW_JAVA_EXCEPTIONは以下に定義されています。C++例外をJava例外に変換します。独自のコードを使用してそのコードをカスタマイズしmypackage::Exception、共通のヘッダーに配置します(これは再生成される可能性があるため、 `Java_my_group_mypackage_example.h'にはありません)。

#define CATCH_CPP_EXCEPTION_AND_THROW_JAVA_EXCEPTION              \
                                                                  \
  catch (const mypackage::Exception& e)                           \
  {                                                               \
    jclass jc = env->FindClass("my/group/mypackage/Exception");   \
    if(jc) env->ThrowNew (jc, e.what());                          \
    /* if null => NoClassDefFoundError already thrown */          \
  }                                                               \
  catch (const std::bad_alloc& e)                                 \
  {                                                               \
    /* OOM exception */                                           \
    jclass jc = env->FindClass("java/lang/OutOfMemoryError");     \
    if(jc) env->ThrowNew (jc, e.what());                          \
  }                                                               \
  catch (const std::ios_base::failure& e)                         \
  {                                                               \
    /* IO exception */                                            \
    jclass jc = env->FindClass("java/io/IOException");            \
    if(jc) env->ThrowNew (jc, e.what());                          \
  }                                                               \
  catch (const std::exception& e)                                 \
  {                                                               \
    /* unknown exception */                                       \
    jclass jc = env->FindClass("java/lang/Error");                \
    if(jc) env->ThrowNew (jc, e.what());                          \
  }                                                               \
  catch (...)                                                     \
  {                                                               \
    /* Oops I missed identifying this exception! */               \
    jclass jc = env->FindClass("java/lang/Error");                \
    if(jc) env->ThrowNew (jc, "unidentified exception");          \
  }

Java_my_group_mypackage_example.cppDLLを生成するためにコンパイルします。そのDLLを設定するPATHか、Javaランタイムディレクトリ内に移動します(通常はtarget)。

"my-DLL-name"Javaソースコードを拡張子のないDLLの名前に置き換えることを忘れないでください(例: myname.dll-> "myname")。

これは、Linux / Unix共有ライブラリを使用しても機能します(*.so);-)

于 2013-03-08T09:15:20.253 に答える