我正在使用 JDK 1.7_25(64 位)在 64 位 Windows 8 上运行 Netbeans,遵循使用 NetBeans 开始 JNI 的说明(https://netbeans.org/kb/docs/cnd/beginning-jni- linux.html )
这些说明适用于 linux,但我相信 Windows 的原理是相同的(生成 .dll 文件而不是 .so,使用 JDK 中包含的 win32 等)
我安装了 Cygwin64 和 Cygwin32。使用 Cygwin64,我能够从我的 C/C++ 动态库项目中生成一个 64 位 DLL。但是,当我调用 System.load("path/to/JNITest.dll") 时,我得到:
Exception in thread "main" java.lang.UnsatisfiedLinkError: C:\Users\Andrew\Documents\NetBeansProjects\JNITestLib\dist\JNITest.dll: %1 is not a valid Win32 application
at java.lang.ClassLoader$NativeLibrary.load(Native Method)
at java.lang.ClassLoader.loadLibrary1(ClassLoader.java:1957)
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1882)
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1843)
at java.lang.Runtime.load0(Runtime.java:795)
at java.lang.System.load(System.java:1061)
at jnitest.JNITest.main(JNITest.java:8)
Java Result: 1
据我所知,在 32 位虚拟机上加载 64 位应用程序时最常出现这种情况,但我的 netbeans.conf 指向的是 64 位 JVM。
此外,当我使用 32 位版本的 Cygwin 编译并运行时,我得到
Can't load IA 32-bit .dll on a AMD 64-bit platform
我很确定我正确地生成了 DLL 文件,它只是一个简单的 HelloWorld printf 来遵循 JNI 教程。我对 JNI 和 C 很陌生,所以我不确定从哪里开始调试。我做过的最好的尝试是尝试 32 位和 64 位 DLL,并且我确保我的 C 编译器(Cygwin)是 64 位的,我的 JVM 也是。
我会很感激任何见解!
编辑:这是包含的文件
=== Java (JNITest.java) ===
package jnitest;
public class JNITest {
public static void main(String[] args) {
System.out.println("JVM: " + System.getProperty("sun.arch.data.model"));
System.load("C:\\Users\\Andrew\\Documents\\NetBeansProjects\\JNITestLib\\dist\\JNITest.dll");
new JNITest().doHello();
}
public native void doHello();
}
=== 生成的 javah 头文件 (jnitest_JNITest.h) ===
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class jnitest_JNITest */
#ifndef _Included_jnitest_JNITest
#define _Included_jnitest_JNITest
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: jnitest_JNITest
* Method: doHello
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_jnitest_JNITest_doHello
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
=== C (JNITest.c) ===
#include <jni.h>
#include "jnitest_JNITest.h"
JNIEXPORT void JNICALL Java_jnidemojava_Main_nativePrint
(JNIEnv *env, jobject obj)
{
printf("\nHello World from C\n");
}
编辑:
问题似乎出在 DLL 上,因为我可以很好地加载其他 64 位 DLL。我认为 Cygwin 可能是问题所在,所以我将编译器更改为 MinGW-w64。它编译得很好,并且库加载了,但现在我得到了一个新的异常:
Exception in thread "main" java.lang.UnsatisfiedLinkError: jnitest.JNITest.doHello()V
at jnitest.JNITest.doHello(Native Method)
at jnitest.JNITest.main(JNITest.java:10)
Java Result: 1
再挖点发现,这里ClassLoader读取libs.size()的时候报错:
// Invoked in the VM class linking code.
static long findNative(ClassLoader loader, String name) {
Vector<NativeLibrary> libs =
loader != null ? loader.nativeLibraries : systemNativeLibraries;
synchronized (libs) {
int size = libs.size();
for (int i = 0; i < size; i++) {
NativeLibrary lib = libs.elementAt(i);
long entry = lib.find(name);
if (entry != 0)
return entry;
}
}
return 0;
}
编辑:答案!
终于想通了。
首先,Cygwin64 出了点问题。使用不同的 64 位 C 编译器消除了 not a valid win32 application 错误。
其次,我的 JNITest.c 文件的方法签名不正确。它应该是:
Java_jnitest_JNITest_doHello
代替
Java_jnitest_Main_doHello
改了之后就可以了!
(虽然我不能在另外 6 个小时内回答我自己的问题......所以 dum de dum)