JNI

Status
Nicht offen für weitere Antworten.
D

davidek

Gast
Hallo!

Ich bin JAVA-Anfänger und will endlich ein tolles Programm schreiben (die Übungsaufgaben aus meinem Java-Buch gehen mir auf die Nerven...).


Für mein Vorhaben brauche ich Zugriff auf Methoden einer .dll-Datei.
Dazu hab ich mich über etwas namens JNI schon schlaugemacht.

Brauche ich für JNI den Sourcecode einer .dll (den hab ich nämlich nicht) oder genügt die fertige DLL (hoffentlich) ?



Ich bin zwar Programmieranfänger und kann Java noch nicht wirklich, aber ich will das trotzdem machen, auch wenn es vllt. noch ein bischen zu schwierig ist.




Danke schonmal für Posts
MfG
davidek
 
G

Gast

Gast
den source brauchst du nicht, aber du kannst nicht einfach irgendwelche funktionen in einer dll aufrufen

du müsstest dir eine wrapper dll schreiben die auf die dll zugreift
 
D

davidek

Gast
Danke erstmal für die Antworten!


Die Javainsel habe ich mir schon vorher angesehen und ich habe sie mir jetzt nochmal angesehen und ich hab nicht wirklich viel verstanden :( .

Das sieht nach einer Menge Arbeit aus...

Ich muss also das Java-Programm schreiben und darin muss System.loadLibrary(); und die Methode, die man verwenden will, mit dem Modifizierer native aufgeführt sein.

Danach compilieren - ist klar.

Bis dahin hab ich es einigermaßen verstanden.

Eine Header-Datei zu erzeugen habe ich dann auch noch irgendwie hingekriegt.


Was macht man in den folgenden Schritten?

24.2.4 Implementierung der Methode in C
Ich dachte die Methode gibt es schon. Genau deswegen will ich sie ja in Java einbinden.

24.2.5 Übersetzen der C-Programme und Erzeugen der dynamischen Bibliothek
Auch eine .dll hab ich ja schon.

24.2.6 Setzen der Umgebungsvariable
Das entfällt doch, wenn ich die .dll in den bin-Ordner von der jre reintue, oder?
Also würde die .dll dann z.B. (standardmäßig) hier drin C:\Programme\Java\jre1.5.0_10\bin gut liegen, oder?
Oder kann sie auch in dem Verzeichnis liegen, wo die class-Datei ist?

Entfallen die letzten drei Schritte also, wenn ich die native Seite schon habe?
Oder muss ich hier jetzt den Wrapper schreiben? Heißt das, dass ich jetzt noch C++ schreiben muss?


Ich glaube ich bin noch nicht so weit.
Wenn das sich hier jetzt doch als zu kompliziert für mich herausstellt, werde ich mir die Basics nochmal richtig verinnerlichen und andere Programme schreiben.

Ich würde mich aber freuen, wenn das irgendwie lösbar wäre.


MfG
davidek
 

Campino

Top Contributor
Also, damit du eine Methode aus einer dll in Java nutzen kannst, muss diese Methode im C-Code als JNICALL-Methode definiert sein. Wenn das nicht der Fall ist, gibt es keine Möglichkeit. Du musst eine dll schreiben, die JNICALL-Methoden bereitstellt, die dann die Original-Methoden aufrufen. Bevor ich das mache, würde ich a) viel einfach nur mit Java üben und b) mal suchen, ob es eventuell bereits einen Port der Bibliotheke für Java gibt.
Was brauchst du denn? Eventuell kennt hier ja jemand eine Java-Lib, die das leistet.
 
D

davidek

Gast
Danke nochmal!

Also wenn jemand eine entsprechende Funktion haben würde, wäre das Klasse.
Ich glaube aber eher nicht, dass es so eine Java-Lib gibt, da das eine eher ausergewöhnliche Anwendung ist.

Wir benutzen in der Schule einen graphikfähingen Taschenrechner von Casio. Diesen kann man mit einem Kabel auch mit dem PC verbinden um Casio-Basic Programme (mit denen hab ich Programmieren gelernt) hin- und herschicken.

Jetzt ist es auch einer Gruppe gelungen, einen offenen Datenaustausch zwischen den zweien zu entwerfen.

Ich wollte nun ein Programm schreiben, um auf dem Taschenrechner (kabellos) im Internet zu surfen :D !

Über den ganzen Rest habe ich mir schon Gedanken gemacht und habe auch schon einen groben Entwurf, aber der wird hier nicht gebraucht...

Es gibt also im Internet diese frei verfügbare DLL. Hier der Link zu der Seite: users.pandora.be/gp/casio/

Wenn es jemanden interessiert, kann er sich die ZIP-Datei ja mal runterladen. Da drin ist auch eine Beispielanwendung und eine sehr gute Hilfedatei enthalten, die die Methoden erklärt.

Da steht auch, dass die .dll sehr einfach zusammen mit C++ oder VisualBasic verwendet werden kann (die unterstützen ja auch die DLLs).

Da ich nun aber Java-Programmieren lerne, will ich das in Java machen auch wenn diese Einbindung etwas schwieriger ist.

Ich denke dafür ist vielleicht die andere Seite, das auslesen von Internetseiten, auch einfacher, da es dafür ja auch schon Parser- und Reader-Klassen in der Java-Standardbibliothek gibt.
 

thE_29

Top Contributor
Die Einstiegspunkte einer DLL sind anders!

Also ein Dll die für Java gemacht ist, kann nicht von C/C++ (geht zwar schon, aber schwerer) aufgerufen werden!

Und umgekehrt gehts schon gar nicht!

Da String (wenn man überhaupt Stirng nutzt) in C/C++ anders ist. Dort wird eigentlich sowieos mit char Arrays gearbeitet!

Dann sind die ganzen Wertebereiche ja anders. int, float, etc sind in C/C++ kleiner als in Java.

Dann gibts noch Probleme wenn du Java Objekte nutzen willst, etc..


Dh, du musst ne DLL schreiben die intern entweder WinApi Befehle oder andere Dlls aufruft!

Von Java aus, kann man aber direkt nie auf zB kernel.dll zugreifen, da Java die Einstigspunkte nicht findet. Bzw net aufrufen kann.


Desweiteren hier noch ein paar Links: http://www.java-forum.org/de/viewtopic.php?t=37816

http://www.java-forum.org/de/viewtopic.php?p=230887#230887 ein Post weiter unten erkläre ich was welcher Befehl macht!

http://www.java-forum.org/de/viewtopic.php?t=13981 (hier ist viel C/C++ Code und Java Code)
http://www.java-forum.org/de/viewtopic.php?t=12637
 
D

davidek

Gast
Hallo!

Dh, du musst ne DLL schreiben die intern entweder WinApi Befehle oder andere Dlls aufruft!
In der Spezifikation steht auch irgendwas von WinApi... Allerdings habe ich davon keine Ahnung. Auch so eine DLL schreiben kann ich nicht.

Ist das viel Arbeit? Hat jemand lust das (eventuell gegen ne kleine Vergütung) zu machen, also die Dinge so einrichten, damit ich die Methoden und die DLL in Java einfach benutzen kann? (Das ist doch möglich das so einzurichten, oder?)

MfG
davidek
 
D

davidek

Gast
Hallo, da bin ich wieder! :)

Ich habe mir die ganze Sachen jetzt nochmal sehr intensiv zu Gemüte geführt und mich jetzt doch dazu entschieden, dass - wenn auch in Unkenntis der Materie - durchzuziehen.

Dieser Post wird zielich lang, ich hab' ihn dafür aber auch schön formatiert und so.
Es wäre super, wenn ihr mich berichtigen könntet!


Ich gehe also wie folgt vor:


Hier erst einmal die Referenzen, die in der Hilfe-Datei dabei waren. Da waren die einzelnen Parameter auch noch genauer erklärt. Lasst euch bitte von der umfangreichen Liste nicht stören.

Referenzen zu CasioIO.dll
  • Code:
    int WINAPI CasioIO_RespondToReceive(
      int handle, 
      unsigned char rows,
      unsigned char columns,
      double * values,
    );
  • Code:
    int WINAPI CasioIO_AfterSend(
      int handle, 
      unsigned char * datatype, 
      unsigned char * name, 
      unsigned char * rows,
      unsigned char * columns,
      double * values,
    );
  • Code:
    int WINAPI CasioIO_AfterReceive(
      int handle, 
      unsigned char * datatype, 
      unsigned char * name, 
    );
  • Code:
    int WINAPI CasioIO_Uninit();
  • Code:
    int WINAPI CasioIO_Close(
      int handle, 
    );
  • Code:
    int WINAPI CasioIO_Init(
      unsigned char comport,
      int iotype
    );
  • Code:
    int WINAPI CasioIO_Open(
      int authorID, 
      int productID, 
      CASIOIO_EVENT sendproc, 
      CASIOIO_EVENT receiveproc, 
    );

1. Schritt: Das Java-Programm schreiben

Als erstes definiere ich die native-Methoden und lasse die Library, also die "Wrapper-DLL", die später auf die richtige DLL zugreifen wird, laden. Der Einfachkeit halber nenne ich die Methoden genau so, wie sie im Original heißen.
Das sieht dann so aus:

jni_test.java
Code:
public class jni_test {

  static {
    System.loadLibrary("jni_test");
  }

  public native static int RespondToReceive(int handle,
                                            short rows,
                                            short columns,
                                            double values[]
                                            );

  public native static int AfterSend(int handle,
                                     short datatype[],
                                     short name[],
                                     short rows[],
                                     short columns[],
                                     double values[]
                                     );

  public native static int AfterSend(int handle,
                                     short datatype[],
                                     short name[]
                                     );

  public native static int Uninit();

  public native static int Close(int handle);

  public native static int Init(short comport,
                                int iotype
                                );

  public native static int Open(int authorID,
                                int productID
                                //CASIOIO_EVENT sendproc,
                                //CASIOIO_EVENT receiveproc
                               );

  public static void main(String[] args) {
    //Hier kann ich jetzt die Methoden unter den oben definierten Namen verwenden,
    //wie ich sie brauche...
  }

}

Für die "unsigned char"s aus der DLL benutzte ich hier den Datentyp short, weil dieser "unsigned char" komplett erfasst.
In diesem ersten Schritt stellen sich mir schon die ersten Fragen:
  1. In der DLL werden ja Felder gebraucht (die Sachen mit den Sternchen). Habe ich das hier jetzt in Java, so wie ich das gemacht habe, korrekt?
  2. In Zeile 36 und 37 habe ich in Kommentaren das hingeschrieben, wovon ich nicht weiß wie ich das hier in Java einbinden muss. Wie muss ich das angehen?


2. Schritt: Header-Datei erzeugen

Jetzt erzeuge ich per Konsolenbefehl "javah jni_test" aus der Java-Class-Datei eine Header-Datei, die ich später in der zwischengeschalteten DLL benutzen werde.

jni_test.h
Code:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class jni_test */

#ifndef _Included_jni_test
#define _Included_jni_test
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     jni_test
 * Method:    RespondToReceive
 * Signature: (ISS[D)I
 */
JNIEXPORT jint JNICALL Java_jni_1test_RespondToReceive
  (JNIEnv *, jclass, jint, jshort, jshort, jdoubleArray);

/*
 * Class:     jni_test
 * Method:    AfterSend
 * Signature: (I[S[S[S[S[D)I
 */
JNIEXPORT jint JNICALL Java_jni_1test_AfterSend__I_3S_3S_3S_3S_3D
  (JNIEnv *, jclass, jint, jshortArray, jshortArray, jshortArray, jshortArray, jdoubleArray);

/*
 * Class:     jni_test
 * Method:    AfterSend
 * Signature: (I[S[S)I
 */
JNIEXPORT jint JNICALL Java_jni_1test_AfterSend__I_3S_3S
  (JNIEnv *, jclass, jint, jshortArray, jshortArray);

/*
 * Class:     jni_test
 * Method:    Uninit
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_jni_1test_Uninit
  (JNIEnv *, jclass);

/*
 * Class:     jni_test
 * Method:    Close
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_jni_1test_Close
  (JNIEnv *, jclass, jint);

/*
 * Class:     jni_test
 * Method:    Init
 * Signature: (SI)I
 */
JNIEXPORT jint JNICALL Java_jni_1test_Init
  (JNIEnv *, jclass, jshort, jint);

/*
 * Class:     jni_test
 * Method:    Open
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_jni_1test_Open
  (JNIEnv *, jclass, jint, jint);

#ifdef __cplusplus
}
#endif
#endif


3. Schritt: Die "zwischengeschaltete DLL"

So, jetzt kommt der schwierigste Schritt. Jetzt muss ich eine DLL in C++ schreiben, was ich nicht kann. Als Grundlage habe ich das von thE_29 gepostete Beispiel aus dem Thread JNI-functions genommen. Nennt man sowas eine Wrapper-DLL?
Ich habe mir hier was zusammengebastelt.

jni_test.cpp
Code:
#include <iostream>
#include <winodws.h> //Hab gelesen, dass ich das brauche, damit WINAPI funktioniert.
#include <jni>
#include <"jni_test.h">
//Hier oben muss ich noch die CasioIO.dll reinbekommen. Oder doch nicht?

JNIEXPORT jint JNICALL Java_jni_1test_RespondToReceive
  (JNIEnv *env, jclass cl, jint handle, jshort rows, jshort columns, jdoubleArray values)
{
   int WINAPI CasioIO_RespondToReceive(handle,rows,columns,values); //Wie muss das hier mit values sein?
}

Diese .cpp-Datei muss ich später zu einer .dll-Datei compilieren, damit ich sie in Java mit "System.loadLibrary("jni_test");" laden kann.
Ich habe erstmal nur die erste Methode als Beispiel eingebunden. Wenn ich weiß ob das hier richtig ist, kann ich auch die anderen fertig machen. Da gibts ja bei der Open-Methode noch das Problem mit dem "EVENT"...

  1. Ist das soweit richtig?
  2. Wie muss ich das "jdoubleArray values" behandeln?
  3. Habe ich alles richtig "#include"ed?
    Oder muss ich die CasioIO.dll noch anders einbinden? (Bei der CasioIO.dll war nämlich auch noch so eine extra .h-Datei dabei.)
  4. Sollte das alles (zusammen mit dem Java) jetzt so laufen?




Ich wäre sehr dankbar wenn mir jemand meine Fragen beantworten könnte und sich vielleicht angucken könnte, ob das soweit richtig ist! Danke für jeden Post!


Mit freundlichen Grüßen
davidek
 
D

davidek

Gast
Hi nochmal, ich hab schon selbst die ersten Fehler gefunden:

Im Cpp muss zwischen den { } natürlich nicht int sondern return stehen.

<jni.h> muss ich nich includen weil das das andere header schon macht.

es uss heißen windows.h.


Achja und ich hab zusätzlich zu der headerdatei für die dll noch eine .lib datei.

hilft mir das weiter?
 
Status
Nicht offen für weitere Antworten.

Neue Themen


Oben