2013-03-19 51 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/