2013-03-19 42 views
1

我试图在JAVA代码中调用MessageBoxA函数。以下方法出了什么问题,以致于我的程序会引发很多错误?在java应用程序中使用winapi

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);    
    } 
} 

1日:

run: Exception in thread "main" java.lang.ClassFormatError: Code attribute in native or abstract methods in class file loading/libraries/MessageBox at 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) at java.net.URLClassLoader$1.run(URLClassLoader.java:361) at java.net.URLClassLoader$1.run(URLClassLoader.java:355) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:354) at java.lang.ClassLoader.loadClass(ClassLoader.java:423) at 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 time: 2 seconds)

2挡:

run: Exception in thread "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 Result: 1 BUILD SUCCESSFUL (total time: 0 seconds)

+1

为什么你在USER32类方法只能说“静态”没有名字,返回类型或接入标识? – DrinkJavaCodeJava 2013-03-19 14:32:34

+1

@DrinkJavaCodeJava静态块是一个“静态初始化器”。它在加载类时自动调用 – user489041 2013-03-19 14:49:21

回答

3

您需要创建一个包装,将调用这些函数在USER32库。不要直接打电话给他们。看看这个教程http://www.ibm.com/developerworks/java/tutorials/j-jni/

还有更多的步骤,然后简单地加载库并调用函数。还必须注意的是,如果你这样做,你可以删除Java中最好的东西之一。能够在任何地方一次写入。你将被束缚到Windows。如果这不是你的问题,那么没有什么大不了的。你确定这不是你直接从Java无法做到的吗? JNI应该是最后的选择。

另外,根据我对JNI的经验,如果不谨慎使用,会导致应用程序不稳定。

4

使用JNI调用本机代码并不像您尝试的那样简单。您调用的DLL中的函数必须符合特定的接口,并且例如Windows User32.dll中的任意函数不符合JNI预期的格式。

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

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

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/