JNA-Mustersammlung (Java Native Access)

Was ist JNA?

Java Native Access - Wikipedia Overview - JNA API Documentation

Ich habe hier über Python-Typen geschrieben. Python: ctypes-Mustersammlung

Es ist mühsam, über neues Material nachzudenken, daher </ s> ist der Inhalt der Probe genau der gleiche.

Vorbereitung

Bringen Sie jedes .jar von den folgenden Seiten. https://mvnrepository.com/artifact/net.java.dev.jna/jna https://mvnrepository.com/artifact/net.java.dev.jna/jna-platform

Wählen Sie die Version aus und laden Sie "jar" in die Spalte "Dateien" herunter. Fügen Sie das heruntergeladene Glas zum Klassenpfad hinzu.

Wenn Sie Gradle verwenden, fügen Sie den Abhängigkeiten von build.gradle zwei Zeilen hinzu, anstatt das Glas selbst herunterzuladen.

dependencies {
    // ...

    //Die folgenden zwei Zeilen wurden hinzugefügt
    implementation 'net.java.dev.jna:jna:4.5.2'
    implementation 'net.java.dev.jna:jna-platform:4.5.2'

    // ...
}

Lösung nach Muster

Unter Verwendung der Windows-API (Win32API) als Thema werden Muster in verschiedenen Fällen zusammengefasst.

Grundform

Sleep-Funktion --MSD

Es ist ein einfaches Programm, das nur 1 Sekunde lang schläft. Zuerst von hier.

JNISample.java


import com.sun.jna.Library;
import com.sun.jna.Native;

public class JNISample {
	public interface Kernel32 extends Library {
		Kernel32 INSTANCE = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);
	   	void Sleep(int dwMilliseconds);
	}

	public static void main(String[] args) {
		System.out.println("started");
		Kernel32.INSTANCE.Sleep(1000);
		System.out.println("finished");
	}
}

Übergeben Sie eine Zeichenfolge

Lassen Sie uns das Meldungsfeld mit der MessageBox-Funktion anzeigen.

MessageBox-Funktion --MSD

JNISample.java


import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;

public class JNISample {
    public interface User32 extends Library {
        User32 INSTANCE = (User32) Native.loadLibrary("user32", User32.class);
        // A/Fügen Sie A hinzu, wenn zwischen W unterschieden wird
        int MessageBoxA(Pointer hWnd, String lpText, String lpCaption, int uType);
    }

    public static void main(String[] args) {
        User32.INSTANCE.MessageBoxA(null, "Prüfung", "Titel", 0);
    }
}

Wie wir später sehen werden, hat das Fensterhandle in einem 64-Bit-Betriebssystem einen 64-Bit-Wert, daher wird es als Argument vom Typ "Zeiger" verwendet.

Wenn der Quellcode in MS932 (Shift-JIS, CP932) geschrieben ist, funktioniert dies, aber wenn der Quellcode in UTF-8 geschrieben ist, werden die Zeichen verstümmelt. Verwenden Sie daher die Unicode-Version der API und setzen Sie das Zeichenfolgenargument auf den Typ "WString".

JNISample.java


import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.WString;

public class JNISample {
	public interface User32 extends Library {
		User32 INSTANCE = (User32) Native.loadLibrary("user32", User32.class);
	   	// A/Addiere W, wenn es einen Unterschied zwischen W gibt
	   	int MessageBoxW(Pointer hWnd, WString lpText, WString lpCaption, int uType);
	}

	public static void main(String[] args) {
		User32.INSTANCE.MessageBoxW(null, new WString("Prüfung"), new WString("Titel"), 0);
	}
}

Das ist in Ordnung. Stellen Sie -encoding von javac entsprechend ein. (Wenn Sie Eclipse verwenden, müssen Sie sich nicht zu viele Sorgen machen.) Nicht auf die Windows-API beschränkt. Wenn es eine Funktion gibt, die den Typ "wchar_t *" usw. empfängt, übergeben wir sie mit "WString".

Von nun an werden wir die Übergabe von Zeichenfolgen basierend auf Unicode behandeln.

Daten per Referenz empfangen

GetComputerName-Funktion --MSD

  1. Ermitteln Sie die erforderliche Größe des Puffers, indem Sie als Referenz übergeben
  2. Ordnen Sie einen Puffer zu
  3. Holen Sie sich das Ergebnis als Zeichenfolge
  4. Ergebnisse anzeigen

Es ist der Fluss von. Sind die folgenden Punkte die Punkte?

  • Unicode-Version der Funktion verwenden (W am Ende des Funktionsnamens) --Wenn Sie den Typ "int" als Referenz übergeben möchten, übergeben Sie das Objekt "IntByReference".
  • Sie können den Wert mit getValue () erhalten
  • Ähnlich gibt es auch LongByReference etc.
  • Das Argument des Zeichenfolgenpuffers sollte vom Typ "char []" sein
  • Im Fall eines Arrays wird es als Referenz übergeben, ohne an irgendetwas zu denken.
  • Wenn Sie "null" übergeben, übergeben Sie den NULL-Zeiger "(void *) 0".
  • Konvertieren Sie den String-Puffer mit Native.toString () in String
  • Es sieht so aus, als ob es mit new String () konvertiert werden kann, aber es wird nicht als Null-Ende interpretiert und es folgt Staub.

JNISample.java


import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.ptr.IntByReference;

public class JNISample {
	public interface Kernel32 extends Library {
		Kernel32 INSTANCE = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);
	   	boolean GetComputerNameW(char[] lpBuffer, IntByReference lpnSize);
	}

	public static void main(String[] args) {
		IntByReference lenComputerName = new IntByReference();
		Kernel32.INSTANCE.GetComputerNameW(null, lenComputerName);
		char[] computerName = new char[lenComputerName.getValue()];
		Kernel32.INSTANCE.GetComputerNameW(computerName, lenComputerName);
		System.out.println(Native.toString(computerName));
	}
}

Ausführungsergebnis: Computername


taro-pc

Da Arrays als Referenz übergeben werden, ist es möglich, Arrays anstelle von "IntByReference" zu verwenden.

import com.sun.jna.Library;
import com.sun.jna.Native;

public class JNISample {
	public interface Kernel32 extends Library {
		Kernel32 INSTANCE = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);
	   	//Der Typ von lpnSize ist int[]Zu
	   	boolean GetComputerNameW(char[] lpBuffer, int[] lpnSize);
	}

	public static void main(String[] args) {
	   	//Verwenden Sie ein Array der Länge 1
		int[] lenComputerName = new int[1];
		Kernel32.INSTANCE.GetComputerNameW(null, lenComputerName);
		char[] computerName = new char[lenComputerName[0]];
		Kernel32.INSTANCE.GetComputerNameW(computerName, lenComputerName);
		System.out.println(Native.toString(computerName));
	}
}

Struktur

Beispiel 1

GetCursorPos-Funktion --MSD

Definieren Sie die Struktur in einer Klasse, die von com.sun.jna.Structure erbt.

--Listet Mitgliedsvariablen als öffentlich auf

  • Implementieren Sie getFieldOrder (), um die Reihenfolge im Speicher zu definieren --Mitgliedvariablen müssen nur proportional aufgelistet werden --This.getClass (). GetFields () kann nicht verwendet werden, da die Reihenfolge undefiniert ist [^ 1]

Wenn Sie die Struktur (Klasse) als Argument angeben, wird sie automatisch als Referenz übergeben.

JNISample.java


import java.util.Arrays;
import java.util.List;

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Structure;

public class JNISample {
	public interface User32 extends Library {
		User32 INSTANCE = (User32) Native.loadLibrary("user32", User32.class);
		boolean GetCursorPos(POINT lpPoint);
	}

	public static class POINT extends Structure {
		@Override
		protected List<String> getFieldOrder() {
			return Arrays.asList("X", "Y");
		}
		public int X;
		public int Y;
	}

	public static void main(String[] args) {
		POINT pt = new POINT();
		User32.INSTANCE.GetCursorPos(pt);
		System.out.println(String.format("x = %d, y = %d", pt.X, pt.Y));
	}
}

Ausführungsergebnis: Mauszeigerposition


x = 340, y = 1061

Beispiel 2

Als nächstes folgt die Geschichte, wenn ein char-Array fester Länge oder eine andere Struktur in die Struktur kommt.

FindFirstFile-Funktion --MSD FindNextFile-Funktion --MSD FindCLose-Funktion --MSD

  • Wenn Sie einen Array-Typ als Strukturelement angeben, entspricht dies der Übergabe eines Werts anstelle eines Zeigers.
  • Im Gegensatz zu Argumenten wird es nicht automatisch als Referenz übergeben (als Zeiger übergeben). Wenn Sie als Referenz übergeben möchten, verwenden Sie den Typ "Zeiger" oder "ByteBuffer".
  • Die Strukturgröße wird erst bestimmt, wenn Sie allen Mitgliedern des Array-Typs eine Instanz zuweisen.
  • Mit anderen Worten, es gibt keinen impliziten Anfangswert (Sie müssen eine Instanz zuweisen).
  • Wenn Sie eine Struktur als Strukturelement angeben, entspricht dies der Übergabe eines Werts anstelle eines Zeigers.
  • Im Gegensatz zu Argumenten wird es nicht automatisch als Referenz übergeben (als Zeiger übergeben)
  • Der implizite Anfangswert ist alle Null
  • Mitglieder mit einer Größe von 32 Bit unter 32 Bit und 64 Bit unter 64 Bit werden durch den Zeigertyp "Zeiger" definiert.
  • Griff- und Zeigertyp (einschließlich UINT_PTR usw.)
  • Typ von WPARAM / LPARAM
  • Wenn Sie den tatsächlichen Wert sehen möchten, können Sie ihn mit Pointer.nativeValue (ptr) abrufen

JNISample.java


import java.util.Arrays;
import java.util.List;

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.WString;

public class JNISample {
	public interface Kernel32 extends Library {
		Kernel32 INSTANCE = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);
	   	Pointer FindFirstFileW(WString lpFileName, WIN32_FIND_DATAW lpFindFileData);
	   	boolean FindNextFileW(Pointer hFindFile, WIN32_FIND_DATAW lpFindFileData);
	   	boolean FindClose(Pointer hFindFile);
	}

	public static final int MAX_PATH = 260;
	public static final Pointer INVALID_HANDLE_VALUE = new Pointer(-1);

	public static class FILETIME extends Structure {
        @Override
        protected List<String> getFieldOrder() {
            return Arrays.asList("dwLowDateTime", "dwHighDateTime");
        }
		public int dwLowDateTime;
		public int dwHighDateTime;
	}

	public static class WIN32_FIND_DATAW extends Structure {
        @Override
        protected List<String> getFieldOrder() {
            return Arrays.asList(
            		"dwFileAttributes", "ftCreationTime", "ftLastAccessTime", "ftLastWriteTime",
            		"nFileSizeHigh", "nFileSizeLow", "dwReserved0", "dwReserved1",
            		"cFileName", "cAlternateFileName", "dwFileType", "dwCreatorType", "wFinderFlags"
            );
        }
		public int      dwFileAttributes;
		public FILETIME ftCreationTime;
		public FILETIME ftLastAccessTime;
		public FILETIME ftLastWriteTime;
		public int      nFileSizeHigh;
		public int      nFileSizeLow;
		public int      dwReserved0;
		public int      dwReserved1;
		public char[]   cFileName          = new char[MAX_PATH];
		public char[]   cAlternateFileName = new char[14];
		public int      dwFileType;
		public int      dwCreatorType;
		public short    wFinderFlags;
	}

	public static void main(String[] args) {
		String pattern = "C:\\Windows\\*.exe";
		WIN32_FIND_DATAW findData = new WIN32_FIND_DATAW();
		Pointer hfind = Kernel32.INSTANCE.FindFirstFileW(new WString(pattern), findData);
		if (hfind != INVALID_HANDLE_VALUE) {
			do {
				System.out.println(Native.toString(findData.cFileName));
			} while (Kernel32.INSTANCE.FindNextFileW(hfind, findData));
		}
		Kernel32.INSTANCE.FindClose(hfind);
	}
}

Ausführungsergebnis: Direkt unter dem Windows-Ordner.exe Dateiliste


bfsvc.exe
explorer.exe
HelpPane.exe
hh.exe
notepad.exe
regedit.exe
RtCRU64.exe
splwow64.exe
winhlp32.exe
write.exe

Beispiel 3

GetOpenFileName-Funktion --MSD

--Funktionen, die sizeof in der Structure.size () Methode entsprechen

  • Definieren Sie eine Unicode-Zeichenfolge, die sich nicht mit dem Typ "WString" ändert
  • Definieren Sie ein Mitglied vom Typ "ByteBuffer", wenn Sie die Adresse des zu ändernden Speicherbereichs angeben
  • Es funktioniert nicht gut, selbst wenn Sie einen Array-Typ wie char [] angeben (es wird wie oben beschrieben als Wertübergabe behandelt)
  • Speicherbereich mit ByteBuffer.allocateDirect () reservieren
  • Der Inhalt des Speichers kann in ein Array eines beliebigen Typs kopiert werden
  • Vergessen Sie nicht, ByteOrder anzugeben

JNISample.java


import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.CharBuffer;
import java.util.Arrays;
import java.util.List;

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.WString;

public class JNISample {
	public interface Comdlg32 extends Library {
		Comdlg32 INSTANCE = (Comdlg32) Native.loadLibrary("comdlg32", Comdlg32.class);
		boolean GetOpenFileNameW(OPENFILENAME lpofn);
	}

	public static class OPENFILENAME extends Structure {
		@Override
		protected List<String> getFieldOrder() {
			return Arrays.asList(
					"lStructSize", "hwndOwner", "hInstance", "lpstrFilter", "lpstrCustomFilter", "nMaxCustFilter",
					"nFilterIndex", "lpstrFile", "nMaxFile", "lpstrFileTitle", "nMaxFileTitle", "lpstrInitialDir",
					"lpstrTitle", "Flags", "nFileOffset", "nFileExtension", "lpstrDefExt", "lCustData", "lpfnHook",
					"lpTemplateName", "pvReserved", "dwReserved", "FlagsEx"
			);
		}
		public int        lStructSize;
		public Pointer    hwndOwner;
		public Pointer    hInstance;
		public WString    lpstrFilter;
		public WString    lpstrCustomFilter;
		public int        nMaxCustFilter;
		public int        nFilterIndex;
		public ByteBuffer lpstrFile;
		public int        nMaxFile;
		public WString    lpstrFileTitle;
		public int        nMaxFileTitle;
		public WString    lpstrInitialDir;
		public WString    lpstrTitle;
		public int        Flags;
		public short      nFileOffset;
		public short      nFileExtension;
	  	public WString    lpstrDefExt;
	  	public Pointer    lCustData;
	  	public Pointer    lpfnHook;
	  	public WString    lpTemplateName;
	  	public Pointer    pvReserved;
	  	public int        dwReserved;
	  	public int        FlagsEx;
	}

	public static void main(String[] args) {
		OPENFILENAME ofn = new OPENFILENAME();
		final int lenFilenameBufferInChars = 1024;
		ByteBuffer buf = ByteBuffer.allocateDirect(lenFilenameBufferInChars * 2);
		ofn.lStructSize = ofn.size();
		ofn.lpstrFilter = new WString("Textdatei\0*.txt\0\0");
		ofn.lpstrFile = buf;
		ofn.nMaxFile = lenFilenameBufferInChars;
		ofn.lpstrTitle = new WString("Bitte wählen Sie die Datei");
		ofn.Flags = 0x00001000; // OFN_FILEMUSTEXIST
		boolean ret = Comdlg32.INSTANCE.GetOpenFileNameW(ofn);
		if (ret) {
			CharBuffer cbuf = buf.order(ByteOrder.LITTLE_ENDIAN).asCharBuffer();
			char[] arr = new char[cbuf.capacity()];
			cbuf.get(arr);
			System.out.println(Native.toString(arr));
		} else {
			System.out.println("wurde storniert");
		}
	}
}

Ausführungsergebnis: Ausgewählter Dateiname


C:\Users\taro\test.txt

An diesem Punkt wird es ziemlich schwierig. Ich hatte ziemlich viel Probleme damit, was ich mit den Typen der Mitglieder der Struktur anfangen sollte.

Rückruffunktion

Einige Windows-API-Funktionen rufen die angegebene Rückruffunktion auf, wenn ein Ereignis auftritt. Beispielsweise benachrichtigt die Funktion "EnumWindows", die vorhandene Fenster auflistet, das gefundene Fenster durch eine Rückruffunktion.

EnumWindows-Funktion --MSD

Der Fluss ist wie folgt.

  • Definieren Sie die Schnittstelle der Rückruffunktion, indem Sie die Rückruf -Schnittstelle erben
  • Definieren Sie Argument- und Rückgabetypen mit der Methode invoke
  • Die Methode invoke der zuvor definierten Schnittstelle wurde implementiert
  • Kann auch mit anonymen Funktionen implementiert werden

Da es schwer zu verstehen ist, selbst wenn nur die Fenstergriffe aufgelistet sind, wird ein Beispiel für die Ausgabe mit dem Fenstertitel gezeigt.

JNISample.java


import com.sun.jna.Callback;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;

public class JNISample {
	public interface User32 extends Library {
		User32 INSTANCE = (User32) Native.loadLibrary("user32", User32.class);
		boolean EnumWindows(EnumWindowsProc lpEnumFunc, Pointer lParam);
		int GetWindowTextW(Pointer hWnd, char[] lpString, int nMaxCount);
	}

	public interface EnumWindowsProc extends Callback {
	    public boolean invoke(Pointer hWnd, Pointer lParam);
	}

	public static void main(String[] args) {
		User32.INSTANCE.EnumWindows(new EnumWindowsProc() {
			@Override
			public boolean invoke(Pointer hWnd, Pointer lParam) {
				char[] windowText = new char[1024];
				User32.INSTANCE.GetWindowTextW(hWnd, windowText, windowText.length);
				System.out.println(String.format("%x: %s", Pointer.nativeValue(hWnd), Native.toString(windowText)));
				return true;
			}
		}, null);
	}
}

Ausführungsergebnis: Liste der geöffneten Fenster (Auszug)


20730:Schneller Zugang
10226:Batterieanzeige
9d09aa: eclipse
f05b4:Taschenrechner

Zeiger Zeiger

Ich frage mich, was ich probieren soll, weil ich es in der Windows-API nicht oft verwende, aber hier verwende ich die Funktion wvsprintf, die eine Funktion für das Zeichenfolgenformat ist. In Java können Sie dasselbe mit der Funktion String.format () tun, sodass es nicht erforderlich ist, sie von Java aus auszuführen.

wvsprintf-Funktion --MSD

Diese Funktion hat eine spezielle Methode zum Übergeben von Argumenten, entspricht jedoch dem Übergeben eines Zeigers auf eine Zeichenfolge (dh eines Zeigers auf einen Zeiger in der Sprache C), solange Sie nur eine Zeichenfolge übergeben. (Ich werde hier nicht über zwei oder mehr sprechen)

Erstellen Sie zunächst ein Array von Zeichenfolgen und übergeben Sie das Array als Referenz.

JNISample.java


import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.WString;

public class JNISample {
	public interface User32 extends Library {
		User32 INSTANCE = (User32) Native.loadLibrary("user32", User32.class);
	   	int wvsprintfW(char[] lpOutput, WString lpFormat, WString[] arglist);
	}

	public static void main(String[] args) {
		char[] buf = new char[1024];
		String name = "Michael";
		WString[] argArray = new WString[] {new WString(name)};
		User32.INSTANCE.wvsprintfW(buf, new WString("My name is %s"), argArray);
		System.out.println(Native.toString(buf));
	}
}

Ausführungsergebnis: Formatierte Zeichenfolge


My name is Michael

Mach dasselbe anders. Es sieht ein wenig umständlich aus, ist aber eine zeigerbewusste Methode.

JNISample.java


import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.WString;
import com.sun.jna.platform.win32.WTypes;
import com.sun.jna.ptr.PointerByReference;

public class JNISample {
	public interface User32 extends Library {
		User32 INSTANCE = (User32) Native.loadLibrary("user32", User32.class);
	   	int wvsprintfW(char[] lpOutput, WString lpFormat, Pointer arglist);
	}

	public static void main(String[] args) {
		char[] buf = new char[1024];
		String name = "Michael";
		WTypes.LPWSTR pname = new WTypes.LPWSTR(name); // wchar_t *
		PointerByReference argArray = new PointerByReference(pname.getPointer()); // wchar_t **
		User32.INSTANCE.wvsprintfW(buf, new WString("My name is %s"), argArray.getPointer());
		System.out.println(Native.toString(buf));
	}
}

Der in der Windows-API angezeigte Typ "LPWSTR" wurde angezeigt, ist jedoch eine Unterklasse von "PointerType". Da "IntByReference" usw. auch "PointerType" erben, kann es auf die gleiche Weise behandelt werden wie diese "ByReference" -Serien.

Das Argument von "arglist" ist vom Typ "Pointer", kann aber auch vom Typ "PointerByReference" sein. In diesem Fall können Sie "argArray" unverändert ohne Konvertierung übergeben (ohne "getPointer ()"). Auf diese Weise können Sie auch bei gleicher Verarbeitung auf verschiedene Arten schreiben, aber ich denke, Sie sollten die Methode wählen, die für jedes Mal geeignet ist.

Zusammenfassung

Vielleicht können wir mehr tun, aber ich denke, es reicht aus, ein solches Muster als Ausgangspunkt zu haben. Sie können sich andere Muster ansehen, wenn Sie es tun möchten (wenn Sie es tun müssen).

Referenzseite

Recommended Posts

JNA-Mustersammlung (Java Native Access)
Führen Sie Rust von Java mit JNA (Java Native Access) aus.
Java9-Sammlung
Zugriffsmodifikator [Java]
[Java] Strategiemuster
Java-Entwurfsmuster
Java-Rückrufmuster
[Java] Singleton-Muster
Java Reintroduction-Java Collection
[Java] Adaptermuster
[Java] Sammlungsframework
Java-Muster-Memo
Abgelaufene Java-Sammlung
Fragen zum Java-Sammlungsinterview
Greifen Sie über Java auf API.AI zu
Informationen zu Java-Zugriffsmodifikatoren
Builder-Muster (effektives Java)
Zusammenfassung des Java-Entwurfsmusters
Erste Schritte mit Java Collection
Java Parallel Code Sample Collection
[Entwurfsmuster] Java-Kernbibliothek
[Java] Komparator der Collection-Klasse
Sammlung von Java-Testcode-Methoden
Was ist eine Java-Sammlung?
Enum Strategiemuster in Java
Deep Copy Collection in Java