Różnice między wybraną wersją a wersją aktualną.
Both sides previous revision Previous revision Next revision | Previous revision Next revision Both sides next revision | ||
jni [2008/04/13 00:43] chappaai |
jni [2008/04/13 00:54] chappaai |
||
---|---|---|---|
Linia 15: | Linia 15: | ||
Przykladowa seria polecen potrzebna do kompilacji przykładu na platformie Windows: | Przykladowa seria polecen potrzebna do kompilacji przykładu na platformie Windows: | ||
+ | <code cpp> | ||
+ | javac .\jni_pkg\Jni.java | ||
+ | javah -jni jni_pkg.Jni | ||
+ | cl -I "c:\Program Files\Microsoft Visual Studio 9.0\VC\include" -I "c:\j2sdk1.4.2_17\include | ||
+ | -I"c:\j2sdk1.4.2_17\include\win32" -LD jni_pkg_Jni.cpp -FeJni_lib.dll'' | ||
+ | </code> | ||
- | ''javac .\jni_pkg\Jni.java | + | ===== Kod Java ===== |
- | javah -jni jni_pkg.Jni | + | Kod zawiera kilka deklaracji przykladowych metod natywnych które sa następnie w nim wykorzystywane. |
- | cl -I "c:\Program Files\Microsoft Visual Studio 9.0\VC\include" -I "c:\j2sdk1.4.2_17\include | + | |
- | -I"c:\j2sdk1.4.2_17\include\win32" -LD jni_pkg_Jni.cpp -FeJni_lib.dll'' | + | |
+ | <code java> | ||
+ | /** | ||
+ | * @author Lukasz Mosdorf G1ISI | ||
+ | */ | ||
+ | /** | ||
+ | * Program ilustrujący Zastosowanie JNI - Java Native Interface. | ||
+ | * Kod wywołuje | ||
+ | */ | ||
+ | package jni_pkg; | ||
+ | public class Jni { | ||
+ | | ||
+ | public int myInt = 10; | ||
+ | public static String mystring = "JNI example"; | ||
+ | public int[] intArray; | ||
+ | private static native void native_call(); // sample native call | ||
+ | private static native String change_string(String arg); | ||
+ | private native int sumArray(int[] arr); | ||
+ | private native int initCppObj(); | ||
+ | private native int deleteCppObj(); | ||
+ | private native int changeCppObjField(int a); | ||
+ | private native void callMe(); | ||
+ | public int cppObjPtr; | ||
+ | private void callback() | ||
+ | { | ||
+ | System.out.println("Java wywolana z cpp"); | ||
+ | } | ||
+ | //Static- wywolywane na saym poczatku | ||
+ | static { | ||
+ | System.loadLibrary("Jni_lib"); | ||
+ | } | ||
+ | |||
+ | public static void main(String[] args) | ||
+ | { | ||
+ | Jni jni = new Jni(); | ||
+ | int arr[] = new int[10]; | ||
+ | |||
+ | //wywołanie metody natywnej, która zmienia podany obiekt String | ||
+ | String input = jni.change_string("String wyslany do metody natywnej"); | ||
+ | System.out.println("Dostano w Javie zmieniony string: "+ input); | ||
+ | | ||
+ | //Zapełnienie tablicy danymi i wywołanie natywnje funkcji sumującej | ||
+ | for (int i = 0; i < 10; i++) { | ||
+ | arr[i] = i; | ||
+ | } | ||
+ | int sum = jni.sumArray(arr); | ||
+ | System.out.println("Suma tablicy zwrocona z metody natywnej = " + sum); | ||
+ | | ||
+ | //inicjalizaja obiektu lol, wskaznik przechowywany w cppObjPtr | ||
+ | jni.initCppObj(); | ||
+ | System.out.println("Obiekt lol zaalokowany: "+ jni.cppObjPtr); | ||
+ | //Wywołanie metody obiektu uprzednio zaalokowanego, | ||
+ | //ktora zmienia wartosc jego pola | ||
+ | jni.changeCppObjField(15); | ||
+ | //wołanie metody która wywołuje motodę obiektu wołającego | ||
+ | jni.callMe(); | ||
+ | jni.deleteCppObj(); | ||
+ | System.out.println("Obiekt lol usuniety, ptr: "+ jni.cppObjPtr); | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | |||
+ | ===== Kod Cpp ===== | ||
+ | |||
+ | Poniżej przedstawiono plik nagłówkowy wygenerowany automatycznie przy uzyciu polecenia javah -jni jni_pkg.Jni. | ||
+ | |||
+ | <code cpp> | ||
+ | /*Lukasz Mosdorf G1ISI | ||
+ | *Plik "jni_pkg_Jni.h" generowany | ||
+ | *przy wywolaniu polecenia javah -jni jni_pkg.Jni | ||
+ | */ | ||
+ | |||
+ | /* DO NOT EDIT THIS FILE - it is machine generated */ | ||
+ | #include <jni.h> | ||
+ | /* Header for class jni_pkg_Jni */ | ||
+ | |||
+ | #ifndef _Included_jni_pkg_Jni | ||
+ | #define _Included_jni_pkg_Jni | ||
+ | #ifdef __cplusplus | ||
+ | extern "C" { | ||
+ | #endif | ||
+ | /* | ||
+ | * Class: jni_pkg_Jni | ||
+ | * Method: native_call | ||
+ | * Signature: ()V | ||
+ | */ | ||
+ | JNIEXPORT void JNICALL Java_jni_1pkg_Jni_native_1call | ||
+ | (JNIEnv *, jclass); | ||
+ | |||
+ | /* | ||
+ | * Class: jni_pkg_Jni | ||
+ | * Method: change_string | ||
+ | * Signature: (Ljava/lang/String;)Ljava/lang/String; | ||
+ | */ | ||
+ | JNIEXPORT jstring JNICALL Java_jni_1pkg_Jni_change_1string | ||
+ | (JNIEnv *, jclass, jstring); | ||
+ | |||
+ | /* | ||
+ | * Class: jni_pkg_Jni | ||
+ | * Method: sumArray | ||
+ | * Signature: ([I)I | ||
+ | */ | ||
+ | JNIEXPORT jint JNICALL Java_jni_1pkg_Jni_sumArray | ||
+ | (JNIEnv *, jobject, jintArray); | ||
+ | |||
+ | /* | ||
+ | * Class: jni_pkg_Jni | ||
+ | * Method: initCppObj | ||
+ | * Signature: ()I | ||
+ | */ | ||
+ | JNIEXPORT jint JNICALL Java_jni_1pkg_Jni_initCppObj | ||
+ | (JNIEnv *, jobject); | ||
+ | |||
+ | /* | ||
+ | * Class: jni_pkg_Jni | ||
+ | * Method: deleteCppObj | ||
+ | * Signature: ()I | ||
+ | */ | ||
+ | JNIEXPORT jint JNICALL Java_jni_1pkg_Jni_deleteCppObj | ||
+ | (JNIEnv *, jobject); | ||
+ | |||
+ | /* | ||
+ | * Class: jni_pkg_Jni | ||
+ | * Method: changeCppObjField | ||
+ | * Signature: (I)I | ||
+ | */ | ||
+ | JNIEXPORT jint JNICALL Java_jni_1pkg_Jni_changeCppObjField | ||
+ | (JNIEnv *, jobject, jint); | ||
+ | |||
+ | /* | ||
+ | * Class: jni_pkg_Jni | ||
+ | * Method: callMe | ||
+ | * Signature: ()V | ||
+ | */ | ||
+ | JNIEXPORT void JNICALL Java_jni_1pkg_Jni_callMe | ||
+ | (JNIEnv *, jobject); | ||
+ | |||
+ | #ifdef __cplusplus | ||
+ | } | ||
+ | #endif | ||
+ | #endif | ||
+ | |||
+ | |||
+ | |||
+ | </code> | ||
+ | |||
+ | Ciała metod natywnych znajdują się w pliku cpp pzedstawionym poniżej: | ||
+ | |||
+ | <code cpp> | ||
+ | /** | ||
+ | *Łukasz Mosdorf G1ISI | ||
+ | *Plik "jni_pkg_Jni.cpp" zawierajacy definicje klasy i kilka metod natywnych | ||
+ | *wolanych z Javy. Załączamy plik "jni_pkg_Jni.h" generowany | ||
+ | *przy wywolaniu polecenia javah -jni jni_pkg.Jni | ||
+ | */ | ||
+ | |||
+ | |||
+ | |||
+ | #include "jni_pkg_Jni.h" | ||
+ | #include <iostream> | ||
+ | #include <jni.h> | ||
+ | using namespace std; | ||
+ | |||
+ | class Lol | ||
+ | { | ||
+ | private: | ||
+ | int i; | ||
+ | public: | ||
+ | void changei(int arg) | ||
+ | { | ||
+ | i=arg; | ||
+ | cout<<"W obiekcie Lol, zmieniono wartosc i na: "<<i<<endl; | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | //Prosta metoda cpp wywolywana z poziomu javy | ||
+ | //Przykład podstawowej składni metody napisanej w C++ (C) i wołanej z Javy | ||
+ | JNIEXPORT void JNICALL Java_jni_1pkg_Jni_native_1call (JNIEnv * env, jclass cls) | ||
+ | { | ||
+ | cout<<"Najprostsza metoda java wywołana !!"<<endl; | ||
+ | } | ||
+ | |||
+ | //Metoda zmieniajaca wartosc Stringa Javy podanego jako argument | ||
+ | JNIEXPORT jstring JNICALL Java_jni_1pkg_Jni_change_1string (JNIEnv * env, jclass jCl, jstring inStr) | ||
+ | { | ||
+ | char buf[128]; | ||
+ | const char *str; | ||
+ | |||
+ | /* Przeksztalcamy String javowy na ciąg bajtów*/ | ||
+ | str = env->GetStringUTFChars(inStr, NULL); | ||
+ | if (str == NULL) { | ||
+ | return NULL; // OutOfMemoryError juz rzucony | ||
+ | } | ||
+ | |||
+ | printf("W metodzie cpp String: %s \n", str); | ||
+ | //Zwalniamy obiekt aby mogl sie nim zajac juz Garbage Collector | ||
+ | env->ReleaseStringUTFChars(inStr, str); | ||
+ | //Zakladamy ze uzytkownik nie wpisze wiecej niz 127 znakow... | ||
+ | cout<<"Wprowadz nowego Stringa"<<endl; | ||
+ | scanf("%s", buf); | ||
+ | | ||
+ | return env->NewStringUTF(buf); | ||
+ | } | ||
+ | |||
+ | //Prosta metoda sumująca tablice intów 10-elementową podana z poziomy Javy jako argument | ||
+ | JNIEXPORT jint JNICALL Java_jni_1pkg_Jni_sumArray(JNIEnv *env, jobject obj, jintArray arr) | ||
+ | { | ||
+ | jint buf[10]; | ||
+ | jint i, sum = 0; | ||
+ | //pobieramy tablice | ||
+ | env->GetIntArrayRegion(arr, 0, 10, buf); | ||
+ | //sumujemy | ||
+ | for (i = 0; i < 10; i++) { | ||
+ | sum += buf[i]; | ||
+ | } | ||
+ | return sum; | ||
+ | } | ||
+ | |||
+ | /*Metoda inicjalizująca obiekt lol, i zapisujaca miejsce jego alokacji w pamieci | ||
+ | * w polu cppObjPtr obiektu który tę metodę wywolal. | ||
+ | */ | ||
+ | JNIEXPORT jint JNICALL Java_jni_1pkg_Jni_initCppObj (JNIEnv *env , jobject jObj) | ||
+ | { | ||
+ | jfieldID fid; //magazynujemy id pola klasy javowej | ||
+ | |||
+ | /* pobieramy referencje na klase obiektu jObj */ | ||
+ | jclass cls = env->GetObjectClass(jObj); | ||
+ | |||
+ | /* Pobieramy ID pola klasy*/ | ||
+ | fid = env->GetFieldID(cls, "cppObjPtr", "I"); | ||
+ | if (fid == NULL) { | ||
+ | return (jint)1; /* nie udalo sie zdobyc id pola */ | ||
+ | } | ||
+ | |||
+ | |||
+ | jint ptr = env->GetIntField(jObj, fid); | ||
+ | cout<<"poczatkowa wartosc wskaznika to: "<<(int)ptr<<endl; | ||
+ | |||
+ | Lol* lol = new Lol(); | ||
+ | if (!lol) | ||
+ | { | ||
+ | return (jint)1; //nie udalo sie zaalokowac | ||
+ | } | ||
+ | //zwracamy wskaznik zaalokowanego obiektu | ||
+ | env->SetIntField(jObj, fid, (jint)lol); | ||
+ | |||
+ | return (jint)0; | ||
+ | } | ||
+ | |||
+ | |||
+ | //Prosta metoda wywołująca metodę obiektu lol (uprzednio zaalokowanego). Metoda zmienia wartość pola obiektu | ||
+ | JNIEXPORT jint JNICALL Java_jni_1pkg_Jni_changeCppObjField (JNIEnv* env, jobject jObj, jint k) | ||
+ | { | ||
+ | /*pzrechowujemy id pola klasy javowej*/ | ||
+ | jfieldID fid; | ||
+ | |||
+ | /* pobieramy referencje na klase obiektu jObj */ | ||
+ | jclass cls = env->GetObjectClass(jObj); | ||
+ | |||
+ | /* pobieramy field ID*/ | ||
+ | fid = env->GetFieldID(cls, "cppObjPtr", "I"); | ||
+ | if (fid == NULL) { | ||
+ | return (jint)1; /* nie udalo sie zdobyc id pola */ | ||
+ | } | ||
+ | /*Pobieramy wskaznik na nasz obiekt (zapisany w polu klasy wywolujacej metode)*/ | ||
+ | jint ptr = env->GetIntField(jObj, fid); | ||
+ | |||
+ | Lol* lol = (Lol*)ptr; | ||
+ | /*wywolujemy metodę obiektu lol*/ | ||
+ | lol->changei(k); | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | //Metoda realizujaca tzw CALLBACK, czyli wywołanie metody nalezacej do obiektu javy | ||
+ | JNIEXPORT void JNICALL Java_jni_1pkg_Jni_callMe (JNIEnv * env, jobject jObj) | ||
+ | { | ||
+ | jclass cls = env->GetObjectClass(jObj); | ||
+ | //pobieramy ID metody | ||
+ | jmethodID mid = env->GetMethodID(cls, "callback", "()V"); | ||
+ | if (mid == NULL) { | ||
+ | return; // nie znaleziono metody | ||
+ | } | ||
+ | cout<<"W C++, przed Callback'iem"<<endl; | ||
+ | env->CallVoidMethod(jObj, mid); | ||
+ | cout<<"W C++, po Callbacku"<<endl; | ||
+ | } | ||
+ | |||
+ | JNIEXPORT jint JNICALL Java_jni_1pkg_Jni_deleteCppObj (JNIEnv * env , jobject jObj) | ||
+ | { | ||
+ | jfieldID fid; //magazynujemy id pola klasy javowej | ||
+ | |||
+ | /* pobieramy referencje na klase obiektu jObj */ | ||
+ | jclass cls = env->GetObjectClass(jObj); | ||
+ | |||
+ | /* Pobieramy ID pola klasy*/ | ||
+ | fid = env->GetFieldID(cls, "cppObjPtr", "I"); | ||
+ | if (fid == NULL) { | ||
+ | return (jint)1; /* nie udalo sie zdobyc id pola */ | ||
+ | } | ||
+ | |||
+ | |||
+ | jint ptr = env->GetIntField(jObj, fid); | ||
+ | cout<<"poczatkowa wartosc wskaznika na obiekt ktory usuwamy to: "<<(int)ptr<<endl; | ||
+ | |||
+ | Lol* lol = reinterpret_cast<Lol*>(ptr); | ||
+ | |||
+ | delete lol; | ||
+ | //zwracamy wskaznik zaalokowanego obiektu | ||
+ | env->SetIntField(jObj, fid, (jint)0); | ||
+ | |||
+ | return (jint)0; | ||
+ | |||
+ | |||
+ | } | ||
+ | </code> | ||