2

我正在尝试编写一个简单的 Java 程序,该程序通过 JNI 调用 C 函数来打印“Hello World”。一切都编译没有错误,但是当我运行程序时,我得到一个“UnsatisfiedLinkError:找不到依赖库”。

根据 Dependency Walker 和 dumpbin,唯一的依赖项是“kernel32.dll”,位于 C:\Windows\System32 及其依赖项中,也在 System32 中。

打电话

    System.loadLibrary("Kernel32");

返回没有错误,但加载包含打印功能的 Hello.dll 仍然会引发错误。

有谁知道这可能是什么原因造成的?

编辑:

Dependency Walker 确实给出了两个警告/错误:

-错误:由于隐式依赖模块中缺少导出函数,至少一个模块具有未解析的导入。

-错误:发现具有不同 CPU 类型的模块。

编辑:

以下是更多细节:我正在运行 Windows 7 64 位,并使用 cl (Visual Studio 2010) 编译我的 .dll。

我的 Java 代码 Hello.java:

    public class Hello
    {
        public static native void hello();

        public static void main(String[] args)
        {
            hello();
        }

        static
        {
            // Extra dependencies load with no error
            System.loadLibrary("NTDLL");
            System.loadLibrary("KERNELBASE");
            System.loadLibrary("KERNEL32");
            System.loadLibrary("Hello"); // Throws UnsatisfiedLinkError
        }
    }

我可以毫无错误地编译 java 文件,并使用 javah -jni 生成 C 头文件 Hello.h:

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

    #ifndef _Included_Hello
    #define _Included_Hello
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
     * Class:     Hello
     * Method:    hello
     * Signature: ()V
     */
    JNIEXPORT void JNICALL Java_Hello_hello
      (JNIEnv *, jclass);

    #ifdef __cplusplus
    }
    #endif
    #endif

我在 Hello.c 中实现了标头:

    #include <stdio.h>
    #include <jni.h>
    #include "Hello.h"
    #pragma comment(linker, "/EXPORT:Java_Hello_hello=_Java_Hello_hello@8")

    JNIEXPORT void JNICALL
    Java_Hello_hello(JNIEnv* env, jclass class)
    {
        printf("Hello World\n");
        return;
    }

C 代码用 cl(虽然我也尝试过 tcc)编译成 Hello.dll,它与 java .class 存储在同一目录中

4

3 回答 3

2

看起来我的问题是 64 位系统和 java 安装以及 32 位 C 编译器的组合。

默认情况下,Visual C++cl编译器会生成 32 位应用程序,这会导致在被 64 位 java.lang.java 加载时出错。我使用 Windows SDK 7.1 64 位编译器编译了我的应用程序,它运行没有错误,并且删除了 Dependency Walker 中的警告。

于 2012-08-26T18:49:30.270 回答
1

我试图让 JNI 为学校的最后一个项目工作,并在一个月的头疼后最终寻找替代方案。请改用Java Native Access。它允许您从 Windows (.dll) 和 Linux (.so) 上的任何共享库中调用任何 C 函数,它甚至还为一些 Win32 函数提供了方便的方法。将您的本机代码编译到共享库中,然后使用 JNA 动态链接到该库并调用您的函数。它说它比 JNI 慢得多,这是有道理的,因为一切都是动态加载的,但我没有注意到性能下降。

为了弄清楚 C 编译器如何修改你的函数名——strlen变成_strlen@4什么——我推荐DLL Export Viewer(下载链接在底部附近)。我不知道Linux是否有类似的工具。

于 2012-08-26T05:47:46.427 回答
0

您将需要

  • 将您的 DLL 放入 windows\system32\ 文件夹
  • 在命令行中指定 java.library.path
于 2012-08-26T18:05:02.417 回答