Micha: DLL mit JNA nutzen; Problem mit Referenzvariablen

Hallo,

ich habe ein kleinen Sensor, der Umgebungsparameter (Temperatur, Druck, usw.) ermitteln kann. Um die Werte auszulesen, habe ich eine DLL dazubekommen. Diese habe ich über JNA eingebunden, so wie es auch auf der Seite im Beispiel zu sehen ist. Diese DLL hat vier Funktionen: OpenComport, CloseComport, GetVersion, GetMeasuredValues. Alle Funktionen geben einen Integer zurück, dabei steht 0 (Null) für "hat funktioniert" und ungleich Null für einen Fehler (außer bei der Version, dort bekomme ich diese zurück als Integer).

Die ersten drei genannten Funktionen funktionieren problemlos. Ich kann die Version abfragen. Ich kann den port öffnen und auch schließen. Probleme macht mir nun das ermitteln der Sensorwerte. Ich habe zwei kleine Beispielcodes in C++ und Pascal beiliegen. Beide arbeiten augenschainlich mit Referenzvariablen:

Das C++ Beispiel:

  
UCHAR out0, out1, out2, out3, out4, out5, out6;  
m_GetValue= (*funcMeasuredValues)(  
	0,  
	6, 3, 0, 0xFF, 0xFF, 0, 0,  
	&out0, &out1, &out2, &out3, &out4, &out5, &out6  
);

bzw. der Pascal-Code

  
var  
  res0: Integer;  
  out0, out1, out2, out3, out4, out5, out6: Byte;  
begin  
  
  res0:= GetMeasuredValues(  
    0,  
    6, 3, 0, $FF, $FF, 0, 0,  
    @out0, @out1, @out2, @out3, @out4, @out5, @out6  
  );  
  
...  

gibt es eine Möglichkeit, solche Aufrufe auch mit JAVA zu realisieren?

mein bisheriger Code sieht wie folgt aus:

Eine Schnittstelle, die die DLL Funktionen besitzt.

  
import com.sun.jna.*;  
import com.sun.jna.win32.StdCallLibrary;  
import com.sun.jna.Library;  
import com.sun.jna.Native;  
import com.sun.jna.Platform;  
                                 //StdCallLibrary  
public interface SENSOR145 extends Library {  
        SENSOR145 INSTANCE = (SENSOR145) Native.loadLibrary("SENSOR145_1", SENSOR145.class);  
        // Weitere Funktionen  
  
        int GetMeasuredValues(int portId, int i0, int i1, int i2, int i3, int i4, int i5, int i6, int o0, int o1, int o2, int o3, int o4, int o5, int o6);  
  
}

und der Aufruf in der Main-Methode:

  
SENSOR145 lib = SENSOR145.INSTANCE;  
int i = lib.GetVersion();  
int j = lib.OpenComport(0, "COM4");  
int t = lib.GetMeasuredValues(0, 6, 3, 0, 0xFF, 0xFF, 0, 0,  0, 0, 0, 0, 0, 0, 0);  
// ----------------------------------------------------------^^^^^^^^^^^^^^^^^^^ hier müssten die Referenzvariablen hin  
int k = lib.CloseComport(0);  

Kann mir da einer einen Tip von Euch geben, wie ich die Funktion der DLL in JAVA nutzbar machen kann? Im Moment bricht der Code mit mit einer Fehlermeldung ab, da der Aufruf der Funktion GetMeasuredValues falsch ist.

Mit freundlichem Gruß
Micha

--
simple JavaScript Spiele: Snake, MineSweeper, Sudoku oder Tetris
  1. Hallo Micha,

    An der Stelle müssen ja praktisch Pointer übergeben werden, auf den Speicherplatz/die Variable, wo der Wert gespeichert werden soll. Für die Basistypen gibt es da fertige Klassen, die das abwickeln. In diesem Fall wäre das IntByReference.

    Du musst also den Rückgabeparameter entsprechend deklarieren:
    void getValue(IntByReference ref);

    Und kannst dann die Funktion so aufrufen:
    IntByReference ref = new IntByReference();
    foo.getValue(ref);
    int i = ref.getValue();

    Grüße

    Daniel

    1. Hallo Daniel Thoma,

      der Tip war Gold wert ;-) Gelöst habe ich es aber (scheinbar) etwas anders:

        
              int GetMeasuredValues(int portId,  
                       int in0, int in1, int in2, int in3, int in4, int in5, int in6,  
                       ByReference out0,  
                       ByReference out1, ByReference out2,  
                       ByReference out3, ByReference out4,  
                       ByReference out5, ByReference out6  
              );  
        
      der Rückgabewert ist weiterhin int, da dieser angibt, ob es einen Fehler beim ermitteln der Werte gab. Die "out" Variablen habe ich, wie Du gesagt hattest, mit ByReference deklariert in der Schnittstelle. Der Aufruf erfolgt nun via:  
        
      [code lang=java]int returnCode = lib.GetMeasuredValues(0, 6, 3, 0, 0xFF, 0xFF, 0, 0, iref0, iref1, iref2, iref3, iref4, iref5, iref6); 
      

      wobei die irefX IntByReference-Typen sind. Auf diese irefX kann ich nachdem Aufruf mit getValue() den Wert holen, so wie Du auch geschrieben hattest.

      Eine Frage hätte ich noch. Die Pointer-Klasse ist dann dazu da, (eigene) Objekte aus einer DLL-Funktion zu erhalten, wenn diese keine Primitive zurück liefert. Ist das korrekt?

      Ansonsten nochmal vielen Dank für Deine schnelle Hilfe!

      Mit freundlichem Gruß
      Micha

      --
      simple JavaScript Spiele: Snake, MineSweeper, Sudoku oder Tetris
      1. Hallo Micha,

        Du kannst die Parameter auch als ByReference deklarieren, allerdings verlierst Du dann die Typsicherheit. Da kann ja jemand Referenzen auf beliebige andere Typen übergeben.

        Eine Frage hätte ich noch. Die Pointer-Klasse ist dann dazu da, (eigene) Objekte aus einer DLL-Funktion zu erhalten, wenn diese keine Primitive zurück liefert. Ist das korrekt?

        Ja, das ist korrekt. Wie in C auch muss man dann auch auspassen, wann und wo man Speicher freigeben muss.

        Grüße

        Daniel

        1. Hallo Daniel Thoma,

          Du kannst die Parameter auch als ByReference deklarieren, allerdings verlierst Du dann die Typsicherheit. Da kann ja jemand Referenzen auf beliebige andere Typen übergeben.

          Du würdest hier also direkt auf den IntByReference setzen, um Mißverständnisse vorzubeugen. Komisch finde ich bei den Beispielcodes (ohne das ich C und PASCAL kann), dass einmal Byte und einmal UCHAR genommen wurde.

          Ja, das ist korrekt. Wie in C auch muss man dann auch auspassen, wann und wo man Speicher freigeben muss.

          Ah, ja, vielen Dank. Vielleicht benötige ich das ja auch mal. Bei dieser DLL reichen die XYZByReference Typen bereits aus.

          Mit freundlichem Gruß
          Micha

          --
          simple JavaScript Spiele: Snake, MineSweeper, Sudoku oder Tetris