从Java调用C++ dll

11

我正在使用Java编写一个小应用程序。这是对现有MFC项目的重写。有一个现有的dll,我需要改变它以便可以使用JNI从Java中访问。所有这些Java东西都是新的,所以当我阅读其他论坛帖子时,我感到有些困惑和迟钝。在现有的dll中,我有一个类似这样的函数:

extern "C" __declspec(dllexport) bool Create()
{
     return TRUE;
}

相当于小学生问题:如何正确地设置它以便被 Java 调用?

我尝试了这样做:

JNIEXPORT jboolean JNICALL Create()
{
     return TRUE;
}

我已经包含了jni.h文件并且编译也没有问题。但是,当我从Java中调用它时,会收到UnsatisfiedLinkError的错误。我在Java中使用以下代码调用:

public static native boolean CreateSession();

System.load("D:\\JavaCallTest.dll");
Create();

能否有人把我引向正确的方向?非常感谢任何帮助。

谢谢,

Nick


1
你看过Sun的例子吗?http://java.sun.com/developer/onlineTraining/Programming/JDCBook/jniexamp.html - Etienne
1
你可以选择使用JNA而不是JNI,因为你有一个可以被JNA加载的C dll。 - ecle
请发布抛出的异常... - quaylar
使用javah生成C头文件,就像Jörn Horstmann在下面提到的那样--或者完全避免JNI。一个简单的替代方案是JNA。 - Andy Thomas
谢谢你的帮助。我曾考虑使用JNA,但我想尽量减少额外的东西,所以我觉得最好使用JNI。 - nickfinity
3个回答

7

您需要在本地代码中包含Java类名和路径。例如,如果您的本地方法在Java中声明为:

public class NativeCode {
    public static native boolean CreateSession();
}

如果类路径为(例如)com.example.NativeCode,则您需要在本地声明以下方法:

extern "C"
JNIEXPORT jboolean JNICALL Java_com_example_NativeCode_CreateSession(JniEnv* env, jclass clazz)
{
    return JNI_TRUE;
}

所有JNI方法的前两个参数都是JNIEnv指针和类。


就是这样。现在似乎可以工作了。等我不再处理像这样简单的函数时,我们会看到遇到什么问题。感谢您的帮助。 - nickfinity
@GooseSerbus,关于使用public static native boolean CreateSession(?,?)的参数怎么样? - Aniket
@Aniket 在 C 方法的参数上添加了参数,例如:public static native boolean CreateSession(boolean, Object); 将变为 JNIEXPORT jboolean JNICALL Java_com_example_NativeCode_CreateSession(JniEnv* env, jclass clazz, jboolean b, jobject o) - GooseSerbus

2

一个静态的本地方法仍然需要至少两个参数:

JNIEnv *env
jclass clazz

函数名也必须对应于Java包结构。
JNIEXPORT jboolean JNICALL Java_com_example_CreateSession(JNIEnv *env, jclass clazz)

理想情况下,您可以使用 javah 工具从声明本地方法的java类创建头文件,然后实现声明的函数原型。

+1 表示需要提到应该使用 javah 生成函数签名。 - Andy Thomas
找到了这个(https://dev59.com/vXA75IYBdhLWcg3wJFcL#3452258),并设置Eclipse来运行javah。现在工作得很好。现在我必须实现其余的东西。希望会很简单。 - nickfinity

1

我曾经遇到过类似的问题 - 我需要从Java中访问现有的C代码库。对我来说,熟悉SWIG这个工具是值得的,它可以生成一个中间的C++ DLL(调用C代码),以及调用C++ DLL的Java代码。

如果您需要包装DLL的不止一个函数,那么使用这个工具可能会更加划算,否则您就需要熟悉JNI...

编辑:

看起来您的DLL没有被System.load()调用找到。您可以尝试使用System.loadLibrary(),但请注意,您的DLL必须位于Java系统属性java.library.path所指定的路径中。 此外,在这种情况下不要传递完整的文件名,而只需传递没有扩展名的文件名即可。


它找到了DLL,但是我的函数没有正确声明。我需要研究一下SWIG。谢谢你的提示。 - nickfinity

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接