![]() |
DLL Schnitstelle
Hallo,
Seit mehreren Tagen brüte ich nun schon über folgendes: Als nicht DLL und auch nicht C/C++ Spezi habe ich hier eine Frage zum Aufruf einer DLL Funktion aus Delphi. Hier die ‘c’ Seite:
Code:
Wie würde das Delphi Gegenstück dazu aussehen?
SE_API_IMPL(se_result_t, se_getCertificationId)(char **certificationId, uint32_t *certificationIdLength)
Die DLL function spreche ich in Delphi so an
Delphi-Quellcode:
Sicher ein Klacks komme aber hier nicht weiter und wäre daher sehr dankbar für eine Hint oder besser
function se_getCertificationId(var certificationId: PAnsiChar; certificationIdLength: Cardinal): Cardinal; cdecl; external 'se-api-c.dll';
Code:
Vielen Dank für jegliche Hilfe
In VB.Net sieht es so aus. Brauche aber das Delphi äquivalent.
' Get certification ID as assigned by BSI ("BSI-K-TR-0374-2019" for cryptovision TSE). ' @param[out] certificationId Returned identifier string (Not null terminated) [REQUIRED] ' If successfully executed, the buffer has to freed by the function caller [@ref se_free()]. ' @param[out] certificationIdLength length of the returned identifier string [REQUIRED] ' @return @ref ExecutionOk execution of the function has been successful ' @return @ref ErrorSECommunicationFailed Secure Element communication failed ' @since v2.1 ' se_result_t se_getCertificationId(char**certificationId, uint32_t*certificationIdLength); <DllImport("se-api-c.dll", EntryPoint:="se_getCertificationId", CharSet:=CharSet.Ansi)> Private Function GetCertificationIdSub(ByRef certificationId As IntPtr, ByRef certificationIdLength As Integer) As SeReturnCode End Function Public Structure GetCertificationIdReturn Public ReturnCode As SeReturnCode Public certificationId As String End Structure Public Function GetCertificationId() Dim ReturnStruct As GetCertificationIdReturn Dim certificationId As IntPtr Dim certificationIdLength As Integer ReturnStruct.ReturnCode = GetCertificationIdSub(certificationId, certificationIdLength) If SeReturnCode.ExecutionOk = ReturnStruct.ReturnCode Then ReturnStruct.certificationId = PtrToStringAnsiAndFree(certificationId, certificationIdLength) Else ReturnStruct.certificationId = String.Empty End If Return ReturnStruct End Function Heiri |
AW: DLL Schnitstelle
Code:
SE_API_IMPL(se_result_t, se_getCertificationId)(char **certificationId, uint32_t *certificationIdLength)
-> declare se_getCertificationId as function (pointer to pointer to char, pointer to uint32_t) returning se_result_t
Delphi-Quellcode:
type
se_result_t = Cardinal; //? musst du in der Doku gucken was se_result_t sein soll PUInt32 = ^System.UInt32; PPByte = ^System.PByte; function se_getCertificationId(var certificationId: PAnsiChar; certificationIdLength: PUInt32): se_result_t ; cdecl; external 'se-api-c.dll'; //oder function se_getCertificationId(var certificationId: PAnsiChar; var certificationIdLength: UInt32): se_result_t ; cdecl; external 'se-api-c.dll'; // probiere auch mal so, wenn certificationID eh ne Zahl zwischen 0 und 255 laut Doku ist: function se_getCertificationId(var certificationId: PByte; var certificationIdLength: UInt32): se_result_t ; cdecl; external 'se-api-c.dll'; // gerne auch function se_getCertificationId(certificationId: PPByte; certificationIdLength: PUInt32): se_result_t ; cdecl; external 'se-api-c.dll'; |
AW: DLL Schnitstelle
Oh vielen Dank für deine Antwort.
- se_result_t enthält ein Fehler Code falls es nicht korrekt durch läuft 0. Bei mir kommt immer 'fehlender Parameter' - var certificationId: PAnsiChar sollte die gesuchte ID zurückliefern bei der VB Version bekomme ich das hier 'BSI-K-TR-0000-2019' bei Delphi eben noch nicht! Humm Heiri |
AW: DLL Schnitstelle
Zeig doch mal deinen Quelltext, wo du die Funktion aufrufst.
Hast du alle beide PAnsiChar-Varianten mal durchprobiert? EDIT: Ändere mal bei se_result_t von Cardinal zu einen Int32. Da du nicht die Definition aus dem C-Header gepostet hast, nehme ich einfach mal an, dass da ggf. auch negative Werte rausfallen können?! |
AW: DLL Schnitstelle
Sicher, dass es cdecl oder nicht vielleicht stdcall ist?
Wie sieht denn SE_API_IMPL aus? [OT] Hach, wie schön es bald mit 64 Bit wird ... da gibt's nur noch eine Convention (die fast wie bei unserem Pascal aussieht :stupid:) |
AW: DLL Schnitstelle
Vielen Dank für eure Hilfe versuche.
Jetzt habe ich auch begriffen wie man hier korrekt Code schnipsel einfügt! Insgesammt sind es über 50 Funktionen, die meisten sind ok nur 'se_getCertificationId' will nicht so recht. So sehen die Einbindungen der DLL Funktionen aus:
Delphi-Quellcode:
Und hier die Aufrufe dazu:
function se_getImplementationVersionString(): PAnsiChar; cdecl; external 'se-api-c.dll';
function se_getImplementationVersion(): PAnsiChar; cdecl; external 'se-api-c.dll'; function se_getUniqueId(): PAnsiChar; cdecl; external 'se-api-c.dll'; function se_getCertificationId(var certificationId: PAnsiChar; certificationIdLength: Cardinal): Cardinal; cdecl; external 'se-api-c.dll'; function se_getLifeCycleState(var lcs: Cardinal): Cardinal; cdecl; external 'se-api-c.dll'; function se_getMaxNumberOfClients(var maxNumberClients: Cardinal): Cardinal; cdecl; external 'se-api-c.dll';
Delphi-Quellcode:
Und die Implementation dazu (Hier mache ich eiregend etwas falsch und komme nicht dahinter was wie gemacht werden muss.)
function SeGetPinStatus(var PINState: Cardinal): TSeReturnCode;
function SeGetUniqueId: string; function SeGetCertificationId(var CertificationId: string): TSeReturnCode; function SeAuthenticateUser(UserId: string; PIN: array of Byte; var AuthenticationResult: TSeAuthenticationResult; var RemainingRetrie: ShortInt): TSeReturnCode; function SeGetLifeCycleState(var lcs: TSeLifeCycleState): TSeReturnCode;
Delphi-Quellcode:
Vielen Dank schon mal für die Auswertung meiner Angaben und etwelche wie was wo zu tun ist Hints!
function SeGetCertificationId(var CertificationId: string): TSeReturnCode;
var PCertificationID: PAnsiChar; PCurrent: PAnsiChar; CertificationIDLength: Cardinal; i: Cardinal; begin PCertificationID := nil; // VB übergibt PCertificationID = &H000000000 und CertificationIDLength = 0 Result := TSeReturnCode(se_getCertificationID(PCertificationID, CertificationIDLength)); // Zurück bekomme ich im VB Code BSI-K-TR-0000-2019 für PCertificationID und 18 für CertificationIDLength // Mit Delphi und der Zeile oben einen Fehlercode // Da werde ich die Parameter entsprechend übernehme sobalt // mir se_getCertificationID was brauchbares liefert. // Aktuell erhalte ich hier Access Violation oder der Result code sagt // etwas von 'missing parameter' end; |
AW: DLL Schnitstelle
Das.
Delphi-Quellcode:
function se_getCertificationId(certificationId: PPByte; certificationIdLength: PUInt32): se_result_t ; cdecl; external 'se-api-c.dll';
kann nur ins leere laufen denn ByRef ist immer var in Delphi ByVal ist einfach ein Parameter der übergeben wird. Und dann was denn nun?
Delphi-Quellcode:
oder
PCertificationID: PAnsiChar;
Delphi-Quellcode:
beides geht auf keinen Fall wenn schon dann
CertificationId: string
Delphi-Quellcode:
entfernen und Rückgabe ist
PCertificationID: PAnsiChar;
Delphi-Quellcode:
CertificationId: string
Wenn CertificationId ein Pointer auf AnsiString ist (siehe PtrToStringAnsiAndFree) dann bitte
Delphi-Quellcode:
und nicht
CertificationID: PAnsiChar
Delphi-Quellcode:
.
CertificationID: string
Alles durcheinander geworfen sorry. Siehe
Delphi-Quellcode:
function SeGetCertificationId(var CertificationId: string): TSeReturnCode;
und
Delphi-Quellcode:
function SeGetCertificationId(var CertificationId: PAnsiChar): TSeReturnCode;
Die Definition
Delphi-Quellcode:
PCertificationID: PAnsiChar;
ist dann unsinnig. Korrekt wäre das ohne Gewähr.
Delphi-Quellcode:
Nochmal
function SeGetCertificationId(var CertificationId: PAnsiChar): TSeReturnCode;
var // PCertificationID: PAnsiChar; // Quatsch // PCurrent: PAnsiChar; wird nicht verwendet CertificationIDLength: Cardinal; // i: Cardinal; wird nicht verwendet begin // PCertificationID := nil; Quatsch // VB übergibt PCertificationID = &H000000000 und CertificationIDLength = 0 Result := TSeReturnCode(se_getCertificationID(CertificationID, CertificationIDLength)); // Zurück bekomme ich im VB Code BSI-K-TR-0000-2019 für PCertificationID und 18 für CertificationIDLength // Mit Delphi und der Zeile oben einen Fehlercode // Da werde ich die Parameter entsprechend übernehme sobalt // mir se_getCertificationID was brauchbares liefert. // Aktuell erhalte ich hier Access Violation oder der Result code sagt // etwas von 'missing parameter' end;
Delphi-Quellcode:
oder
var certificationId: PAnsiChar
Delphi-Quellcode:
entscheide dich einfach mal.
var certificationId: string
Delphi-Quellcode:
function se_getCertificationId(var certificationId: PAnsiChar; certificationIdLength: Cardinal): Cardinal; cdecl; external 'se-api-c.dll';
|
AW: DLL Schnitstelle
Das PAnsiChar <> String UnicodeString (seit Delphi 2009) wollte ich auch grade ansprechen.
Zitat:
Wieso ignoriert hier jemand die Compilerwarnungen? Und wenn VB das macht, warum du nicht auch? CertificationIDLength wurde nicht initialisiert PCertificationID = string -> PAnsiChar Und wenn VB das macht, dann vermutlich um erstmal im Result die nötige Länge abzufragen, welche für einen weiteren Aufruf benutzt wird. Man kann alternativ auch blind den Speicher auf eine Länge festlegen, die "immer" ausreichend wäre, und anschließend auf das zurück ändern, was wirklich benutzt wurde. Probleme: * falsche Typen (ANSI <> Unicode) * falsche Benutzung (ungültige Parameter) Entweder intern mit ANSI arbeiten und umkopieren oder die umgebende Funktion mit einem AnsiString bauen. |
AW: DLL Schnitstelle
Vielen Dank venice2,
hilft mir schon mal weiter.
Delphi-Quellcode:
function SeGetCertificationId(var CertificationId: string): TSeReturnCode;
var PCertificationID: PAnsiChar; PCurrent: PAnsiChar; CertificationIDLength: Cardinal; i: Cardinal; begin PCertificationID := nil; // VB übergibt PCertificationID = &H000000000 und CertificationIDLength = 0 Result := TSeReturnCode(se_getCertificationID(PCertificationID, CertificationIDLength)); // Zurück bekomme ich im VB Code BSI-K-TR-0000-2019 für PCertificationID und 18 für CertificationIDLength // Der var Parameter im Header der Funktion sollte für meine Zwecke schon [B]string[/B] sein // Dann müsste ich halt dies entsprechend konvertieren. // Zum Beispiel so CertificationId := String(AnsiString(PCertificationID)); // Oder sehe ich das falsch? // Nur eben die Funktion se_getCertificationID liefert nichts brauchbares in Delphi // Also müsste wohl PCertificationID: PAnsiChar; anders definiert sein oder anders // initialisiert werden, [B]da liegt offenbar mein Problem. [/B] end; |
AW: DLL Schnitstelle
Ich würde den Kram so umschreiben wenn für CertificationIDLength keine Rückgabe erforderlich ist.
Zitat:
Delphi-Quellcode:
function SeGetCertificationId(var CertificationId: PAnsiChar; CertificationIDLength: Cardinal): TSeReturnCode;
Delphi-Quellcode:
EDIT:
if SeGetCertificationId(CertificationId, 0) = ExecutionOk then
bla, bla
Delphi-Quellcode:
CertificationId := String(AnsiString(PCertificationID)); // Oder sehe ich das falsch?
Ja. Du benötigst die Variable PCertificationID nicht! Die Rückgabe ist ein Pointer auf Ansistring (PAnsiChar) siehe (PtrToStringAnsiAndFree) kein String! |
AW: DLL Schnitstelle
Danke vorerst mal an alle muss es mal ausprobieren die DLL Spricht mit einer Hardware, brauche für den Testaufbau zu aktivier etwas Zeit.
@Himitsu: Lässt sich so wie dargestellt Fehlerfrei Kompilieren die Initialisierung CertificationIDLength := 0; löst das Problem nicht hatte ich auch schon ausprobiert. Der Vollständige VB Aufruf der einwandfrei funktioniert ist in meinem initial Post enthalten. Dort wird Length auch nicht weitergereicht. Melde mich dann wieder. |
AW: DLL Schnitstelle
Zitat:
Irgendwie wiedersprüchlich. Zitat:
Aber diese Zeile ist unnötig
Delphi-Quellcode:
CertificationId := String(AnsiString(PCertificationID)); // Oder sehe ich das falsch?
Die Rückgabe der CertificationId ist schon in der Abfrage enthalten
Delphi-Quellcode:
Result := TSeReturnCode(se_getCertificationID(CertificationID, CertificationIDLength));
Denn CertificationID ist ein var parameter. Wenn du die Funktion so aufrufst
Delphi-Quellcode:
if SeGetCertificationId(CertificationId, 0) = ExecutionOk then
dann befindet sich das Ergebnis in CertificationId. Ok bin raus. |
AW: DLL Schnitstelle
Also die Ganze kette steht, so dass ich aktiv testen kann. Und ich habe Venice2 Vorschlag ausprobiert.
Delphi-Quellcode:
Den folgendes wird aufgerufen:
function SeGetCertificationId(var CertificationId: string): TSeReturnCode;
var PCertificationID: PAnsiChar; CertificationIDLength: Cardinal; begin PCertificationID := nil; CertificationIDLength:= 0; // ################ Das kann Kompiliert werden Mein bisheriger Code! Result := TSeReturnCode(se_getCertificationID(PCertificationID, CertificationIDLength)); // ////////////////// Das lässt sich so nicht kompilieren Venice2 Vorschlag! Result := TSeReturnCode(se_getCertificationID(CertificationID, CertificationIDLength)); Ergibt: [DCC Fehler] SeApi.pas(545): E2033 Die Typen der tatsächlichen und formalen Var-Parameter müssen übereinstimmen
Code:
Übrigens: >>> Ich weis nicht wie oft du mit Delphi bisher gearbeitet hast. <<< Sei doch froh dass sich jemand in Delphi weiter entwinkeln versucht,
function se_getCertificationId(var certificationId: PAnsiChar; certificationIdLength: Cardinal): Cardinal; cdecl; external 'se-api-c.dll';
und unterstürze die noch nicht experten das verhilft Delphi zum weiteren überleben. Mein Problem ist damit leider noch nicht gelöst. Will ja keinem auf den Wecker gehen brauche lediglich eine Lösung auf die ich nicht selber komme. Danke Heiri |
AW: DLL Schnitstelle
Zitat:
Delphi-Quellcode:
Vergleiche meinen und deinen Code.
function SeGetCertificationId(var CertificationId: PAnsiChar): TSeReturnCode;
var //PCertificationID: PAnsiChar; nicht nötig CertificationIDLength: Cardinal; begin // PCertificationID := nil; nicht nötig CertificationIDLength:= 0; Result := TSeReturnCode(se_getCertificationID(CertificationId, CertificationIDLength)); end; Die Rückgabe ist PAnsiChar und nicht string. siehe (Wie oft habe ich das jetzt schon gesagt? ) Zitat:
Zitat:
Ich sagte PAnsiChar aber du hast immer noch den String in deiner Funktion. Und dieser Type muss gleich sein bei einem var Parameter. |
AW: DLL Schnitstelle
Ja, und das geht bestimmt auch etwas weniger schroff, oder?
|
AW: DLL Schnitstelle
bei APIs die man vorher nach der Länge fragt, entsprechend dem vom VB
Delphi-Quellcode:
oder eben nicht fragen, sondern einfach machen
var S: AnsiString;
S := ''; x := API(nil, 0); Check(x); SetLength(S, x); Check(API(PAnsiChar(S), x)); Result := S;
Delphi-Quellcode:
ich empfehle mal die Dokumentation von der Funktion zu lesen,
var S: AnsiString; // oder array[0..MAX_LENGTH-1] of AnsiChar;
SetLength(S, MAX_LENGTH); x := API(PAnsiChar(S), {Length(S)}MAX_LENGTH); Check(x); SetLength(S, x); Result := S; oder hier mal von Anderen, die auch sowas machen. ![]() ![]() |
AW: DLL Schnitstelle
Zitat:
Sein Unverständnis dann auf mich abzuwälzen ist weniger schroff ? |
AW: DLL Schnitstelle
Also hier nochmal den ganzen Zusammenhang vielleicht habe ich mich auch nicht wirklich klar ausgedrückt.
Danke dass Ihr nochmals versuchst mich auf den Richtigen Weg zu führen!
Code:
VB Verwendet die gleiche DLL und bekommt einen Pointer und kann den Wert (CertificationID) abholen.
/* 1: ---------- Das ist der C Code in der DLL ------------------------------------------------------- */
SE_API_IMPL(se_result_t, se_getCertificationId)(char **certificationId, uint32_t *certificationIdLength) { SE_EXPORT_METHOD; return se_getCertificationIdEx(&g_se_ctx, certificationId, certificationIdLength); } /* 2: ---------- Das mein Delphi Aufruf (Schnittstelle) der DLL Funktion --------------------------- */ function se_getCertificationId(var certificationId: PAnsiChar; certificationIdLength: Cardinal): Cardinal; cdecl; external 'se-api-c.dll'; /* 3: ---------- Das mein Delphi Aufruf auf der DLL Schnittstellen funktion ------------------------ */ function SeGetCertificationId(var CertificationId: PAnsiChar): TSeReturnCode; var CertificationIDLength: Cardinal; begin CertificationIDLength:= 0; Result := TSeReturnCode(se_getCertificationID(CertificationID, CertificationIDLength)); // Und hier ist CertificationID =nil if PCertificationID<>nil then begin ... .. . Mein Delphi Code nicht?? Also ist möglicherweise im oberen Bereich /* 2: ---- oder /* 3: ---- etwas falsch. |
AW: DLL Schnitstelle
Entweder im Vorfeld einen ausreichend großen Puffer reservieren und dessen Länge übergeben oder zunächst die benötigte Länge zurückgeben lassen, entsprechenden Speicher reservieren und diesen samt seiner tatsächlichen Länge übergeben. Das erfordert dann 2 Aufrufe.
|
AW: DLL Schnitstelle
Ich glaube du meinst.
Delphi-Quellcode:
PCertificationID gibt es nicht.
// Und hier ist CertificationID =nil
if CertificationID <> nil then begin //... end |
AW: DLL Schnitstelle
Zitat:
Das sind allgemeine Grundlagen, die fast überall gleich sind, weil Viele es so machen. Ich hoffe nur jemand macht sein teures Wormlaufwerk nicht kaputt. Quelle: ![]() |
AW: DLL Schnitstelle
Ja richtig danke für den Hinweis!
Sollte heissen: if CertificationID <> nil then begin |
AW: DLL Schnitstelle
Einmal grundsätzlich: man übergibt 2 Parameter an die Funktion, die auch beide von der DLL überschrieben werden, Rückgabe ist ein Fehlercode. Daraus folgt, dass man auch beide Parameter als Var-Parameter deklarieren muss. Ich habe die Cryptovision-API gerade nicht zur Hand, aber mit ziemlicher Sicherheit gibt die Funktion im 2. Parameter entweder die Anzahl der tatsächlich geschriebenen Bytes des 1. Parameters zurück, oder falls dieser zu knapp dimensioniert ist, die Anzahl der benötigten Bytes. Man kann nun also die benötigten Bytes ermitteln, indem man die Funktion mit den Werten nil für den PAnsiChar und 0 für die Länge übergibt. Anschließend wertet man die zurückgegebene Länge (deshalb Var-Parameter) aus, reserviert entsprechenden Speicher und übergibt diesen dann wie vorhin schon einmal erwähnt.
|
AW: DLL Schnitstelle
Heiii danke DeddyH das war das Problem.
function se_getCertificationId(var certificationId: PAnsiChar; certificationIdLength: Cardinal): Cardinal; cdecl; external 'se-api-c.dll'; Geändert zu: function se_getCertificationId(var certificationId: PAnsiChar; var certificationIdLength: Cardinal): Cardinal; cdecl; external 'se-api-c.dll'; Und schon funzt alles. Viele Dank. Auch an alle Andern die an meiner 30 Jährigen Delphi Erfahrung gezweifelt haben. Heiri |
AW: DLL Schnitstelle
Ja, immer diese dummen Sternchen in C, die kann man leicht übersehen :wink:
|
AW: DLL Schnitstelle
Zitat:
Zitat:
Wie dem auch sei. |
AW: DLL Schnitstelle
Was willst Du mir mit diesem Kommentar mitteilen?
|
AW: DLL Schnitstelle
Zitat:
|
AW: DLL Schnitstelle
Zitat:
String/PChar = AnsiString/PAnsiChar bis Delphi 2007 String/PChar = UnicodeString/PWideChar seit Delphi 2009 und nicht zu verwechseln mit WideString, welches kein Delphi-Typ ist, sondern nur die Kapselung der OLE32-String-API. |
AW: DLL Schnitstelle
Zitat:
Hewy, dreißig Jahre Delphi-Erfahrung sind zwar gut und schön, aber mit dreißig Sekunden erhöhtem Leseverständnisses und/oder stumpfen Ausprobieren meiner Vorschläge hätte viel Zeit und Nerven aller Beteiligten gespart werden können. |
AW: DLL Schnitstelle
Und wo ich schonmal am rumranten bin:
Zum Kuckuck, gebe den Buffer gefälligst wieder frei mit se_free(). Einfach mal die Doku lesen, die du selber im ersten Beitrag zum VB Beispiel gepostet hast. Internet kann für heute zu... |
AW: DLL Schnitstelle
Ich schlage mich gerade mit dem selben Mist herum und hätte auch mal eine Frage:
Ich habe folgende Definition in der C-DLL:
Code:
Anmerkung: Die DLL gibt es in sowohl als CDECL- als auch als STDCALL-Variante. Ich benutze logischerweise die STDCALL-Variante, während Hewy wohl die CDECL-Variante verwendet.
se_result_t se_authenticateUser ( const char * userId,
uint32_t userIdLength, const uint8_t * pin, uint32_t pinLength, se_authentication_result_t * authenticationResult, int16_t * remainingRetries ) Weiterhin lade ich die DLL dynamisch über LoadLibrary. Ich habe daraus folgende Definition für Delphi gemacht:
Code:
Die eigentlich Zugriffsmethode, die ich dazwischengeschaltet habe, sieht dann folgendermaßen aus:
se_authenticateUser = Function(userId : PAnsiChar; userIdLength : UInt32; pin : PByteArray; pinLength : UInt32;
Var authenticationResult : SeAuthenticationResult; Var remainingRetries : PShortInt) : SeReturnCode; Stdcall;
Code:
Anmerkung: Unterer unwichtiger Teil der Methode ist abgeschnitten, also bitte nicht auf etwaiges Result etc fokussieren.
Function AuthentifiziereBenutzer(BenutzerID, BenutzerPIN : String; Var Ergebnis : SeAuthenticationResult; Var Versuche : ShortInt) : Boolean;
Var ReturnCode : SeReturnCode; PVersuche : PShortInt; ID : PAnsiChar; PIN : PByteArray; Begin Result := False; PVersuche := @Versuche; ID := PAnsiChar(AnsiString(BenutzerID)); PIN := StringToPByteArray(BenutzerPIN); ReturnCode := Self.AuthenticateUser(ID, Length(BenutzerID), PIN, Length(BenutzerPIN), Ergebnis, PVersuche); Versuche := PVersuche^; End; StringToPByteArray ist folgendermaßen implementiert:
Code:
Ich habe zwei Probleme damit:
Function StringToPByteArray(Nummer : AnsiString) : PByteArray;
Var AByteArray : TBytes; I : Integer; Begin AByteArray := System.SysUtils.TEncoding.ANSI.GetBytes(Nummer); Result := @AByteArray; End; 1. Die Funktion liefert korrekt Rückgabewerte, aber die Authentifizierung klappt nicht trotz richtiger Zugangsdaten, was impliziert, dass etwas mit meinem übergebenen Datentypen nicht stimmt. 2. 1-2 Sekunden nach Ausführen dieser Funktion stürzt das gesamte Programm ab und schließt sich ohne weitere Warnung. Hier bin ich etwas ratlos. Debugger hält mit einer Zugriffsverletzung ganz unten im internen TControl.WndProc an und bricht dann dermaßen katastrophal zusammen ("Aktuelle Debugger-Sitzung muss beendet werden...", "Systemresourcen erschöpft"), dass ich per Task Manager die Entwicklungsumgebung killen muss. Die Funktion wird in einem Button aufgerufen. Ich hoffe stark, dass dieser Punkt mit Punkt 1 zusammenhängt. Meine Überlegungen: PAnsiChar für "char *" ist logisch. Bei der Längenübergabe bin ich mir aber nicht ganz sicher, ob das so in Ordnung ist. PByteArray für "uint8_t * & length"-Konstruktionen zur Übergabe von alphanumerischen Werten in die C DLL sollte generell korrekt sein, jedoch bin ich mir auch hier bei der Längenübergabe unsicher sowie bei meiner Umwandlung eines Eingabe-Strings in ein PByteArray. Eventuell wäre hier ebenfalls PAnsiChar sinnvoller? Offensichtlich ist der Zugriff auf eine C-DLL von Delphi aus Neuland für mich, weswegen ziemlich dämliche Fehler nicht unwahrscheinlich sind. Ich wäre für jede Hilfestellung dankbar. |
AW: DLL Schnitstelle
Ich bin gerade ein ganzes Stück weiter gekommen.
Das mit den Datentypen hat sich vermutlich erledigt und lag an etwas anderem. Authentifizieren hat funktioniert. Interessant wird es hingegen beim Absturzproblem: Ich habe den Aufruf von "AuthentifiziereBenutzer" mal zum Spaß in einen Timer gesteckt und im Button nur noch den Timer aktiviert. In diesem Falle kommt es konsistent nicht zum Absturz, während direkt im Button es konsistent IMMER zum Absturz kommt. Nun stellt sich für mich die große Frage, warum? Im Debugger zumindest kam der katastrophale Fehler im Wndproc, was insofern Sinn machen würde, dass der TButton eine TWinControl ist, während der Timer eine TComponent ist. Nur bin ich etwas ratlos, was genau überhaupt schiefgeht. EDIT: TSpeedButton machts auch. Alles, was keine TWinControl ist, funktioniert. |
AW: DLL Schnitstelle
Zitat:
Das dynamische Array "AByteArray" wird am Ende der Funktion freigegeben, somit zeigt der Zeiger auf alten/ungültigen Mist. Außerdem zeigt Result garnicht auf ein Byte-Array, sondern auf die Variable, die auf ein Byte-Array zeigt.
Delphi-Quellcode:
Result := @AByteArray[0];
Aber, wie schon gesagt, sind Variable und das Array nach dem END verschwunden und der Zeiger zeigt so oder so nur auf Mist. Lösung: Via GetMem Speicher reservieren (bei DLLs nur unter Verwendung von ShareMem), dort die Array-Daten reinkopieren, und später nicht vergessen den Speicher wieder freizugeben. Oder VirtualAlloc, GlobalMem oder einen anderen "globalen" Speichermanager verwenden, wie z.B. den aus'm Ole32/OleAuth. |
AW: DLL Schnitstelle
Im Prinzip habe ich festgestellt, dass die ganze Function unnötig ist.
Dank dir weiß ich nun auch im Detail, warum sie nicht funktioniert hat. :-D Das ByteArray, was erwartet wird, ist tatsächlich einfach nur ein Array von Zahlen, weswegen das Ganze wesentlich einfacher zu lösen war... Einfach ein Bytearray füllen und den Zeiger darauf mit der passenden Länge übergeben und es läuft. Die einzige offene Frage, die ich momentan habe, ist der Grund für das Absturzphänomen, was aber keine sonderlich quälende Frage ist, da die Lösung darin besteht, die DLL-Aufrufe nicht mit TWinControl-TButtons durchzuführen, welche ich sowieso nicht verwende. |
AW: DLL Schnitstelle
Ein neuer Tag, ein neues Problem mit der Schnittstelle...
Ich habe folgende DLL-Methode:
Code:
Das widerliche daran ist der Datentyp "uint8_t **", was meines Verständnisses nach in C die Darstellung eines Arrays von Byte-Arrays ist. Also vergleichbar mit char **, für welches in Delphi ja bereits der Typ PPAnsiChar bereitgestellt wird. Ich bekomme einen Pointer, der auf den ersten PByteArray zeigt sowie praktisch die Anzahl der PByteArrays.
se_result_t se_readLogMessage ( uint8_t ** logMessage,
uint32_t * logMessageLength ) Reads a log message that bases on the last log message parts that have been produced and processed by the Secure Element. Parameters [out] logMessage contains the last log message that the Secure Element has produced [REQUIRED] If successfully executed, the buffer has to freed by the function caller [se_free()]. [out] logMessageLength length of the array that represents the last log message [REQUIRED] Mein derzeitiger Ansatz sieht wie folgt aus: Ich deklariere mir analog einen eigenen Typ "PPByteArray":
Code:
Habe ich dann meinen PPByteArray "PPA" und dessen Länge erhalten, so durchlaufe ich dieses und lege die einzelnen PByteArray in einem Array of PByteArray ab:
Type PPByteArray = ^PByteArray
Code:
Ab diesem Zeitpunkt sollte ich theoretisch mit den PByteArrays standardmäßig verfahren können. In der Praxis kommt aber letztendlich ein Byte-Salat raus, der definitiv falsche Speicheradressen enthält.
PBArray : Array of PByteArray;
For I := 0 to Laenge - 1 Do Begin PBArray[I] := PPA^; Inc(PPA); End; Dementsprechend würde mich mal interessieren, ob in meinen Überlegungen bereits Schwachsinn drin steckt oder ob das tatsächlich der richtige Umgang mit dem C-Datentyp "uint8_t ** ist. Ich musste mich bisher nur sehr selten mit derlei Pointern auseinandersetzen und habe auch nie C gelernt, weswegen mir das etwas Schwierigkeiten bereitet. |
AW: DLL Schnitstelle
Zitat:
Geil ist daran, dass er eben nicht den String rausgibt, sondern einen Zeiger auf seine Variable, die dann auf den String zeigt. Kann auch gut sein, dass du dir hier auch in deine Variable einen Zeiger reinschreiben lässt, der auf eine Variable zeigt, in der dann der String drin steht. |
AW: DLL Schnitstelle
So ähnlich wars letztendlich auch:
Im Prinzip hat ein PByteArray als Parameter ausgereicht, aus dessem angezeigten ByteArray der zurückgegebenen Länge ich dann die Werte auslesen konnte. PPByteArray etc war alles unnötig. Ob "uint8_t *" oder "uint8_t **" macht für Delphi keinen Unterschied. Was ein Schwachsinn... |
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:54 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz