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.
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'
// ...
}
En utilisant l'API Windows (Win32API) comme thème, nous résumerons les modèles dans divers cas.
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");
}
}
Affichons la boîte de message à l'aide de la fonction MessageBox.
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.
Fonction GetComputerName --MSD
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``.
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));
}
}
Définissez la structure dans une classe qui hérite de `` com.sun.jna.Structure ''.
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
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
Pointer '' ou le type
ByteBuffer ''. 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
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
char [] '' (il est traité comme passant par valeur comme décrit ci-dessus) --Réservez la zone mémoire avec
ByteBuffer.allocateDirect () ''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.
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.
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
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
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.
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.
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).
Recommended Posts