Collection de modèles JNA (Java Native Access)

Qu'est-ce que JNA

Java Native Access - Wikipedia Overview - JNA API Documentation

J'ai écrit sur les ctypes Python ici. Python: collection de modèles ctypes

Il est difficile de penser à un nouveau matériel, donc </ s> le contenu de l'échantillon est exactement le même.

Préparation

Apportez chaque .jar des sites suivants. https://mvnrepository.com/artifact/net.java.dev.jna/jna https://mvnrepository.com/artifact/net.java.dev.jna/jna-platform

Sélectionnez la version et téléchargez "jar" dans la colonne Fichiers. Ajoutez le fichier jar téléchargé au chemin de classe.

Si vous utilisez Gradle, ajoutez deux lignes aux dépendances de build.gradle au lieu de télécharger le fichier jar vous-même.

dependencies {
    // ...

    //Ajout des deux lignes suivantes
    implementation 'net.java.dev.jna:jna:4.5.2'
    implementation 'net.java.dev.jna:jna-platform:4.5.2'

    // ...
}

Solution par modèle

En utilisant l'API Windows (Win32API) comme thème, nous résumerons les modèles dans divers cas.

Forme basique

Fonction de veille --MSD

C'est un programme simple qui ne dort que pendant 1 seconde. D'abord d'ici.

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

Passer une chaîne

Affichons la boîte de message à l'aide de la fonction MessageBox.

Fonction MessageBox - 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/Ajouter A s'il y a une distinction entre W
        int MessageBoxA(Pointer hWnd, String lpText, String lpCaption, int uType);
    }

    public static void main(String[] args) {
        User32.INSTANCE.MessageBoxA(null, "tester", "Titre", 0);
    }
}

Comme nous le verrons plus tard, le handle de fenêtre a une valeur de 64 bits dans un OS 64 bits, il est donc utilisé comme argument de type `` Pointer ''.

Si le code source est écrit en MS932 (Shift-JIS, CP932), cela fonctionnera, mais si le code source est écrit en UTF-8, les caractères seront déformés. Par conséquent, utilisez la version Unicode de l'API et définissez l'argument de chaîne sur le type 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/Ajouter W s'il y a une distinction entre W
	   	int MessageBoxW(Pointer hWnd, WString lpText, WString lpCaption, int uType);
	}

	public static void main(String[] args) {
		User32.INSTANCE.MessageBoxW(null, new WString("tester"), new WString("Titre"), 0);
	}
}

C'est acceptable. Réglez correctement -encoding '' de javac ''. (Si vous utilisez Eclipse, vous n'avez pas à vous inquiéter trop) Non limité à l'API Windows, s'il y a une fonction qui reçoit le type wchar_t * '' etc., transmettez-la avec WString``.

Désormais, nous allons gérer le passage des chaînes de caractères basées sur Unicode.

Recevoir des données par référence

Fonction GetComputerName --MSD

  1. Obtenez la taille requise du tampon en passant par référence
  2. Allouez un tampon
  3. Obtenez le résultat sous forme de chaîne
  4. Afficher les résultats

C'est le flux de. Les points suivants sont-ils les points?

--Utiliser la version Unicode de la fonction (W à la fin du nom de la fonction) --Lorsque vous voulez passer un type ʻint`` par référence, passez un objet de type ʻIntByReference``.

  • Vous pouvez obtenir la valeur avec `` getValue () ''
  • De même, il y a aussi `` LongByReference '', etc.
  • L'argument du tampon de chaîne doit être de type `` char [] ''
  • Dans le cas d'un tableau, il sera passé par référence sans penser à rien. --Si vous passez null '', vous passez le pointeur NULL (void *) 0 ''. --Convertissez le tampon de chaîne en String '' avec Native.toString () '' --Il semble qu'il puisse être converti avec `` new String () '', mais il n'est pas interprété comme une fin nulle et est suivi de poussière.

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

Résultat de l'exécution: nom de l'ordinateur


taro-pc

Puisque le tableau est passé par référence, il est possible d'utiliser le tableau au lieu de `ʻIntByReference``.

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);
	   	//Le type de lpnSize est int[]À
	   	boolean GetComputerNameW(char[] lpBuffer, int[] lpnSize);
	}

	public static void main(String[] args) {
	   	//Utilisez un tableau de longueur 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));
	}
}

Structure

Exemple 1

Fonction GetCursorPos --MSD

Définissez la structure dans une classe qui hérite de `` com.sun.jna.Structure ''.

  • Répertorier les variables membres comme publiques --Mise en œuvre `` getFieldOrder () '' pour définir l'ordre en mémoire
  • Les variables de membre doivent être listées en proportion juste --This.getClass (). GetFields () ne peut pas être utilisé car l'ordre n'est pas défini [^ 1]

Si vous spécifiez la structure (classe) comme argument, elle sera automatiquement passée par référence.

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

Résultat de l'exécution: position du curseur de la souris


x = 340, y = 1061

Exemple 2

Vient ensuite l'histoire lorsqu'un tableau `` char '' de longueur fixe ou une autre structure entre dans la structure.

Fonction FindFirstFile --MSD Fonction FindNextFile --MSD Fonction FindCLose --MSD

  • Si vous spécifiez un type de tableau en tant que membre de la structure, cela revient à passer par valeur au lieu d'un pointeur.
  • Contrairement aux arguments, il n'est pas automatiquement passé par référence (passé par pointeur). Si vous voulez passer par référence, utilisez le type Pointer '' ou le type ByteBuffer ''.
  • La taille de la structure n'est pas déterminée tant que vous n'assignez pas une instance à tous les membres du type de tableau.
  • En d'autres termes, il n'y a pas de valeur initiale implicite (vous devez attribuer une instance)
  • Si vous spécifiez une structure en tant que membre de structure, cela revient à passer par valeur au lieu d'un pointeur.
  • Contrairement aux arguments, il ne passe pas automatiquement par référence (passe par pointeur) --La valeur initiale implicite est entièrement nulle
  • Les membres d'une taille de 32 bits sur un système d'exploitation 32 bits et de 64 bits sur un système d'exploitation 64 bits sont définis par le type pointeur ''. --Type de poignée et de pointeur (y compris `ʻUINT_PTR etc.) --Type de WPARAM '' / LPARAM '' --Si vous voulez voir la valeur réelle, vous pouvez l'obtenir avec `` Pointer.nativeValue (ptr) ''

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

Résultat de l'exécution: directement sous le dossier Windows.liste de fichiers exe


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

Exemple 3

Fonction GetOpenFileName --MSD

--Fonctions équivalentes à sizeof '' dans la méthode Structure.size () '' --Définissez une chaîne Unicode qui ne change pas avec le type WString --Définissez un membre de type `` ByteBuffer '' lors de la spécification de l'adresse de la zone mémoire à modifier

  • Cela ne fonctionne pas bien même si vous spécifiez un type de tableau tel que char [] '' (il est traité comme passant par valeur comme décrit ci-dessus) --Réservez la zone mémoire avec ByteBuffer.allocateDirect () ''
  • Le contenu de la mémoire peut être copié dans un tableau de n'importe quel type
  • Veillez à ne pas oublier de spécifier ByteOrder

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("fichier texte\0*.txt\0\0");
		ofn.lpstrFile = buf;
		ofn.nMaxFile = lenFilenameBufferInChars;
		ofn.lpstrTitle = new WString("Veuillez sélectionner un fichier");
		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("a été annulé");
		}
	}
}

Résultat de l'exécution: nom de fichier sélectionné


C:\Users\taro\test.txt

À ce stade, cela devient assez difficile. J'ai eu beaucoup de mal à savoir quoi faire avec les types de membres de la structure.

Fonction de rappel

Certaines fonctions de l'API Windows appellent la fonction de rappel spécifiée lorsqu'un événement se produit. Par exemple, la fonction `ʻEnumWindows``, qui énumère les fenêtres existantes, notifie la fenêtre trouvée avec une fonction de rappel.

Fonction EnumWindows --MSD

Le flux est le suivant.

--Définissez l'interface de la fonction de rappel en héritant de l'interface Callback '' --Définissez l'argument et les types de retour avec la méthode `ʻinvoke

  • Implémentation de la méthode `ʻinvoke`` de l'interface définie précédemment --Peut également être implémenté avec des fonctions anonymes

Comme il est difficile à comprendre même si seules les poignées de fenêtre sont répertoriées, un exemple de sortie avec le titre de la fenêtre est affiché.

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

Résultat de l'exécution: Liste des fenêtres ouvertes (extrait)


20730:Accès rapide
10226:Compteur de batterie
9d09aa: eclipse
f05b4:calculatrice

Pointeur pointeur

Je me demande quoi échantillonner car je ne l'utilise pas beaucoup dans l'API Windows, mais j'utiliserai ici la fonction wvsprintf '', qui est une fonction de format de chaîne. En Java, vous pouvez faire la même chose en utilisant la fonction String.format () '', il n'est donc pas nécessaire de l'exécuter à partir de Java.

fonction wvsprintf --MSD

Cette fonction a une manière spéciale de passer des arguments, mais c'est la même chose que de passer un pointeur vers une chaîne (c'est-à-dire un pointeur vers un pointeur en langage C) tant que vous ne passez qu'une seule chaîne. (Je ne parlerai pas de deux ou plus ici)

Commencez par créer un tableau de chaînes de caractères et passez le tableau par référence.

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

Résultat de l'exécution: chaîne de caractères formatée


My name is Michael

Faites la même chose différemment. Cela semble un peu détourné, mais c'est une méthode plus sensible aux pointeurs.

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

Le type LPWSTR que vous voyez dans l'API Windows est sorti, mais il s'agit en fait d'une sous-classe de PointerType ''. Puisque ```IntByReference etc. hérite également de PointerType, il peut être traité de la même manière que ces séries ByReference.

L'argument de ```arglistest de type Pointer, mais il peut aussi être de type PointerByReference. Dans ce cas, vous pouvez passer `ʻargArray tel quel (sans utilisergetPointer ()) sans conversion. De cette façon, vous pouvez écrire de différentes manières même lorsque vous effectuez le même traitement, mais je pense que vous devez choisir la méthode qui vous convient à chaque fois.

Résumé

Peut-être pouvons-nous faire plus, mais je pense qu'il suffit d'avoir un modèle comme celui-ci comme point de départ. Vous pouvez regarder d'autres modèles lorsque vous voulez le faire (lorsque vous devez le faire).

Page de référence

Recommended Posts

Collection de modèles JNA (Java Native Access)
Exécuter Rust depuis Java avec JNA (Java Native Access)
Collection Java9
Modificateur d'accès [Java]
[Java] Modèle de stratégie
Modèle de conception Java
modèle de rappel java
[Java] Motif singleton
Réintroduction Java - Collection Java
[Java] Modèle d'adaptateur
[Java] Cadre de collection
Mémo de modèle Java
Collection expirée de java
Questions d'entretien de Java Collection
Accédez à API.AI depuis Java
À propos des modificateurs d'accès Java
Modèle de générateur (Java effectif)
Résumé du modèle de conception Java
Premiers pas avec Java Collection
Collection d'exemples de code parallèle Java
[Design pattern] Bibliothèque de base Java
[Java] Comparateur de la classe Collection
Collection de méthodes de code de test Java
Qu'est-ce qu'une collection Java?
Modèle de stratégie Enum en Java
Collecte de copies approfondies en Java