为什么在Windows上调用MinGW编译函数(不加载库)时会得到UnsatisfiedLinkError?

我正在Windows上使用Eclipse做一个简单的JNItesting应用程序。 我的C ++编译器是MinGW 4.6.2。 当我尝试在我的testingDLL中调用一个函数时,Java抛出UnsatisfiedLinkError (DLL自身加载没有问题)。 我已经validation我的DLL导出一个“C”函数与javah实用程序生成的函数具有相同的名称。

如何试图调用该函数可能会产生链接错误? (另外,还有什么办法可以得到更多的细节,找不到什么符号吗?一个秃头的声明,有一个UnsatisfiedLinkError是无用的。)

这里是定义本地函数的Java:

 package com.xyz.jsdi_test; import java.io.File; public class JSDI { public static native void func( String str, int i, Integer ii, long j /* 64 bits */, Long jj, byte[] b ); public static void dummy() { System.out.println("JSDI.dummy()"); } static { File f = new File("..\\jsdi\\bin\\jsdi.dll"); System.out.println("Preparing to load: " + f); System.load(f.getAbsolutePath()); System.out.println("Successfully loaded: " + f); } 

这里是来自javah的相应输出:

 ... #ifdef __cplusplus extern "C" { #endif /* * Class: com_xyz_jsdi_test_JSDI * Method: func * Signature: (Ljava/lang/String;ILjava/lang/Integer;JLjava/lang/Long;[B)V */ JNIEXPORT void JNICALL Java_com_xyz_jsdi_1test_JSDI_func (JNIEnv *, jclass, jstring, jint, jobject, jlong, jobject, jbyteArray); #ifdef __cplusplus } #endif 

…以及我如何实现该function…:

 extern "C" { JNIEXPORT void JNICALL Java_com_xyz_jsdi_1test_JSDI_func( JNIEnv * env, jclass _class, jstring str, jint i, jobject ii, jlong j, jobject jj, jbyteArray b ) { // don't do anything...let's just try to get called successfully... } } // extern "C" 

这是我如何尝试调用它。

 ... public static void main(String[] args) { JSDI.dummy(); // cause class to load, which should cause System.load() to run. JSDI.func("hello", 0, 0, 0L, 0L, (byte[])null); } 

最后,这是输出:

 Preparing to load: ..\jsdi\bin\jsdi.dll Successfully loaded: ..\jsdi\bin\jsdi.dll JSDI.dummy() java.lang.UnsatisfiedLinkError: com.xyz.jsdi_test.JSDI.func(Ljava/lang/String;ILjava/lang/Integer;JLjava/lang/Long;[B)V at com.xyz.jsdi_test.JSDI.func(Native Method) at com.xyz.jsdi_test.SimpleTest.main(SimpleTest.java:24) 

解决它 – WOOO!

事实证明,MSVC预先为__stdcall函数的名称加下划线。 MinGW没有。 Windows JVM显然需要“_”前缀。 只要我在函数名前添加了“_”,并用MinGW重新编译,一切工作都变得简单了。

例如

 JNIEXPORT void JNICALL Java_com_xyz_jsdi_1test_JSDI_func ==> _Java_com_xyz_jsdi_1test_JSDI_func 

编辑 :MinGW中包含的dlltool实用工具的--add-stdcall-underscore dlltool --add-stdcall-underscore功能可以透明地为您解决这个问题。 在你的Makefile中设置它,你不用担心不同版本的实际源代码适用于不同的编译器。 请参阅此链接 。

发布一个工作示例,将同一目录下的三个文件中的内容复制(修改JDK的路径),然后调用build.cmd

 /* File: HelloWorld.java */ public class HelloWorld { private static native void writeHelloWorldToStdout(); public static void main(String[] args) { System.loadLibrary("HelloWorld"); writeHelloWorldToStdout(); } } 

 /* File: HelloWorld.c */ #include <stdio.h> #include "HelloWorld.h" JNIEXPORT void JNICALL Java_HelloWorld_writeHelloWorldToStdout(JNIEnv *env, jclass c) { printf("Hello World!"); } 

 rem File: build.cmd %echo off echo delete generated binaries del HelloWorld.class del HelloWorld.dll del HelloWorld.h del HelloWorld.def echo Compile the Java Class javac HelloWorld.java echo Generate the Header file javah -classpath . -o HelloWorld.h HelloWorld echo Build the DLL gcc -I"C:\Program Files (x86)\Java\jdk1.7.0_25\include" -I"C:\Program Files (x86)\Java\jdk1.7.0_25\include\win32" -Wl,--add-stdcall-alias -Wl,--output-def,HelloWorld.def -shared -o HelloWorld.dll HelloWorld.c echo run the program java HelloWorld 

异常中的签名不具有“int”参数。 所以你的Java代码不同意你的本地代码。