gpt4 book ai didi

java - 另一个 JNI 相关的 java.lang.UnsatisfiedLinkError

转载 作者:行者123 更新时间:2023-11-28 02:49:29 25 4
gpt4 key购买 nike

我已经浏览了很多关于类似问题的论坛帖子,但我觉得我已经看到了所有内容。简而言之,我通过 Java 访问的 JNI 奇迹获得了 native 代码。在我开始使用 JAVA 包之前,代码运行良好。我关注了所有关于确保 Javah cmd 在正确文件夹中运行的论坛帖子,并成功构建了我的 DLL。我已确保包含包装器的包存在于 C++ 函数的名称中。由于项目的大小,我将简单地展示此代码的示例。注意所有代码(DLL、JVM C++ 编译器)均以 32 位运行,目标是运行 Windows 8.1 的 PC。

我所有的 Java 代码都包含在包中:

package com.optin.executableContainer.client;

所以在我的 Java 包装器类中,我按如下方式明确加载 DLL(32 位)

static
{
System.load("C:\\JNITests\\JNIBridge.dll");
}

我知道这会加载 DLL,因为该文件夹中没有 DLL,我会收到“无法加载库”运行时错误。 javah -jni 命令生成的头代码是

JNIEXPORT void JNICALL Java_com_optin_executableContainer_client_COMControl_setControlBackColor
(JNIEnv *, jobject, jlong);

.cpp 文件中包含的关联 C++ 代码是:

JNIEXPORT void JNICALL Java_com_optin_executableContainer_client_COMControl_setControlBackColor
(JNIEnv *env, jobject obj, jlong color)
{
printf("\nHello World\n");
}

当我用 Visual Studio 2010 编译它时没有错误。我已经验证了这个函数存在于目标 DLL 中,通过使用 DLL 导出查看器将函数名称视为:

void __stdcall Java_com_optin_executableContainer_client_COMControl_setControlBackColor(struct JNIEnv_ *,class _jobject *,__int64)

然而,当我在 Eclipse IDE 中运行这段代码时,我得到了可怕的结果

Exception in thread "main" java.lang.UnsatisfiedLinkError: 
com.optin.executableContainer.client.COMControl.setControlBackColor(J)V
at com.optin.executableContainer.client.COMControl.setControlBackColor(Native Method)

如果我在此过程中遗漏了什么,请指出给我。

问候贾伦

更新:我去比较了工作 dll(在打包之前完成)和新 dll,发现了一些主要差异。这是未打包的工作dll的函数名

_Java_COMControl_destroy@8

这里是新打包的未运行的 dll 的函数名

void __stdcall Java_com_optin_executableContainer_client_COMControl_destroy(struct JNIEnv_ *,class _jobject *)

Java 代码 COMControl.java(生成 COMControl header )声明此函数如下

private native void destroy();

我已经尝试比较产生工作头文件和产生损坏头文件的头文件之间的差异,除了明显的基于包装的更改(com_optin 等)之外,没有其他差异。 COMControl.java 文件的唯一区别是在 Java 文件的顶部包含了 package com.optin.executableContainer.client;

这是怎么回事?

最佳答案

您正在将 native 例程导出为名称损坏的 C++ 函数。我们可以这样说的原因是因为函数的参数列在库的导出信息中。每当您可以告诉在函数名称中传递的参数的类型时,就意味着该函数正在作为修饰的 C++ 方法导出。如果您查看库的原始导出信息而不进行 demangling,它将类似于:

?Java_Package_ComControl_destroy@@YGXPAUJNIEnv_@@PAV_jobject@@@Z

当它看起来像这样时,java 运行时找不到它,它应该看起来更像:

_Java_Package_ComControl_destroy@8

这是一个未修饰的 C 例程。 @8 是 8 个字节的 stdcall 简写,在堆栈中传递给例程

发生这种情况的最常见原因是声明函数并由 javah 生成的 .h 文件不匹配定义函数内容的 .cpp 文件 - 即有一些微妙的.h 文件和 .cpp 文件之间的区别。您应该将 .h 文件中的函数声明复制粘贴到 .cpp 文件中,确保所有参数对齐并且所有类型对齐。

此外,对于 .cpp 文件,您必须确保它 #include 是 javah 生成的 .h 文件,而不仅仅是 #include <jni.h> 。如果您不这样做,那么编译器将不知道该例程将作为 C 样式例程导出。这是生成的已编译 dll 不包含该方法的未损坏版本的常见原因。

如果您想使用未修饰的 C 调用约定手动强制导出例程,在 .cpp 文件的函数定义处,您可以输入:

extern "C"
JNIEXPORT void JNICALL
Java_com_optin_executableContainer_client_COMControl_setControlBackColor
(JNIEnv *env, jobject obj, jlong color)
{
printf("\nHello World\n");
}

通过以这种方式使用 extern "C",函数将被定义为导出为 C 例程而不是 C++ 例程;但这是不可取的,因为你真的应该包括来自 .hjavah

我不知道 visual studio 是否有等同于 -Wmissing-declarationsgcc 的等价物,它注意到像这样的不一致,这对于 .dll s 很重要。

关于java - 另一个 JNI 相关的 java.lang.UnsatisfiedLinkError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23388629/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com