Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/137.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
另一个与JNI相关的java.lang.UnsatifiedLinkError_Java_C++_Java Native Interface - Fatal编程技术网

另一个与JNI相关的java.lang.UnsatifiedLinkError

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

我已经浏览了很多类似问题的论坛帖子,但我觉得我已经看到了所有这些。简而言之,我通过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"); 
}
private native void destroy();
我知道这会加载DLL,因为如果该文件夹中没有DLL,则会出现“无法加载库”运行时错误。javah-jni命令生成的头代码是

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

包含在.CPP文件中的ASCOCOCIATIC C++代码是:

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
void __stdcall Java_com_optin_executableContainer_client_COMControl_destroy(struct JNIEnv_ *,class _jobject *)
这是新打包的未工作dll的函数名

_Java_COMControl_destroy@8
void __stdcall Java_com_optin_executableContainer_client_COMControl_destroy(struct JNIEnv_ *,class _jobject *)
Java代码
COMControl.Java
(生成COMControl头)声明此函数如下

static
{
System.load("C:\\JNITests\\JNIBridge.dll"); 
}
private native void destroy();
我试着比较产生工作文件的头文件和产生损坏文件的头文件之间的差异,除了明显的基于打包的更改(com_optin等),没有其他差异。
COMControl.java
文件中唯一的区别是包含了
包com.optin.executableContainer.client位于Java文件的顶部


这里发生了什么?

您正在将本机例程导出为一个名称损坏的
C++
函数。之所以可以这样说,是因为函数的参数列在库的导出信息中。无论何时,只要您能说出以函数名传递的参数类型,就意味着函数将作为修饰的
C++
方法导出。如果您查看库的原始导出信息而不进行Demanling,它将类似于:

?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
。如果不这样做,编译器将不知道该例程将作为
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


我不知道visual studio是否有一个与
gcc
-Wmissing声明
等价的声明,它注意到这样的不一致,这对
.dll
s很重要。

该函数需要作为普通的c函数从dll中导出,而不是作为名称损坏的
c++
函数。如果在DLL导出查看器中看到参数列表,则听起来像是将函数导出为名称受损的函数。将函数声明为“代码>外部”C“/CODE”,并在C++头中重新编译了该函数。Javah cmd生成的JNIBridge.h文件包含整个头文件的包装器外部“C”{}。extern命令有一个#ifdef uu cplusplus,但这不应该是问题,对吗?您可以在
.cpp
文件中包含
extern“C”
声明的头,如果没有,则链接类型不适用。我已经在“JNIBridge.cpp”中包含了#include“JNIBridge.h”它包含了代码,并且在statfx.h文件中使用了#include,但没有使用它。如果我可以问一下,一个
普通C
函数和一个名称损坏的
C++
函数是什么样的呢。我很好奇
extern“C”
代码是否影响了dll。我用.h文件做了一个cpp文件的空白副本,但它仍然不起作用。仅在cpp文件中的每个函数之前放置
extern“C”
,最终解决了d