有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

C++,但又是一个JNI相关的java。lang.unsatifiedlinkerror

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

我的所有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);

包含在A中的ASCOCOCIATIC C++代码。cpp文件是:

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

当我用VisualStudio2010编译这篇文章时,没有错误。我已使用DLL导出查看器验证了目标DLL中是否存在此函数,该查看器将函数名视为:

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

然而,当我在EclipseIDE中运行这段代码时,我会感到恐惧

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头)声明此函数如下

private native void destroy();

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

这是怎么回事


共 (1) 个答案

  1. # 1 楼答案

    您正在将本机例程导出为名称损坏的C++函数。我们之所以能看出这一点,是因为函数的参数列在库的导出信息中。无论何时,只要你能说出以函数名传递的参数的类型,就意味着函数是作为修饰的C++方法导出的。如果您查看库中的原始导出信息时没有发出请求,它看起来会像:

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

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

    _Java_Package_ComControl_destroy@8
    

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

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

    此外,对于.cpp文件,必须确保它是由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++例程;但是这是不受欢迎的,因为您应该包括来自javah.h

    我不知道VisualStudio是否有一个与-Wmissing-declarationsof gcc相当的程序,它会注意到这样的不一致性,这对.dll很重要