Windows JNI Loading and executing c++ code in dll error java.lang.UnsatisfiedLinkError:
Windows JNI Loading and executing c++ code in dll error java.lang.UnsatisfiedLinkError:
Answer/Solution:明确地说,Jorn Vernee 的回答是正确的,因为当我最初创建我的 .h 文件时,我没有 .java class 中的包信息,但是当我的代码被执行了,它确实有包信息。 .h 文件中的方法名称最终会在名称中包含包信息。
我有一些用于截屏的 C++ 代码。我一直在尝试使用 JNA 和 JNI 从 Java 调用它,但都没有成功。我的最终目标是让 captureScreen 方法正常工作。我创建了一个 getNumber 方法作为一个简单的测试,没有传入任何参数,但即使它也不起作用。
更新 我的应用程序是 运行 作为 64 位应用程序,我的 dll 是 64 位的。不确定这是否会影响传入或传出的参数。
我当前的实现
Java
public class JNIScreenShotTest {
static {
String oldLibraryPath = System.getProperty("java.library.path");
try{
//This doesnt work for me it fails on the loadLibrary call and I get an UnsatisfiedLinkError
//System.setProperty("java.library.path", "C:\workspace\com.tdkc.udop\dlls");
//System.loadLibrary("JNIScreenShot");
//This Manages to load the library without error
System.load("C:\workspace\com.tdkc.udop\dlls\JNIScreenShot.dll")
}finally}
System.setProperty("java.library.path", oldLibraryPath );
}
}
private native void captureScreen(String filePath, int x, int y, int width, int height);
private native int getNumber();
}
我使用 javac -h 从上面 class
创建了我的头文件
.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
C++ 文件
// ScreenCapture.cpp : Defines the exported functions for the DLL.
//
#include "JNIScreenShot.h"
#include <iostream>
JNIEXPORT void JNICALL Java_JNIScreenShot_captureScreen
(JNIEnv *env, jobject clz, jstring filePath, jint x, jint y, jint width, jint height) {
HRESULT hr = S_OK;
CDXGICapture dxgiCapture;
jboolean isCopy;
const char* pszOutputFileName = (env)->GetStringUTFChars(filePath, &isCopy);
hr = dxgiCapture.Initialize();
tagScreenCaptureFilterConfig config;
// set default config
RtlZeroMemory(&config, sizeof(config));
config.ShowCursor = 1;
config.SizeMode = tagFrameSizeMode_AutoSize;
hr = dxgiCapture.SetConfig(config);
hr = dxgiCapture.CaptureToFile((LPCTSTR)CA2WEX<>(pszOutputFileName), x, y, width, height);
if (FAILED(hr))
{
printf("Error[0x%08X]: CDXGICapture::CaptureToFile failed.\n", hr);
}
}
/*
* Class: JNIScreenShotTest
* Method: getNumber
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_JNIScreenShotTest_getNumber
(JNIEnv *env, jobject clz) {
return 2;
}
我来自java的电话如下
File f = new File("Some file");
int x = some value;
int y = some value;
int width = some value;
int height = some value;
JNIScreenShot jniScreenShot = new JNIScreenShot();
jniScreenShot.(f.getAbsolutePath(), x,y,width,height)
这会产生一个错误
java.lang.UnsatisfiedLinkError: com.tdkc.udop.screencapture.jniScreenShot.captureScreen(Ljava/lang/string;IIII)V
起初我以为 captureScreen 中的某些东西失败了,或者可能是我传入的数据类型不同。所以我创建了 getNumber 方法作为测试
我在调用 getNumber() 时遇到了类似的错误
java.lang.UnsatisfiedLinkError: com.tdkc.udop.screencapture.jniScreenShot.getNumber()我
这两条错误消息都引用了 .h 文件中的签名,所以我知道它找到了 dll 并试图调用正确的方法。
花了一些时间查看 UnsatisfiedLinkError 但大多数谷歌搜索结果显示,当库正在加载时,我已经看到很多包括在尝试使用 System.loadLibrary() 而不是 System.load( )
它似乎可以找到方法,因为错误包含在我的 .h 文件中为每个方法定义的签名。
在这一点上,我已经尝试遵循关于 JNI 的一百万个指南和教程,并且它已经 2 天了,我失去了任何帮助,非常感谢。
根据您的错误信息判断:
java.lang.UnsatisfiedLinkError: com.tdkc.udop.screencapture.jniScreenShot.getNumber()I
您的 class 似乎在包裹中。但是,您的本机函数的名称与此不匹配:
Java_JNIScreenShotTest_getNumber
包名也应该编码在原生函数的名称中。从该错误消息来看,您的本机函数的名称应该是:
Java_com_tdkc_udop_screencapture_jniScreenShot_getNumber
使用 -Xlog:library*=trace
(since JDK 15) 您可以看到 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
Answer/Solution:明确地说,Jorn Vernee 的回答是正确的,因为当我最初创建我的 .h 文件时,我没有 .java class 中的包信息,但是当我的代码被执行了,它确实有包信息。 .h 文件中的方法名称最终会在名称中包含包信息。
我有一些用于截屏的 C++ 代码。我一直在尝试使用 JNA 和 JNI 从 Java 调用它,但都没有成功。我的最终目标是让 captureScreen 方法正常工作。我创建了一个 getNumber 方法作为一个简单的测试,没有传入任何参数,但即使它也不起作用。
更新 我的应用程序是 运行 作为 64 位应用程序,我的 dll 是 64 位的。不确定这是否会影响传入或传出的参数。
我当前的实现
Java
public class JNIScreenShotTest {
static {
String oldLibraryPath = System.getProperty("java.library.path");
try{
//This doesnt work for me it fails on the loadLibrary call and I get an UnsatisfiedLinkError
//System.setProperty("java.library.path", "C:\workspace\com.tdkc.udop\dlls");
//System.loadLibrary("JNIScreenShot");
//This Manages to load the library without error
System.load("C:\workspace\com.tdkc.udop\dlls\JNIScreenShot.dll")
}finally}
System.setProperty("java.library.path", oldLibraryPath );
}
}
private native void captureScreen(String filePath, int x, int y, int width, int height);
private native int getNumber();
}
我使用 javac -h 从上面 class
创建了我的头文件.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
C++ 文件
// ScreenCapture.cpp : Defines the exported functions for the DLL.
//
#include "JNIScreenShot.h"
#include <iostream>
JNIEXPORT void JNICALL Java_JNIScreenShot_captureScreen
(JNIEnv *env, jobject clz, jstring filePath, jint x, jint y, jint width, jint height) {
HRESULT hr = S_OK;
CDXGICapture dxgiCapture;
jboolean isCopy;
const char* pszOutputFileName = (env)->GetStringUTFChars(filePath, &isCopy);
hr = dxgiCapture.Initialize();
tagScreenCaptureFilterConfig config;
// set default config
RtlZeroMemory(&config, sizeof(config));
config.ShowCursor = 1;
config.SizeMode = tagFrameSizeMode_AutoSize;
hr = dxgiCapture.SetConfig(config);
hr = dxgiCapture.CaptureToFile((LPCTSTR)CA2WEX<>(pszOutputFileName), x, y, width, height);
if (FAILED(hr))
{
printf("Error[0x%08X]: CDXGICapture::CaptureToFile failed.\n", hr);
}
}
/*
* Class: JNIScreenShotTest
* Method: getNumber
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_JNIScreenShotTest_getNumber
(JNIEnv *env, jobject clz) {
return 2;
}
我来自java的电话如下
File f = new File("Some file");
int x = some value;
int y = some value;
int width = some value;
int height = some value;
JNIScreenShot jniScreenShot = new JNIScreenShot();
jniScreenShot.(f.getAbsolutePath(), x,y,width,height)
这会产生一个错误 java.lang.UnsatisfiedLinkError: com.tdkc.udop.screencapture.jniScreenShot.captureScreen(Ljava/lang/string;IIII)V
起初我以为 captureScreen 中的某些东西失败了,或者可能是我传入的数据类型不同。所以我创建了 getNumber 方法作为测试
我在调用 getNumber() 时遇到了类似的错误 java.lang.UnsatisfiedLinkError: com.tdkc.udop.screencapture.jniScreenShot.getNumber()我
这两条错误消息都引用了 .h 文件中的签名,所以我知道它找到了 dll 并试图调用正确的方法。
花了一些时间查看 UnsatisfiedLinkError 但大多数谷歌搜索结果显示,当库正在加载时,我已经看到很多包括在尝试使用 System.loadLibrary() 而不是 System.load( )
它似乎可以找到方法,因为错误包含在我的 .h 文件中为每个方法定义的签名。
在这一点上,我已经尝试遵循关于 JNI 的一百万个指南和教程,并且它已经 2 天了,我失去了任何帮助,非常感谢。
根据您的错误信息判断:
java.lang.UnsatisfiedLinkError: com.tdkc.udop.screencapture.jniScreenShot.getNumber()I
您的 class 似乎在包裹中。但是,您的本机函数的名称与此不匹配:
Java_JNIScreenShotTest_getNumber
包名也应该编码在原生函数的名称中。从该错误消息来看,您的本机函数的名称应该是:
Java_com_tdkc_udop_screencapture_jniScreenShot_getNumber
使用 -Xlog:library*=trace
(since JDK 15) 您可以看到 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