Java 为什么在Windows上调用MinGW编译函数(不加载库)时会出现不满意的LinkError?

Java 为什么在Windows上调用MinGW编译函数(不加载库)时会出现不满意的LinkError?,java,c,windows,dll,java-native-interface,Java,C,Windows,Dll,Java Native Interface,我正在Windows上使用Eclipse制作一个简单的JNI测试应用程序。我的C++编译器是MIW4.4.2。当我试图调用测试DLL中的函数时,Java抛出了一个unsatifiedlinkerror(DLL本身加载没有问题)。我已经验证了我的DLL导出的“C”函数与javah实用程序生成的函数同名 尝试调用函数怎么可能会产生链接错误?(还有,有没有办法获得关于找不到哪个符号的更多详细信息?一个关于存在未满足链接错误的空洞陈述几乎是无用的。) 以下是定义本机函数的Java: 下面是来自javah

我正在Windows上使用Eclipse制作一个简单的JNI测试应用程序。我的C++编译器是MIW4.4.2。当我试图调用测试DLL中的函数时,Java抛出了一个
unsatifiedlinkerror
(DLL本身加载没有问题)。我已经验证了我的DLL导出的“C”函数与
javah
实用程序生成的函数同名

尝试调用函数怎么可能会产生链接错误?(还有,有没有办法获得关于找不到哪个符号的更多详细信息?一个关于存在
未满足链接错误的空洞陈述几乎是无用的。)

以下是定义本机函数的Java: 下面是来自
javah
的相应输出: …以及我如何实现该功能…: 下面是我尝试调用它的方式。 最后,这是输出:
异常中的签名没有“int”参数。所以您的Java代码与本机代码不一致。

解决了它——哇

结果是,MSVC在
\uu stdcall
函数的名称前加了一个下划线。明格没有。Windows JVM显然需要“\u1”前缀。当我在函数名前面加上“u”并用MinGW重建时,一切都很顺利

例如:

编辑
MinGW附带的
dlltool
实用程序的
--addstdcall下划线
功能可以透明地解决此问题。在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();
    }
}


我已经消除了一些低挂水果。它不是包名称中的下划线(请注意,
javah
希望在其前面粘贴一个“1”)。此外,我还创建了一个非静态成员函数,该函数使用零参数,并且在尝试调用
newjsdi().mf()时出现了相同的错误.Hmmm。我不知道你从哪里得到的。“I”表示
int
参数。此外,“C”调用本身没有“签名”,从这个意义上说,库只导出符号名,调用方知道如何调用它。因此,最可能的解释是JVM找不到符号,而不是JVM找不到特定的签名。谢谢,在我的例子中,它帮助添加了
-Wl,--add stdcall alias
...
#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
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)
JNIEXPORT void JNICALL Java_com_xyz_jsdi_1test_JSDI_func ==> _Java_com_xyz_jsdi_1test_JSDI_func
/* 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