Java Native Access (JNA) class Vs interface
Oliv
-
Oliv -
Oliv -
Bonjour,
Voilà mon petit(?) soucis :
J'utilisais l'interface pour récupérer user32.dll de la manière suivante :
Je faisais tant bien que mal ce que je recherchais.
Las, j'ai voulu passer par la
Et patatras !
Les fonctions natives en commentaires renvoient une erreur : méthode introuvable.
Et les fonctions :
aussi, bien que les mêmes mais avec un "A" au bout de leur nom semblent fonctionner, mais sont-elles vraiment équivalentes ?.
Pourquoi ?
Comment obtenir la liste des fonctions natives et leur constructions pour les utiliser au sein d'une
Comment placer un
Doit-on créer une
Quand à :
dont j'avais besoin pour pouvoir utiliser :
Il ne compile carrément pas,
Que dois-je faire ?
Voilà mon petit(?) soucis :
J'utilisais l'interface pour récupérer user32.dll de la manière suivante :
private interface User32 extends StdCallLibrary { static final User32 INSTANCE = (User32)Native.load ( "user32", User32.class, W32APIOptions.DEFAULT_OPTIONS ); class WINDOWPLACEMENT extends Structure { public int length; public int flags; public int showCmd; public POINT ptMinPosition; public POINT ptMaxPosition; public RECT rcNormalPosition; private WINDOWPLACEMENT(){ length = size(); // Lignes totalement inutiles, juste pour ne pas avoir de @SuppressWarnings("unused") List<Object>_null = Arrays.asList ( length, flags, showCmd, ptMinPosition, ptMaxPosition, rcNormalPosition ); _null.isEmpty(); //=================================================================================== } @Override protected List<String>getFieldOrder(){ return Arrays.asList ( "length", "flags", "showCmd", "ptMinPosition", "ptMaxPosition", "rcNormalPosition" ); } } int GetWindowRect(HWND h_wnd, int _rect[]); int GetWindowTextA(HWND h_wnd, byte lp_string[], int n_max_count); boolean EnumWindows(WNDENUMPROC lp_enum_func, Pointer _pointer); boolean IsWindowVisible(HWND h_wnd); UINT SendInput(DWORD cInputs, INPUT pInputs[], int cbSize); BOOL SetForegroundWindow(HWND h_wnd); BOOL GetWindowPlacement(HWND h_wnd, WINDOWPLACEMENT lp_wnd_pl); BOOL SetWindowPlacement(HWND h_wnd, WINDOWPLACEMENT lp_wnd_pl); BOOL SetWindowPos ( HWND h_wnd, HWND h_wnd_insert_after, int _x, int _y, int _cx, int _cy, int u_flag ); }
Je faisais tant bien que mal ce que je recherchais.
Las, j'ai voulu passer par la
classau lieu de l'
interfaceen faisant :
private static class User32 { static { Native.register("user32"); } public static class WINDOWPLACEMENT extends Structure { public int length; public int flags; public int showCmd; public POINT ptMinPosition; public POINT ptMaxPosition; public RECT rcNormalPosition; public WINDOWPLACEMENT(){ length = size(); // Lignes totalement inutiles, juste pour ne pas avoir de @SuppressWarnings("unused") List<Object>_null = Arrays.asList ( length, flags, showCmd, ptMinPosition, ptMaxPosition, rcNormalPosition ); _null.isEmpty(); //=================================================================================== } @Override protected List<String>getFieldOrder(){ return Arrays.asList ( "length", "flags", "showCmd", "ptMinPosition", "ptMaxPosition", "rcNormalPosition" ); } } private static native BaseTSD.LONG_PTR SetWindowLongPtrA(HWND hWnd, int nIndex, BaseTSD.LONG_PTR dwNewLongPtr); private static native HWND GetForegroundWindow(); //private static native HHOOK SetWindowsHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hMod, int dwThreadId); //private static native UINT SendInput(DWORD cInputs, INPUT pInputs[], int cbSize); private static native BOOL GetWindowPlacement(HWND h_wnd, WINDOWPLACEMENT lp_wnd_pl); private static native BOOL SetWindowPlacement(HWND h_wnd, WINDOWPLACEMENT lp_wnd_pl); private static native Pointer SetWindowLongA(HWND hWnd, int nIndex, Pointer dwNewLong); private static native Pointer SetWindowLongPtrA(HWND hWnd, int nIndex, Pointer dwNewLongPtr); private static native LRESULT CallNextHookEx(HHOOK hhk, int nCode, WPARAM wParam, Pointer lParam); private static native LRESULT CallNextHookEx(HHOOK hhk, int nCode, WPARAM wParam, LPARAM lParam); private static native LRESULT DefWindowProcA(HWND hWnd, int Msg, WPARAM wParam, LPARAM lParam); // private static native LRESULT DispatchMessage(MSG lpMsg); private static native void PostMessageA(HWND hWnd, int msg, WPARAM wParam, LPARAM lParam); private static native void PostQuitMessage(int nExitCode); // private static native int GetMessage(MSG lpMsg, HWND hWnd, int wMsgFilterMin, int wMsgFilterMax); private static native int GetWindowTextLengthA(HWND hWnd); private static native int GetWindowTextA(HWND hWnd, char[] lpString, int nMaxCount); private static native int GetWindowThreadProcessId(HWND hWnd, IntByReference lpdwProcessId); private static native int SetWindowLongA(HWND hWnd, int nIndex, int dwNewLong); private static native boolean EnumWindows(WNDENUMPROC lpEnumFunc, Pointer data); private static native boolean GetWindowRect(HWND hWnd, RECT rect); private static native boolean IsWindowVisible(HWND hWnd); private static native boolean PeekMessageA(MSG lpMsg, HWND hWnd, int wMsgFilterMin, int wMsgFilterMax, int wRemoveMsg); private static native boolean SetForegroundWindow(HWND hWnd); private static native boolean SetWindowPos(HWND hWnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags); private static native boolean ShowWindow(HWND hWnd, int nCmdShow); private static native boolean TranslateMessage(MSG lpMsg); private static native boolean UnhookWindowsHookEx(HHOOK hhk); }
Et patatras !
Les fonctions natives en commentaires renvoient une erreur : méthode introuvable.
Et les fonctions :
SetWindowLongPtr
DefWindowProc
PostMessage
GetWindowTextLength
GetWindowText
SetWindowLong
PeekMessage
aussi, bien que les mêmes mais avec un "A" au bout de leur nom semblent fonctionner, mais sont-elles vraiment équivalentes ?.
Pourquoi ?
Comment obtenir la liste des fonctions natives et leur constructions pour les utiliser au sein d'une
class?
Comment placer un
HHOOKpour suivre les évènements des fenêtres (extérieures à la JVM) ? Rien ne semble remplacer
HHOOK SetWindowsHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hMod, int dwThreadId)
LRESULT DispatchMessage(MSG lpMsg)
int GetMessage(MSG lpMsg, HWND hWnd, int wMsgFilterMin, int wMsgFilterMax)
Doit-on créer une
interfaceen plus de la
classpour elles ?????
Quand à :
UINT SendInput(DWORD cInputs, INPUT pInputs[], int cbSize)
dont j'avais besoin pour pouvoir utiliser :
SetForegroundWindow(HWND hWnd)
Il ne compile carrément pas,
INPUTne serait pas un argument valide...
Que dois-je faire ?
Configuration: Windows / Chrome 79.0.3945.117
A voir également:
- Java Native Access (JNA) class Vs interface
- Waptrick java football - Télécharger - Jeux vidéo
- Jeux java itel - Télécharger - Jeux vidéo
- Eclipse java - Télécharger - Langages
- Udp vs tcp - Guide
- Java apk - Télécharger - Langages
3 réponses
Bonjour,
Comme dans ta précédente discussion le problème concerne plus Windows que Java mais je dirais que tu n'as pas la bonne version de user32.dll (j'imagine qu'elle évolue d'un OS à un autre) et que les méthodes que tu essayes d'utiliser ne sont tout simplement pas dans la DLL
Comme dans ta précédente discussion le problème concerne plus Windows que Java mais je dirais que tu n'as pas la bonne version de user32.dll (j'imagine qu'elle évolue d'un OS à un autre) et que les méthodes que tu essayes d'utiliser ne sont tout simplement pas dans la DLL
Bon. J'ai une première piste, du moins en ce qui concerne la fonction
Selon
https://java-native-access.github.io/jna/4.2.1/
"Use direct mapping of methods
Using direct mapping of methods makes native calls more efficiently than does interface mapping. Direct mapping does not support varargs calls or arrays of Pointer, String, or WString as an argument or return value. For optimium results, use only primitive arguments and return values; you'll have to convert to and from objects yourself explicitly."
Si je comprend bien ce serait le tableau d'
Mais on ne nous dit pas comment y remédier. Les objets pour la conversion en question, on les devine comment ?
Et je ne sais toujours pas pourquoi les quelques autres fonctions (qui n'ont pourtant pas de tableau en paramètre) fonctionnent par l'
UINT SendInput(DWORD c_inputs, INPUT p_inputs[], int cb_size)
Selon
https://java-native-access.github.io/jna/4.2.1/
"Use direct mapping of methods
Using direct mapping of methods makes native calls more efficiently than does interface mapping. Direct mapping does not support varargs calls or arrays of Pointer, String, or WString as an argument or return value. For optimium results, use only primitive arguments and return values; you'll have to convert to and from objects yourself explicitly."
Si je comprend bien ce serait le tableau d'
INPUTqui poserait problème et non
INPUTet ce, uniquement en cas de direct-mapping (
classau lieu d'
interface), ce qui est le cas.
Mais on ne nous dit pas comment y remédier. Les objets pour la conversion en question, on les devine comment ?
Et je ne sais toujours pas pourquoi les quelques autres fonctions (qui n'ont pourtant pas de tableau en paramètre) fonctionnent par l'
interfaceet pas par la
class.
Oki, cool merci.
En attendant, j'avance un peu. Mais c'est pas simple, vu que :
contrairement à ce qui est indiqué là :
https://java-native-access.github.io/jna/4.2.0/com/sun/jna/platform/win32/User32.html
La procédure
ne veut vraiment rien savoir,. En revanche, la procédure
a au moins le mérite de faire comme si elle existait, en dépit de son absence de la doc.
Par contre, si elle renvoie "bien" la longueur en char du titre, rien à faire pour tirer quoi que ce soit de la copie du titre lui même.
Mais... En faisant :
et
Ouiiii. Bon. En fait la
Pfff.
Second point, j'ai pu résoudre le problème de :
tiré de la même doc.
Impossible de trouver quoi que ce soit nul part pour m'aider, à part ce petit filet tiré de la doc et cité dans le commentaire précédant.
En désespoir de cause, je me dis que c'est quand même très bête.
Puis.. Que si c'est vraiment bête, ça donne quoi si on joue au plus bête ?
Pas de tableau en paramètre ni en retour, dans certains cas ? Ok. Alors on oublie les trucs compliqués, cast et consorts, et on vire juste les crochets :
Ouiiiii. Alors je ne sais pas ce qui est effectivement envoyé, vu que c'est seulement pour pouvoir gérer la fenêtre de premier plan (extérieure à la JVM donc), grâce à :
Mais en tous cas, il me le permet. Hallucinant. Si si.
Pour les autres procédures (ouais tant qu'à faire... java c'est des méthode, C c'est des fonctions, ben jna -au moins dans Eclipse, c'est des procédures, na), rien de neuf, toujours inexistantes, invalides, intransformables... indevinables...
J'aimerais bien pouvoir disposer du
si jamais j'arrive à me faire aider du côté de la DLL (aaaah, ben voilà, j'irai du côté du forum Windows, les énerver un peu) qui ferait la même chose que mon code (dans l'autre discussion) mais en agissant sur les message reçus et envoyés par les fenêtres au lieu de corriger leurs conséquences après coup.
Bon. Je m'y remet...
En attendant, j'avance un peu. Mais c'est pas simple, vu que :
contrairement à ce qui est indiqué là :
https://java-native-access.github.io/jna/4.2.0/com/sun/jna/platform/win32/User32.html
La procédure
GetWindowText(HWND hWnd, char[] lpString, int nMaxCount)
ne veut vraiment rien savoir,. En revanche, la procédure
GetWindowTextA(HWND hWnd, char[] lpString, int nMaxCount)
a au moins le mérite de faire comme si elle existait, en dépit de son absence de la doc.
Par contre, si elle renvoie "bien" la longueur en char du titre, rien à faire pour tirer quoi que ce soit de la copie du titre lui même.
char _copy[] = new char[512]; GetWindowTextA(h_wnd, _copy, 512); System.out.println(new String(_copy));// --> seul le saut de ligne apparait System.out.println(Native.toString(_copy));// --> tous les caractères sauf le dernier // sont des "?"
Mais... En faisant :
GetWindowTextA(HWND hWnd, byte[] lpString, int nMaxCount) // et oui, faut qu'ils arrêtent leur char
et
Native.toString(_copy)
Ouiiii. Bon. En fait la
class WindowUtilsdu jna contient une méthode
static:
getWindowTitle(HWND hWnd)
Pfff.
Second point, j'ai pu résoudre le problème de :
SendInput(DWORD cInputs, INPUT pInputs[], int cbSize);
tiré de la même doc.
Impossible de trouver quoi que ce soit nul part pour m'aider, à part ce petit filet tiré de la doc et cité dans le commentaire précédant.
En désespoir de cause, je me dis que c'est quand même très bête.
Puis.. Que si c'est vraiment bête, ça donne quoi si on joue au plus bête ?
Pas de tableau en paramètre ni en retour, dans certains cas ? Ok. Alors on oublie les trucs compliqués, cast et consorts, et on vire juste les crochets :
SendInput(DWORD cInputs, INPUT pInputs, int cbSize);
Ouiiiii. Alors je ne sais pas ce qui est effectivement envoyé, vu que c'est seulement pour pouvoir gérer la fenêtre de premier plan (extérieure à la JVM donc), grâce à :
SetForegroundWindow(HWND hWnd)
Mais en tous cas, il me le permet. Hallucinant. Si si.
Pour les autres procédures (ouais tant qu'à faire... java c'est des méthode, C c'est des fonctions, ben jna -au moins dans Eclipse, c'est des procédures, na), rien de neuf, toujours inexistantes, invalides, intransformables... indevinables...
J'aimerais bien pouvoir disposer du
SetWindowsHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hMod, int dwThreadId)
si jamais j'arrive à me faire aider du côté de la DLL (aaaah, ben voilà, j'irai du côté du forum Windows, les énerver un peu) qui ferait la même chose que mon code (dans l'autre discussion) mais en agissant sur les message reçus et envoyés par les fenêtres au lieu de corriger leurs conséquences après coup.
Bon. Je m'y remet...
Bonjour,
J'ai regardé un peu plus en détail le fonctionnement de JNA en particulier sur l'interface StdCallLibrary que tu as utilisé et il se trouve que tu pourrais aller plus loin car il y a une interface User32 prête à l'emploi :
Exemple :
Voir la source ici : https://github.com/java-native-access/jna/blob/master/contrib/platform/src/com/sun/jna/platform/win32/User32.java
J'ai regardé un peu plus en détail le fonctionnement de JNA en particulier sur l'interface StdCallLibrary que tu as utilisé et il se trouve que tu pourrais aller plus loin car il y a une interface User32 prête à l'emploi :
Exemple :
import com.sun.jna.platform.win32.User32; import com.sun.jna.platform.win32.WinDef.RECT; public class TestUser32 { public static void main(final String[] args) { final User32 user32 = User32.INSTANCE; final RECT rect = new RECT(); user32.GetWindowRect(user32.GetForegroundWindow(), rect); System.out.println(rect); } }
Voir la source ici : https://github.com/java-native-access/jna/blob/master/contrib/platform/src/com/sun/jna/platform/win32/User32.java
User32.INSTANCEEST StdCallLibrary
Cette discussion-ci a pour but de se débarrasser de l'interface, au profit du direct-mapping (une classe) censé être plus performant.
Effectivement, tout ce que je décris ici ne concerne pas l'interface, où tout est fonctionnel (voir code complet et fonctionnel dans l'autre discussion). Mais... bla bla bla, tout relire, c'est de ça que ça parle.
Merci quand même, mais comme expliqué (c'est même par là que je commence), si je fais les appels au natif par l'interface, toutes les méthodes sont bien là. Par la classe, non. Pour être encore plus clair :
Dans le même fichier du même programme, si je mets une classe ET une interface, avec les mêmes méthodes dans l'une et l'autre, le programme plante (méthode introuvable, argument non valide...) quand c'est la classe qui s'en sert, pas quand c'est l'interface.
Et encore une fois JAVA Native Access, c'est du Java. Ouvrir cette discussion dans un forum C ou Windows n'aurait aucun sens : je ne comprendrais rien aux réponses, si tant est qu'elles soient pertinentes.
Du coup j'enlève même le tag "Windows".