Funktionsaufruf einer C++-Funktion mittels JNA

raumichi

Grünschnabel
Hallo,

ich hoffe ich bin hier richtig und mir kann jemand helfen.

Ich will einen Kartenleser ansprechen (Krankenversichertenkarte). Bei dem Kartenleser ist eine API dabei, die drei Funktionen zur Verfügung stellt:

CT_init, CT_data und CT_close.

Die init Funktion und die Close-Funktion laufen problemlos, nur das Aufrufen der CT_data Funktion will mir nicht gelingen.

Definiert sind die Funktionen in der API wie folgt:

CT_init ( unsigned short ctn , unsigned short ctn)
CT_close ( unsigned short ctn)
CT_data (unsigned short ctn, unsigned char *dad, unsigned char *sad,
unsigned short lenc, unsigned char *command, unsigned short* lenr, unsigned char *response)

Ich habe die DLL mittels JNA eingebunden und folgende Klasse definiert:
Code:
package gbws.bw_tm.control;

import java.nio.ByteBuffer;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.ptr.ShortByReference;


public class CtTMKartenleser {

   public interface IKVKarteLibrary extends Library {
      IKVKarteLibrary INSTANCE = (IKVKarteLibrary)
         Native.loadLibrary("ctdeutin" , IKVKarteLibrary.class);
    
      int CT_init(char shA, char shB);
      int CT_close(char shA);
      int CT_data(char shCtn, ByteBuffer dad, ByteBuffer sad, char shLenc, ByteBuffer sCommand, ShortByReference lenr, ByteBuffer sResponse);
   }

}

So und nun will ich die Funktionen aufrufen.

CT_init und CT_close funktioniert, nur leider CT_data nicht.

Code:
final char chCtn = 0x00000001; 
         final char chPn  = 0x00000001;
            // Instanz des Kartenlesers erzeugen            
         IKVKarteLibrary lib  = IKVKarteLibrary.INSTANCE;
         // erster Schritt Kartenleser initialisieren
         int iInit = lib.CT_init(chCtn, chPn);

         // Datenfelder für den Zugriff auf CT_DATA #
         byte[] btDad = {1};
         byte[] btSad = {2};
         char chLenc = 0X00000005;     
         char chLenr = 256;
         short shLenr = 256;
         // Befehl
         byte[] resetICC = {0x20, 0x12, 0x01, 0x01, 0x00,0x00,  0x00, 0x00, 0x00, 0x00 };
        
        // Rückgabebereich         
         byte[] hsp = new byte[11];
         for (int i = 0; i < 10; i++) {
            hsp[i] = resetICC[i];
         }  
         byte[] rsp = new byte[501];
         for (int i = 0; i < rsp.length; i++) {
            rsp[i] = 0;
         }         
         int iErg = 0; 
               
         
         ByteBuffer bbin  = ByteBuffer.wrap(hsp);
         ByteBuffer bbout = ByteBuffer.wrap(rsp);
         ByteBuffer bbDad = ByteBuffer.wrap(btDad);
         ByteBuffer bbSad = ByteBuffer.wrap(btSad); 
         ShortByReference p1 = new ShortByReference(); 
         p1.setValue((short)chLenr); 


         // Nun sind 4 Befehle an das Kartenterminal abzusetzen:
         iErg = lib.CT_data(chCtn , bbDad, bbSad, chLenc, bbin, p1, bbout);

Als Rückgabewert sollte idealerweise 0 zurückkomme . ich bekomme allerdings: "202731264"

Aus einem C++Programm, aus dem der Zugrif funktioniert, schaut das so aus:

Code:
int ctn=1;
unsigned char ct_dad=1;
unsigned char sad=2;
unsigned short lenr=256;
unsigned char commandcode[11];
unsigned char responsearray[501];
commandcode[0]=0x20;
commandcode[1]=0x12;
commandcode[2]=0x01;
commandcode[3]=0x01;
commandcode[4]=0x00;
commandcode[5]=0x00;
commandcode[6]=0x00;
commandcode[7]=0x00;
commandcode[8]=0x00;
commandcode[9]=0x00;
commandcode[10]=0x00;			
			
// Request ICC zum CT schicken
rc=CT_data(ctn,&ct_dad,&sad,5,&commandcode[0],&lenr,&responsearray[0]);


Kann mir da jemand helfen, wo mein Denkfehler ist? Leider bin ich noch neu in JAVA und C++ kann ich kaum.

Danke
 
Howdie.

Prinzipiell zu JNA:
Ich habe inzwischen einige Projekte damit durchgeführt, und solche Zahlen-Geschichten haben meistens die gleiche Ursache - Unsigned C-Variablen in signed Java-Variablen zu speichern. Vielleicht versuchst du mal den Rückgabewert im nächstgrößeren Datentyp zu speichern (in dem Fall Long), damit das Vorzeichen-Bit (das erste Bit der Variable) nicht als gesetzt interpretiert wird. Wobei es natürlich seltsam ist, dass ausgerechnet 202731264 als Ergebnis zurückkommt....

Falls was bei der Übergabe falsch läuft:
Versuch doch mal statt dem ByteBuffer den ByteByReference-Datentyp zu verwenden. Warum nimmst du überhaupt einen Buffer? Hast du schon mal versucht, direkt das Byte-Array zu verwenden? Das mache ich meistens bei Char-Pointern. Ich muss gestehen, mit dem ByteBuffer hab ich das noch nie ausprobiert...
Für Mappings auf 16Bit C-Datentypen habe ich auch immer Shorts verwendet, nicht Chars. Hast du eine Möglichkeit, die Bibliothek zu debuggen und zu schauen, ob die gewünschten Werte ankommen? Dann könntest du den Fehler zumindest einschränken.

Ohne die Bibiothek selbst zu haben kann ich dir momentan leider nur bedingt helfen.... Sorry.

Viel Erfolg + Gruß
miffi
 
Hallo,

Vielen Dank erstmal für deine Hilfe!!

Ich hab nun die Funktion geändert:

Code:
long CT_data(short shCtn, ByteBuffer dad, ByteBuffer sad, short shLenc, byte[] sCommand, Pointer lenr, byte[] sResponse);

Code:
         final short shCtn = 1;
         byte[] btDad = {1};
         byte[] btSad = {2};
         short shLenc = 5;     
         short shLenr = 256 ;
         final ByteBuffer bbDad = ByteBuffer.wrap(btDad);
         final ByteBuffer bbSad = ByteBuffer.wrap(btSad); 
         ShortByReference p1 = new ShortByReference(); 
         p1.setValue(shLenr); 
         Pointer pLenr = p1.getPointer();  
        
         
        
         iErg = lib.CT_data(shCtn , bbDad, bbSad, shLenc, hsp, pLenr, rsp);

Leider mit einem ähnlichen Ergebnis: "797154176660410112".

Debuggen kann ich die Biliothek leider nicht. Ich kann dir gerne die .dll zuschicken?
 
Hallo,


weiß ich nicht, ob ihr Profis damit nicht sogar was anfangen könntet.

Ich selbst kann mit .dll und Kartenleser die Lösung nicht finden. :confused:

Gruß


Michi
 
Hi Michi.

Da die Long-Variable auch mit so seltsamen Werten gefüllt wird, kommt mir eine Frage:
Ist der Rückgabewert der Funktion CT_data nicht zufällig ein Pointer? Vielleicht liest du da grad nur Speicheradressen aus. In deinem ersten Post stehen gar keine Rückgabewerte bei der API.

Wie Thomas schon gesagt hat - ob es sinnvoll ist, die DLL ohne Lesegerät zu testen, ist fraglich...
Oder gibt es einen brauchbaren Rückgabewert, falls kein Lesegerät gefunden wurde? Dann könnt ich mir das schon mal anschauen.

Gruß

miffi
 
Hi,

ich bin nun total verwirrt, wenn ich es als pointer definiere kommt ein zumindest besseres Ergebnis raus. Es läuft zwar immer noch nicht korrekt, aber das Ergebnis zeigt nun eine "0" (steht eigentlich für fehlerfrei) an. Leider stehen aber keine Daten in dem Response-Bereich.

Code:
ShortByReference p2 = new ShortByReference(); 
p2 = lib.CT_data(shCtn , btDad, btSad, (short) 5, hsp, p1, rsp);
shErg = p2.getValue();

Kann mir jemand vielleicht ein C++-Programm schreiben, dass die Funktion
Code:
CT_data 
(unsigned short ctn, unsigned char * dad, unsigned char * sad, unsigned short lenc, unsigned char * command, unsigned short * lenr, unsigned char * response);
allgemein zur Verfügung stellt und die übergebenen Bereiche an die Konsole übergibt. Dann würde ich mir ´ne .dll draus machen und schauen welcher Parameter falsch ankommt.

Grüsse und nochmals vielen Dank!
 
Hi.

Laut CT-API Referenz ist der Rückgabetyp ein "signed char". (IS8)

Man könnte schon eine C Datei erstellen welche diese Funktione zur Verfügung stellt, nur müßtest du dann auch wirklich konkret sagen wie die Funktionen aussehen (Rückgabetyp, calling convention?). Zeig mal die Headerdatei wo die Funktionen deklariert sind.

Gruß
 
Hier, ich hoffe das ist die richtige:


Code:
/*****************************************************************************
@doc            INT EXT
******************************************************************************
* $ProjectName:  $
* $ProjectRevision:  $
*-----------------------------------------------------------------------------
* $Source: z:/pr/ctapi/sw/ct/rcs/ct.h $
* $Revision: 3 $
*-----------------------------------------------------------------------------
* $Author: tbruendl $
*-----------------------------------------------------------------------------
* History: see EOF
*-----------------------------------------------------------------------------
*
* Copyright © 2009 HID Global
******************************************************************************/

#ifndef _INC_CT
   #define _INC_CT

/*****************************************************************************/
/**  CT-API return codes according CT-API 1.1                               **/
/*****************************************************************************/
/*
** @consts CT API Error Codes | The CT API functions return following error codes.
*/
#define    OK              0           /* @cnst Function call was successful        */
#define    ERR_INVALID    -1           /* @cnst Invalid parameter or value          */
#define    ERR_CT         -8           /* @cnst CT error (CT not in operation)      */
#define    ERR_TRANS      -10          /* @cnst Non-eliminable transmission error   */
#define    ERR_MEMORY     -11          /* @cnst Memory assignment error in HTSI     */
#define    ERR_HTSI       -128         /* @cnst HTSI error                          */

#define SAD_HOST         0x02
#define SAD_REMOTE_HOST  0x05
#define SAD_ICC1         0x00
#define SAD_CT           0x01

#define DAD_HOST         0x02
#define DAD_REMOTE_HOST  0x05
#define DAD_ICC1         0x00
#define DAD_CT           0x01





#ifdef __cplusplus
    extern "C" {
#endif


char  _stdcall CTDEUTICM_close             (
                          unsigned short ctn
                          );

char  _stdcall CTDEUTICM_init        (
                           unsigned short ctn,
                           unsigned short pn
                    );
char _stdcall CTDEUTICM_data (
                             unsigned short ctn,
                             unsigned char * dad,
                             unsigned char * sad,
                             unsigned short lenc,
                             unsigned char * command,
                             unsigned short * lenr,
                             unsigned char * response
                             );

char  _stdcall CT_close             (
                          unsigned short ctn
                          );

char  _stdcall CT_init        (
                           unsigned short ctn,
                           unsigned short pn
                    );
char  _stdcall CT_data (
                             unsigned short ctn,
                             unsigned char * dad,
                             unsigned char * sad,
                             unsigned short lenc,
                             unsigned char * command,
                             unsigned short * lenr,
                             unsigned char * response
                             );


#ifdef __cplusplus
   }
#endif



#endif /* _INC_CT */
 
Hi.

Die Datei ist etwas merkwürdig. Es wird stdcall verwendet, allerdings konnte JNA die Funktionen in der DLL finden obwohl nur von Library und nicht von StdCallLibrary
geerbt wurde... (evtl. solltest du mal StdCallLibrary versuchen...)

Dann wird der Rückgabetyp als char spezifiziert und nicht als signed char wie laut Spezifikation.

Außerdem wird kein declspec import bzw. export der Funktionen zur Nutzung als DLL durchgeführt. Das ist schon etwas merkwürdig.

Ich hab mal schnell einen Testtreiber und DLL geschrieben. Wenn du die DLL erstellst mußt du die ct_EXPORTS Variable definieren - beim Kompilieren des ct_test.c Programmes nicht.

Gruß
 

Anhänge

Zurück