【问题标题】:JNI Hello World Unsatisfied Link ErrorJNI Hello World 不满意的链接错误
【发布时间】:2009-08-31 17:42:23
【问题描述】:

这是我第一次尝试 JNI。我的最终目标是让当前在机器上运行的所有任务,但甚至需要让一个简单的示例运行。当我尝试执行我的主程序时,我不断收到此错误。我提供了我的简单 Java 主程序、生成的头文件和错误。

我不知道这个 DLL 可能依赖于什么。它最初引用了一个我跟踪并放入 system32 (msvcr90.dll) 的 DLL。

这是我用来编译 C 代码的命令,它生成了 DLL、OBJ、LIB、EXP 和清单文件。

cl -I"C:\Program Files\Java\jdk1.6.0\include" -I"C:\Program Files\Java\jdk1.6.0\include\win32" -MD -LD HelloWorld.c -FeHelloWorld. dll

class HelloWorld {
     private native void print();
     public static void main(String[] args) {
         new HelloWorld().print();
     }
     static {
         System.load("C:\\temp\\HelloWorld.dll");
     }
 }


#include <jni.h>
 #include <stdio.h>
 #include "HelloWorld.h"

 JNIEXPORT void JNICALL 
 Java_HelloWorld_print(JNIEnv *env, jobject obj)
 {
     printf("Hello World!\n");
     return;
 }

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloWorld */

#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     HelloWorld
 * Method:    print
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_HelloWorld_print
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

java.lang.UnsatisfiedLinkError: C:\temp\HelloWorld.dll: A dynamic link library (DLL) initialization routine failed
    at java.lang.ClassLoader$NativeLibrary.load(Native Method)
    at java.lang.ClassLoader.loadLibrary0(Unknown Source)
    at java.lang.ClassLoader.loadLibrary(Unknown Source)
    at java.lang.Runtime.load0(Unknown Source)
    at java.lang.System.load(Unknown Source)
    at HelloWorld.<clinit>(HelloWorld.java:7)
Exception in thread "main" 

【问题讨论】:

标签: java java-native-interface


【解决方案1】:

不满意的链接错误可能意味着很多事情都出错了。我会用

System.loadLibrary("HelloWorld");

代替

System.load();

正如 TwentyMiles 建议的那样。

此外,在调用程序时,您需要(假设您的 DLL 与类文件位于同一目录中:

java -Djava.library.path=。你好世界

这是我做的一个简单的演示,它调用了一个 Win32 API 函数(MessageBox)

Java 类

class CallApi{
    private native String showMessageBox(String msg);
    private native double getRandomDouble();

    static{
        try{
            System.loadLibrary("CallApi");
            System.out.println("Loaded CallApi");
        }catch(UnsatisfiedLinkError e){
            //nothing to do
            System.out.println("Couldn't load CallApi");
            System.out.println(e.getMessage());
        }
    }

    public static void main(String args[]){
        CallApi api = new CallApi();
        double randomNumber = api.getRandomDouble();
        String retval = api.showMessageBox("Hello from Java!\n"+
            "The native random number: "+randomNumber);
            System.out.println("The native string: "+retval);
    }
}

生成的头文件

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class CallApi */

#ifndef _Included_CallApi
#define _Included_CallApi
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     CallApi
 * Method:    showMessageBox
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_CallApi_showMessageBox
  (JNIEnv *, jobject, jstring);

/*
 * Class:     CallApi
 * Method:    getRandomDouble
 * Signature: ()D
 */
JNIEXPORT jdouble JNICALL Java_CallApi_getRandomDouble
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

C DLL 代码

#include "CallApi.h"
#include <windows.h>
#include <stdlib.h>
#include <time.h>

#pragma comment(lib,"user32.lib")

JNIEXPORT jstring JNICALL Java_CallApi_showMessageBox
  (JNIEnv *env, jobject thisObject, jstring js)
{
    //first convert jstring to const char for use in MessageBox
    const jbyte* argvv = (*env)->GetStringUTFChars(env, js, NULL);
    char* argv =(char *) argvv;

    //Call MessageBoxA
    MessageBox(NULL, argv, "Called from Java!", MB_ICONEXCLAMATION | MB_OK);
    return js;
}

JNIEXPORT jdouble JNICALL Java_CallApi_getRandomDouble
  (JNIEnv *env, jobject thisObject)
{
    double num1;
    srand((unsigned)(time(0)));
    num1 = ((double)rand()/(double)RAND_MAX);

    return num1;
}

编译说明

我使用 Visual C++ express 2008 cl 进行编译,删除了 -ML 标志,因为当 Java 代码尝试调用本机代码时它会导致异常:

cl /I"c:\Program Files\Java\jdk1.6.0_10\include" /I"c:\Program Files\Java\jdk1.6.0_10\include\win32" -LD CallApi.c -FeCallApi. dll

然后,运行代码:

java -Djava.library.path=。调用接口

【讨论】:

  • 我使用了java -classpath . CallApi 而不是java -Djava.library.path=. CallApi。它仅适用于第一个,而不适用于您所提供的... Y?是这样吗?
【解决方案2】:

我并没有声称对这种情况的理解足以解释它,但是一些用户在使用“-MD”编译器标志时报告了错误。

有关更多信息,请参阅 Java Native Interface (JNI) - Impossible to use VS2005 with Java? 讨论了这个问题并提供了可能的解决方法,think techie blog 提供了替代方案。

【讨论】:

  • 感谢您的更新。我也会研究这些建议。我在网上找到了一个工作示例,我正在将其集成到我的应用中以满足我的特定需求,但仍想了解获取 DLL 的细节。
  • “Java 本地接口 (JNI) - 无法将 VS2005 与 Java 一起使用?”的链接坏了。
  • 感谢您报告损坏的链接。很遗憾,我无法更新参考。
  • 我相信 Bruno Simões 在回复中最初引用的页面可以在这里找到:“线程:无法将 VS2005 与 Java 一起使用?” forums.oracle.com/forums/thread.jspa?threadID=1547791HTH!
【解决方案3】:

我相信你应该使用

System.loadLibrary("HelloWorld");

而不是 System.load。 LoadLibrary 将检查您的系统路径(而不是 Java 库路径),因此请确保 HelloWorld.dll 位于可以找到的目录中。另请注意,它不需要完整路径,也不需要在末尾添加 dll 扩展名。

【讨论】:

    【解决方案4】:

    我刚刚删除了 -MD 选项并编译它就像魅力一样工作

    cl -I"C:\Program Files\Java\jdk1.6.0_21\include" -I"C:\Program Files\Java\jdk1.6.0_21\include\win32" -LD HelloWorld.c -FeHelloWorld.dll
    

    【讨论】:

      【解决方案5】:

      如果你从java端改变你的native函数声明的位置(包)而不更新h文件,以及c++端方法的签名,它不会解析到方法,会抛出不满足。 .

      package x;
      public class A {
          private native void print();
          ...
      }
      

      移至:

      package x.y;
      public class A {
          private native void print();
          ...
      }
      

      这将需要重新生成 H 文件(类似于 Java_x_y_A_print )。

      请注意,您可以手动更改这些签名,但我不推荐

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-06-23
        • 2012-04-22
        • 2013-09-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-26
        相关资源
        最近更新 更多