2

I'm trying to use dll in my java application in eclipse, but I'm getting runtime exception whenever I try to call any method associated with that dll.

The dll exists in the following address, which I've passed in Run/Debug Settings in eclipse:

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

Code:

class Test {

  public native int nsio_init();

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

Error:

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

The command dumpbin /exports "C:\Program Files\NPortAdminSuite\ipserial\lib\x86\IPSerial.dll" also returning me the name of method, which I'm trying to call from that dll enter image description here

Could anyone please tell how to solve this problem?

Dusk
  • 2,191
  • 6
  • 38
  • 57
  • 1
    can you find any helpful information with either of hte following ? http://stackoverflow.com/a/1403808/774691 or http://stackoverflow.com/questions/8761979/unsatisfiedlinkerror-java-exception-when-the-class-with-the-native-method-is-not – john.k.doe Jul 02 '12 at 05:57

2 Answers2

4

Looks like you are trying to call a dll function directly from java code. This is not possible (directly). You need to write a layer that translates between java and the native dll.

Have a look at these resources:


Another way around the problem is to use JNA, check out the wikipedia article for example.

dacwe
  • 43,066
  • 12
  • 116
  • 140
2

EDIT:   See also this elegant answer using a function instead of the bottom preprocessor macro.


If you want to implement JNI, this is how I did:

Let's imagine the below class in file 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
  }
}

Generate example.class from example.java (using javac or your EDI or maven...). Then generate C/C++ header file Java_my_group_mypackage_example.h from example.class using javah.

The declaration of C/C++ functions are in Java_my_group_mypackage_example.h. Now we implement the definition (body) of these functions in Java_my_group_mypackage_example.cpp for instance. Prefer using C++ (instead of C) to catch exceptions from other DLLs.

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
}

The C preprocessor macro CATCH_CPP_EXCEPTION_AND_THROW_JAVA_EXCEPTION is defined below. It converts the C++ exceptions into Java exceptions. Customize that code using your your own mypackage::Exception and put it in a common header (not in `Java_my_group_mypackage_example.h' because this could be regenerated again).

#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");          \
  }

Compile Java_my_group_mypackage_example.cpp to produce a DLL. Set your PATH or move that DLL within your java run-time directory (usually target).

Do not forget to replace "my-DLL-name" in the java source code by the name of your DLL without the extension (e.g. myname.dll -> "myname").

This also works using Linux/Unix shared library (*.so) ;-)

Community
  • 1
  • 1
oHo
  • 51,447
  • 27
  • 165
  • 200