Różnice między wybraną wersją a wersją aktualną.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
|
jni [2008/04/13 00:49] chappaai |
jni [2008/04/16 23:55] (aktualna) chappaai |
||
|---|---|---|---|
| Linia 1: | Linia 1: | ||
| ====== Java JNI i C++ ====== | ====== Java JNI i C++ ====== | ||
| + | Autor : Łukasz Mosdorf G1ISI | ||
| + | --- | ||
| + | //[[L.Mosdorf[eeeet]stud.elka.pw.edu.pl|Łukasz Mosdorf]] 2008/04/13 01:05// | ||
| - | Ta strona zawiera prosty przykład zastosowania Java Native Interface. Technologia ta pozwala łączyć kod Javy z kodem pisanym pisanym w językach specyficznych dla danej platformy. Potrzeba łączenia Javy z C++ zachodzi np gdy | + | Ta strona zawiera prosty przykład zastosowania Java Native Interface. Technologia ta pozwala łączyć kod Javy z kodem pisanym w językach specyficznych dla danej platformy. Potrzeba łączenia Javy z C++ zachodzi np gdy |
| * maszyna wirtualna nie jest w stanie zapewnić nam wystarczającej szybkości obliczeń | * maszyna wirtualna nie jest w stanie zapewnić nam wystarczającej szybkości obliczeń | ||
| * Chcemy połączyć aplikację javy z juz istniejącym kawałkiem oprogramowania napisanego w C/C++ | * Chcemy połączyć aplikację javy z juz istniejącym kawałkiem oprogramowania napisanego w C/C++ | ||
| Linia 8: | Linia 11: | ||
| * Utworzyć klasę (Javaclass.java), która deklaruje metodę natywną | * Utworzyć klasę (Javaclass.java), która deklaruje metodę natywną | ||
| * skompilowac tę klasę za pomocą polecenia 'javac' i w ten sposób otrzymać Javaclass.class | * skompilowac tę klasę za pomocą polecenia 'javac' i w ten sposób otrzymać Javaclass.class | ||
| - | * uzyc javah -jni aby otrzymac plik naglowkowy, w oparciu o ktory napiszemy kod w C++ | + | * uzyc javah -jni aby otrzymac plik naglowkowy, w oparciu o który napiszemy kod w C++ |
| - | * napisac kod w C++ | + | * napisać kod w C++ |
| * skompilować kod do postaci biblioteki (*.dll pod Windows, *.so pod Solarisem) | * skompilować kod do postaci biblioteki (*.dll pod Windows, *.so pod Solarisem) | ||
| * uruchomić program Javaclass | * uruchomić program Javaclass | ||
| - | Przykladowa seria polecen potrzebna do kompilacji przykładu na platformie Windows: | + | Przykładowa seria poleceń potrzebna do kompilacji przykładu na platformie Windows: |
| <code cpp> | <code cpp> | ||
| Linia 21: | Linia 24: | ||
| -I"c:\j2sdk1.4.2_17\include\win32" -LD jni_pkg_Jni.cpp -FeJni_lib.dll'' | -I"c:\j2sdk1.4.2_17\include\win32" -LD jni_pkg_Jni.cpp -FeJni_lib.dll'' | ||
| </code> | </code> | ||
| + | |||
| + | Jeżeli powyższe polecenia nie dzialaja, należy dodać odpowienie ścieżki do zmiennej srodowiska Windows - PATH. | ||
| + | Polecenie cl polecam uruchamiac z konsoli Visual Studio - nie mamy wtedy problemów z wskazywaniem lokalizacji dodatkowych plików nagłówkowych i bibliotek. | ||
| ===== Kod Java ===== | ===== Kod Java ===== | ||
| Linia 31: | Linia 37: | ||
| /** | /** | ||
| * Program ilustrujący Zastosowanie JNI - Java Native Interface. | * Program ilustrujący Zastosowanie JNI - Java Native Interface. | ||
| - | * Kod wywołuje | + | * Kod wywołuje kilka natywnych metod napisanych w cpp |
| */ | */ | ||
| package jni_pkg; | package jni_pkg; | ||
| Linia 86: | Linia 92: | ||
| } | } | ||
| </code> | </code> | ||
| + | |||
| Linia 172: | Linia 179: | ||
| </code> | </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 c++ wywołana z javy !!"<<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> | ||