Windows JNI加载和执行c++;dll错误java.lang.UnsatifiedLinkError中的代码:

Windows JNI加载和执行c++;dll错误java.lang.UnsatifiedLinkError中的代码:,java,c++,java-native-interface,Java,C++,Java Native Interface,答案/解决方案:Jorn Vernee的答案是正确的,当我最初创建.h文件时,我在.java类中没有包信息,但当我的代码被执行时,它确实有包信息。.h文件中的方法名称最终将包括名称中的包信息 我有一些C++代码,我用它来截屏。我一直在尝试使用JNA和JNI从Java调用它,但两者都没有成功。我的最终目标是让captureScreen方法工作。我创建了一个getNumber方法,就像一个简单的测试一样,没有传入任何参数,但即使它也不起作用 更新我的应用程序以64位应用程序运行,我的dll为64位。

答案/解决方案:Jorn Vernee的答案是正确的,当我最初创建.h文件时,我在.java类中没有包信息,但当我的代码被执行时,它确实有包信息。.h文件中的方法名称最终将包括名称中的包信息

我有一些C++代码,我用它来截屏。我一直在尝试使用JNA和JNI从Java调用它,但两者都没有成功。我的最终目标是让captureScreen方法工作。我创建了一个getNumber方法,就像一个简单的测试一样,没有传入任何参数,但即使它也不起作用

更新我的应用程序以64位应用程序运行,我的dll为64位。不确定这是否会影响传入或传出的参数

我当前的实现

爪哇

我使用javac-h从上面的类创建头文件

.h文件

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

    #include "DXGICapture.h"

    #include <stdio.h>
    #include <tchar.h>
    #include <shlobj.h>
    #include <atlconv.h>
    #include <string>

    using namespace std;

    #ifndef _Included_JNIScreenShot
    #define _Included_JNIScreenShot
    #ifdef __cplusplus
    extern "C" {
    #endif
        /*
         * Class:     JNIScreenShot
         * Method:    captureScreen
         * Signature: (Ljava/lang/String;IIII)V
         */
        JNIEXPORT void JNICALL Java_JNIScreenShot_captureScreen
        (JNIEnv*, jobject, jstring, jint, jint, jint, jint);

        /*
     * Class:     JNIScreenShotTest
     * Method:    getNumber
     * Signature: ()I
     */
        JNIEXPORT jint JNICALL Java_JNIScreenShotTest_getNumber
        (JNIEnv*, jobject);

    #ifdef __cplusplus
    }
    #endif
    #endif
这会产生一个错误 java.lang.UnsatifiedLinkError:com.tdkc.udop.screencapture.jniScreenShot.captureScreen(Ljava/lang/string;IIII)V

起初,我认为我的captureScreen中有些东西失败了,或者可能是我传递的数据类型不同。所以我创建了getNumber方法作为测试

调用getNumber()时,我会遇到类似的错误 java.lang.UnsatisfiedLinkError:com.tdkc.udop.screencapture.jniScreenShot.getNumber()I

这两条错误消息都引用了.h文件中的签名,因此我知道它正在查找dll并试图调用正确的方法

花了一些时间查看未满足的LinkError,但大多数Google结果显示,当库加载时,我已经看到了很多,包括尝试使用System.loadLibrary()而不是System.load()时

它似乎可以找到方法,因为错误包含在my.h文件中为每个方法定义的签名


在这一点上,我已经尝试了以下关于JNI的指南和教程,已经2天了,我失去了任何帮助,非常感谢。

从您的错误消息判断:

java.lang.UnsatisfiedLinkError: com.tdkc.udop.screencapture.jniScreenShot.getNumber()I
看来你们班的学生都很团结。但是,本机函数的名称与此不匹配:

Java_JNIScreenShotTest_getNumber
包名称也应该用本机函数的名称编码。从该错误消息来看,本机函数的名称应该是:

Java_com_tdkc_udop_screencapture_jniScreenShot_getNumber

使用
-Xlog:library*=trace
()可以看到VM用于查找的确切名称。例如:

[0.211s][info][library] Loaded library C:\Program Files\Java\jdk-15\bin\nio.dll, handle 0x00007ffacf0f0000
...
[0.212s][info][library] Found Java_sun_nio_fs_WindowsNativeDispatcher_initIDs in library with handle 0x00007ffacf0f0000

如果使用
-Xlog:library*=trace运行程序(需要JDK 15+),它会打印什么?您的库是否已成功加载?本机函数的符号查找是否搜索了正确的库?我不确定我是否理解您的要求。我的应用程序正在从Eclipse运行。这一行的快速谷歌没有告诉我它做什么,或者它在哪里保存文件,你能详细说明一下吗?这是VM参数吗?是的,这是VM参数。输出应在控制台中打印。这是一个选项,可以启用有关本机库加载和符号查找的额外日志记录。您可以在控制台中运行
java-Xlog:help
(cmd/powershell/sh/bash,具体取决于您使用的平台/shell),或者查看在线文档:要获得关于VM参数的更多信息,我无法启动应用程序,我会得到一个java虚拟机启动器,然后出现一个Eclipse错误对话框,上面说Cannotconnect to VM。也就是说,它正在加载dll,因为它尝试调用时的错误消息与my.h文件中方法的签名匹配。输出应该告诉您是否正在加载正确的库(它打印路径),以及符号查找是否正在使用正确的名称查找正确的库。FWIW,对于查找来说,唯一重要的是函数名(DLL中没有类型信息,至少不典型)。您可以使用类似于
dumpbin
(随Visual Studio提供)的内容,或者验证正在加载的DLL是否确实包含符号。要添加此内容,请始终重新创建标头并将实现更改为匹配,如果更改JNI包/类/方法名,这就是问题所在,因为.h文件是从没有包的java文件构建的。一旦我添加了包信息并让它重新生成.h文件,它就会更改我的方法名。虽然这解决了我的问题,但它留给我的另一个问题是,我假设如果java文件被移动,它将中断,并且无法找到正确的方法。有没有办法让.h文件方法名不包含包信息,这样,如果java文件移动了,它就不会影响它?@Jeremy不是真的,没有。您可能想看看API,它允许您手动链接本机函数,但需要先调用本机代码,第一次调用也会有相同的包命名问题。在我看来,这太麻烦了。至少在即将推出的ProjectPanama外部函数接口中,无需精确的名称映射,就可以更轻松地链接任意本机函数。
Java_JNIScreenShotTest_getNumber
Java_com_tdkc_udop_screencapture_jniScreenShot_getNumber
[0.211s][info][library] Loaded library C:\Program Files\Java\jdk-15\bin\nio.dll, handle 0x00007ffacf0f0000
...
[0.212s][info][library] Found Java_sun_nio_fs_WindowsNativeDispatcher_initIDs in library with handle 0x00007ffacf0f0000