INE 2 Java Native Access I'm I'maanative nativeAmerican American ■ Einführung ■ Dynamische Bibliotheken ■ Java-Signatur Hello JNA ■ Mittels Java Native Access (JNA) lassen sich native C Funktionen einfach von Java aus aufrufen. ■ Es wird einfach ein Interface definiert, in dem für jede DLL Funktion eine "passende" Java Methode definiert wird. ■ Diese kann dann mit INSTANCE.<FunktionsName> direkt aufgerufen werden. import com.sun.jna.Library; import com.sun.jna.Native; import com.sun.jna.Platform; /** Simple example of native library declaration and usage. */ public class HelloWorld { public interface CLibrary extends Library { CLibrary INSTANCE = (CLibrary) Native.loadLibrary( (Platform.isWindows() ? "msvcrt" : "c"), CLibrary.class); void printf(String format, Object ... args); } public static void main(String[] args) { CLibrary.INSTANCE.printf("Hello, World\n"); for (int i = 0; i < args.length; i++) { CLibrary.INSTANCE.printf("Argument %d: %s\n", i, args[i]); } } } School of Engineering © K. Rege, ZHAW 2 von 17 Dynamische Bibliotheken School of Engineering © K. Rege, ZHAW 3 von 17 Dynamische Bibliotheken ■ Dynamische Bibliotheken müssen speziell erzeugt werden ■ unter Windows mit der Endung DLL ■ Betriebssystem selber besteht aus einer Sammlung von DLLs ■ Sie stellen dem Linker (über Libs) die Funktionen zur Verfügung, ■ Es wird nicht die Funktion sondern lediglich ein Vermerk (Referenz) gespeichert ■ Der Lader löst die Referenz dynamisch auf und lädt die benötigten DLLs nach ■ Suchpfad für die DLLs ist aktuelles Verzeichnis und zusätzlich alle in der "PATH" Umgebungsvariablen vermerkte School of Engineering Dependency Walker zur Dependency Walker zur Anzeige der Abhängigkeiten Anzeige der Abhängigkeiten © K. Rege, ZHAW 4 von 17 Export mit __declspec(dllexport) ■ Exportierte Funktionen müssen speziell gekennzeichnet werden #define DLL_EXPORT __declspec(dllexport) ■ Von andern Modulen importierte ensprechend #define DLL_EXPORT __declspec(dllimport) ■ Die Aufrufkonvention muss __cdecl sein ■ Am einfachsten mit einem Define (z.B. _DLL), das man über das Projekt setzt #ifdef _DLL // If accessing the data from inside the DLL #define DLL_EXPORT __declspec(dllexport) #else // If accessing the data from outside the DLL #define DLL_EXPORT __declspec(dllimport) #endif __cdecl void DLL_EXPORT foo(void); ■ Die exportierten Funktionen sind im LIB File gespeichert School of Engineering © K. Rege, ZHAW 5 von 17 Übersetzung im Überblick ■ Compilierung der Bibliothek und Klient und Ausführen #include #include Compiler Compiler Namen Namender derDLL DLL vermerkt vermerkt DynLib.h DynLib.dll Beim BeimLaden Ladenwird wird die referenzierte die referenzierte DLL DLL(mit(mit)geladen )geladen DynLib.c DynLib.lib Beim Beim Compilieren Compilierenwird wird das h File das h File included included Beim BeimLinken Linken wird wirddas dasliblibFile File gebunden gebunden Lader Lader Compiler Compiler TestClient.exe TestClient.c School of Engineering © K. Rege, ZHAW 6 von 17 DynLib.h #ifndef DYNLIB1_H #define DYNLIB1_H #ifdef _DLL // If accessing the data from inside the DLL #define DLL_EXPORT __declspec(dllexport) #else // If accessing the data from outside the DLL #define DLL_EXPORT __declspec(dllimport) #endif #ifdef __cplusplus extern "C" { #endif void __cdecl DLL_EXPORT foo(void); #ifdef } #endif __cplusplus #endif /* DYNLIB1_H */ School of Engineering © K. Rege, ZHAW 7 von 17 DynLib.c und TestClient.exe ■ Implementation der Library #include "DynLib1.h" #include <stdio.h> void __cdecl foo() { printf("Hello World\n"); } ■ Und Aufruf von foo() in TestClient (separates EXE) #include <stdio.h> #include <stdlib.h> #include "DynLib1.h" int main(int argc, char** argv) { foo(); return (EXIT_SUCCESS); } School of Engineering © K. Rege, ZHAW 8 von 17 Weiterer Vorteil von dynamischen Bibliotheken ■ C-Bibliotheken lassen sich von praktisch jeder Programmiersprache aus aufrufen ■ Z.B. können GUIs mit Java (oder C#) entwickelt werden ■ ■ ■ einfacher plattformunabhängig sehr gute Werkzeuge vorhanden (sog. GUI Builder) ■ Der Aufruf der C Bibliotheksfunktion in Java dann via JNA (später) School of Engineering © K. Rege, ZHAW 9 von 17 LoadLibrary School of Engineering © K. Rege, ZHAW 10 von 17 LoadLibrary ■ Mittels Native.loadLibrary wird die DLL geladen ■ ■ sie muss im Pfad (definiert durch die PATH Umgebungsvariablen) oder im Ausführungsverzeichnis liegen ■ Mittels Platform.isWindows() kann abgefragt werden, ob man sich auf einer Windows Platform befindet public interface CLibrary extends Library { CLibrary INSTANCE = (CLibrary) Native.loadLibrary( (Platform.isWindows() ? "msvcrt" : "c"), CLibrary.class); void printf(String format, Object... args); } School of Engineering © K. Rege, ZHAW 11 von 17 Definition der Signatur ■ Anhand des Header Files kann die Signatur der Java Methode "abgeleitet" werden. ■ void printf(const char *format, ...) -> void printf(String format, Object... args) ■ Die Abbildungsregeln der Datantypen: School of Engineering © K. Rege, ZHAW 12 von 17 … Definition der Signatur ■ Strings werden automatisch umgewandet ■ Structs als Parameter sind etwas komplizierter -> siehe Praktikum ■ Vorsicht: Fehler in der Abbildung werden nicht erkannt und führen zu Laufzeitfehler. School of Engineering © K. Rege, ZHAW 13 von 17 Aufruf der C Funktion ■ Der Aufruf selber wird über INSTANCE ganz "normal" { ... public static void main(String[] args) { CLibrary.INSTANCE.printf("Hello, World\n"); } } School of Engineering © K. Rege, ZHAW 14 von 17 Noch Fragen School of Engineering © K. Rege, ZHAW 15 von 17 Bsp: Kernel Funktionen ■ Aufruf von Kernel Funktionen import com.sun.jna.Library; import com.sun.jna.Native; /** Simple example of Windows native library declaration and usage. */ public class BeepExample { public interface Kernel32 extends Library { // FREQUENCY is expressed in hertz and ranges from 37 to 32767 // DURATION is expressed in milliseconds Kernel32 INSTANCE = (Kernel32 ) Native.loadLibrary( "kernel32", Kernel32.class); public boolean Beep(int FREQUENCY, int DURATION); public void Sleep(int DURATION); } public static void main(String[] args) { Kernel32.INSTANCE.Beep(300, 500); Kernel32.INSTANCE.Sleep(500); Kernel32.INSTANCE.Beep(698, 500); } } School of Engineering © K. Rege, ZHAW 16 von 17 Bsp: User32 Funktionen ■ Aufruf von User32 Funktionen: Lock Computer import com.sun.jna.*; public class JNASample { public interface User32 extends Library { User32 INSTANCE = (User32) Native.loadLibrary("User32", User32.class); public boolean LockWorkStation(); } public static void main(String args[]) { User32.INSTANCE.LockWorkStation(); } } School of Engineering © K. Rege, ZHAW 17 von 17