1

我试图在 JAVA 代码中调用 MessageBoxA 函数。以下方法有什么问题,以至于我的程序抛出了很多错误?

package loading.libraries;

public class User32
{
    //first case:public native int MessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType);
    //second: public native int MessageBoxA(int hWnd,String lpText,String lpCaption,int uType);
    static  
    {
        System.loadLibrary("User32");
    }        

}

package loading.libraries;

public class LoadingLibraries 
{
    public static void main(String[] args) 
    {
        User32 hwapi = new User32();

        hwapi.MessageBoxA(0,"Hello","World",0);               
    }
}

第一:

运行:线程“main”中的异常 java.lang.ClassFormatError:类文件加载/库/MessageBox 中的本机或抽象方法中的代码属性 java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass( ClassLoader.java:791) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) at java.net.URLClassLoader.defineClass(URLClassLoader.java:449) at java.net.URLClassLoader.access$100(URLClassLoader.java: 71) 在 java.net.URLClassLoader$1.run(URLClassLoader.java:361) 在 java.net.URLClassLoader$1.run(URLClassLoader.java:355) 在 java.security.AccessController.doPrivileged(Native Method) 在 java.net .URLClassLoader.findClass(URLClassLoader.java:354) 在 java.lang.ClassLoader.loadClass(ClassLoader.java:423) 在 sun.misc。Launcher$AppClassLoader.loadClass(Launcher.java:308) at java.lang.ClassLoader.loadClass(ClassLoader.java:356) at loading.libraries.LoadingLibraries.main(LoadingLibraries.java:8) Java Result: 1 BUILD SUCCESSFUL (total时间:2秒)

第二:

运行:线程“main”中的异常 java.lang.UnsatisfiedLinkError: loading.libraries.User32.MessageBoxA(ILjava/lang/String;Ljava/lang/String;I)I at loading.libraries.User32.MessageBoxA(Native Method) at loading.libraries.LoadingLibraries.main(LoadingLibraries.java:10) Java 结果:1 构建成功(总时间:0 秒)

4

3 回答 3

4

使用 JNI 调用本机代码并不像您尝试的那么简单。您正在调用的 DLL 中的函数必须符合某个接口,例如 Windows User32.dll 中的任意函数不符合 JNI 期望的格式。

您可以编写一个包装 DLL,这意味着您可以使用可以从 Java 调用的 JNI API 在 C 中编写一些代码。

另一种方法是使用JNA,它比 JNI 更易于使用,它允许您调用任意 DLL 中的函数,而无需自己编写本机代码。

于 2013-03-19T14:47:44.150 回答
3

您需要创建一个包装器来调用 User32 库中的这些函数。不要直接打电话给他们。查看本教程http://www.ibm.com/developerworks/java/tutorials/j-jni/

除了简单地加载库并调用函数之外,还涉及更多步骤。还必须注意,如果您这样做,您将删除 Java 中最好的东西之一。能够编写一次运行任何地方。您将被束缚在 Windows 上。如果这对您来说不是问题,那么没什么大不了的。你确定这不是你不能直接从 Java 做的事情。JNI 真的应该是最后的手段。

此外,根据我使用 JNI 的经验,如果不小心使用它可能会导致应用程序不稳定。

于 2013-03-19T14:42:17.883 回答
2

您正在使用 Java JNI。JNI 不能只调用任何 DLL 方法,而只能调用设计为从 JVM 调用的方法。DLL 中的 C 方法签名应与 JNI 规范中定义的 Java 方法签名相匹配。

例如这个 C 函数

include "jni.h"

JNIEXPORT jobject JNICALL Java_net_sf_sevenzipjbinding_SevenZip_nativeOpenArchive(JNIEnv * env,
     jclass thiz, jstring formatName, jobject inStream,
     jobject archiveOpenCallbackImpl) { ... }

可以使用以下本地方法声明从 Java 调用:

package net.sf.sevenzipjbinding;

class public class SevenZip {
    private static native ISevenZipInArchive nativeOpenArchive(String formatName, IInStream inStream,
        IArchiveOpenCallback archiveOpenCallback) throws SevenZipException;
    ...
}

如您所见,DLL 中导出的名称应与 java 包、类名和方法名匹配。函数签名应与使用 jni.h 中定义的类型的 java 签名相对应

示例来自https://github.com/borisbrodski/sevenzipjbinding/

于 2013-03-19T14:53:04.407 回答