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

1位:

run:スレッド "main"の例外java.lang.ClassFormatError:java.lang.ClassLoader.defineClass1(ネイティブメソッド)のクラスファイルloading / libraries /MessageBoxのネイティブメソッドまたは抽象メソッドのコード属性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)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)atsun.misc。Launcher $ AppClassLoader.loadClass(Launcher.java:308)at java.lang.ClassLoader.loadClass(ClassLoader.java:356)at load.libraries.LoadingLibraries.main(LoadingLibraries.java:8)Java結果:1 BUILD SUCCESSFUL(合計時間:2秒)

2位:

run:スレッド "main"の例外java.lang.UnsatisfiedLinkError:loading.libraries.User32.MessageBoxA(ILjava / lang / String; Ljava / lang / String; I)I at load.libraries.User32.MessageBoxA(Native Method)at load.libraries.LoadingLibraries.main(LoadingLibraries.java:10)Java結果:1 BUILD SUCCESSFUL(合計時間:0秒)

4

3 に答える 3

4

JNI を使用してネイティブ コードを呼び出すことは、あなたが試みているほど単純ではありません。呼び出している DLL 内の関数は、特定のインターフェイスに準拠する必要があり、Windows User32.dll などの任意の関数は、JNI が期待する形式に準拠していません。

ラッパー DLL を作成できます。これは、Java から呼び出すことができる JNI API を使用して C でコードを作成することを意味します。

もう 1 つのアプローチは、JNI よりも使いやすく、ネイティブ コードを自分で記述しなくても任意の DLL で関数を呼び出すことができるJNAを使用することです。

于 2013-03-19T14:47:44.150 に答える
3

User32 ライブラリでこれらの関数を呼び出すラッパーを作成する必要があります。それらを直接呼び出さないでください。このチュートリアルhttp://www.ibm.com/developerworks/java/tutorials/j-jni/をご覧ください。

ライブラリをロードして関数を呼び出すだけでなく、さらに多くの手順が必要です。また、これを行うと、Java の優れた点の 1 つが失われることに注意する必要があります。一度走ればどこでも書けること。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 に答える