Python char Pointer mit ctypes an C-DLL Funktion übergeben

Python in C/C++ embedden, C-Module, ctypes, Cython, SWIG, SIP etc sind hier richtig.
tryanderror
User
Beiträge: 24
Registriert: Mittwoch 19. Februar 2020, 08:30

Leider habe ich auf dem aktuellen Rechner kein LabView mein Kollege hat das auf seinem Laptop, nur leider ist dieser heute nicht da...

Verwendet habe ich jetzt den Code von __blackjack__

Code: Alles auswählen

from ctypes import *

lib = CDLL('tolledll.dll')
generate_key_exopt = lib.GenerateKeyExOpt
generate_key_exopt.argtypes = [
    c_char_p,
    c_uint,
    c_uint,
    c_char_p,
    c_char_p,
    c_char_p,
    c_uint,
    POINTER(c_uint),
]
generate_key_exopt.restype = c_uint

seed = b'\x00\x00\xAF\xBF\x04\xB9\x23\x8D'
seed_size = 8
security_level = 1
variant = b'\0' * 5
options = b'E00S00'

max_key_size = 6
key = (c_char * max_key_size)()
actual_key_size = c_uint()


response = generate_key_exopt(
    seed,
    len(seed),
    security_level,
    variant,
    options,
    key,
    max_key_size,
    actual_key_size,
)
print(response, actual_key_size, key.value[: actual_key_size.value])
Ich weiß nur bezüglich der Parameter die Datentypen und meines Wissens nach wurden auch die Datentypen aus dem Prototyp in LabView verwendet.
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

Wie sieht denn die Komplette Fehlermeldung aus? Ist die Speicheradresse 0 oder irgend ein anderer Wert?
Wenn es sich um eine 32bit-DLL handelt, kann es sich noch um die falsche Call-Konvention handeln

Code: Alles auswählen

lib = WinDLL('tolledll.dll')
tryanderror
User
Beiträge: 24
Registriert: Mittwoch 19. Februar 2020, 08:30

Es handelt sich um eine 32-Bit Dll, verwende auch Python 3.7.3-32 bit.
Fehlercode ist:

Exception has occured: OSError
exception: access violation writing 0x00000006

es wird auf die Funktionsaufrufzeile verwiesen also diese:

Code: Alles auswählen

response = generate_key_exopt(
    seed,
    len(seed),
    security_level,
    variant,
    options,
    key,
    max_key_size,
    actual_key_size,
)
Hab jetzt auch mit WinDll versucht, es bleibt jedoch der gleiche Fehler.
Benutzeravatar
__blackjack__
User
Beiträge: 12984
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@tryanderror: `max_key_size` hat den Wert 6, ändert sich was an der Adresse wenn Du da einen anderen Wert übergibst? Ist die Signatur/Reihenfolge der Argumente eventuell einfach falsch?
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
tryanderror
User
Beiträge: 24
Registriert: Mittwoch 19. Februar 2020, 08:30

Ja ich habe gerade den Wert paar mal verändert und der Fehlercode ist immer gleich des Wertes von max_key_size in hex.
Benutzeravatar
__blackjack__
User
Beiträge: 12984
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Was auch auffällt ist das es sowohl ``unsigned char*`` gibt als auch ``char *``. Und in der Doku bei den ersteren was von „raw bytes“ steht und bei den anderen was von freiem Text. Kann es sein, dass *die* dann auch tatsächlich Zeichenketten aus C-Sicht sein sollten, also *mit* Nullbyte am Ende? Und wo sind die Rückgabewerte dokumentiert?
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

Es ist ja offensichtlich, dass der Parameter max_key_size (der einzige mit dem Wert 6) für einen Pointer gehalten wird. Du hast also entweder einen Parameter zu viel oder zu wenig angegeben, je nachdem ob versucht wird, statt dessen auf key oder actual_key_size zu schreiben.
Da wäre es wieder gut, einen funktionierenden Funktionsaufruf zu sehen.

@__blackjack__: ipVariant und ipOptions scheinen ja tatsächlich "lesbarer" Text zu sein (E00S00). Python-Strings enthalten aber automatisch ein 0-Byte als Endekennung und ctypes nutzt das auch.
tryanderror
User
Beiträge: 24
Registriert: Mittwoch 19. Februar 2020, 08:30

Sorry aber ich habe leider wirklich nur diese eine PDF welche ich verlinkt habe, ich weiß nur, dass die Funktion in das übergebenden Array schreibt was der generierte Schlüssel ist und wie lang dieser ist in die Int Var.

Im Fehlerfall gibt die Funktion eine Return von 1-4, wo ich dann sehen kann was verkehrt ist aber leider kommt das Programm nicht so weit.

Ja options muss Lesbar sein, der Code wir anders Interpretiert als das im SeedArray.

Wenn ich ein Parameter entferne kommt die Fehlermeldung:
Exception has occurred: ValueError
Procedure probably called with too many arguments (28 bytes in excess)
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

Ich hab ja nicht geschrieben, dass Du irgendwo einfach so einen Parameter entfernen sollst. Es ist halt nur komisch, warum er einen Parameter als Pointer benutzt, der dafür nicht gedacht ist. Es gibt ja noch die Funktion ohne Opt, die einen Parameter weniger hat. Vielleicht wurde da etwas vertauscht.
Benutzeravatar
__blackjack__
User
Beiträge: 12984
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Wenn Du *einen* Parameter entfernst sind plötzlich 28 Bytes zu viel beim Aufruf? Das ist sehr merkwürdig.

Ich habe meins noch mal überarbeitet. Natürlich ungetestet.

Code: Alles auswählen

#!/usr/bin/env python3
from ctypes import *

lib = WinDLL("tolledll.dll")
_generate_key_exopt = lib.GenerateKeyExOpt
_generate_key_exopt.argtypes = [
    POINTER(c_uint8),
    c_uint,
    c_uint,
    c_char_p,
    c_char_p,
    POINTER(c_uint8),
    c_uint,
    POINTER(c_int),
]
_generate_key_exopt.restype = c_int


def generate_key(seed, security_level, variant, options, max_key_size):
    key = (c_uint8 * max_key_size)()
    actual_key_size = c_uint()
    response = _generate_key_exopt(
        c_char_p(seed),
        len(seed),
        security_level,
        None if variant is None else c_char_p(variant.encode("ascii")),
        None if options is None else c_char_p(options.encode("ascii")),
        key,
        max_key_size,
        byref(actual_key_size),
    )
    if response != 0:
        raise Exception(f"response was {response}.")
    return key.value[: actual_key_size.value]


def main():
    generate_key(b"\x00\x00\xAF\xBF\x04\xB9\x23\x8D", 1, None, "E00S00", 6)


if __name__ == "__main__":
    main()
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
__deets__
User
Beiträge: 14480
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich weiss nicht ob jemand anderes es schon erwaehnt hat - aber statt CDLL gibt's ja auch noch WinDLL, mit einer anderen calling-convention. Hast du das mal ausprobiert? https://docs.python.org/3/library/ctype ... -libraries

Edit: gerade gesehen, Sirius3 hat das auch schon erwaehnt.
tryanderror
User
Beiträge: 24
Registriert: Mittwoch 19. Februar 2020, 08:30

Hallo, ich hatte gestern schon mit dem Thema abgeschlossen gehabt und mich ebend erst wieder rangesetzt. Euer Hinweis darauf, dass der folgender Fehler auf eine Nutzung der Funktion mit zu vielen Parametern war, hat mich auf die Idee gebracht die anderen Funktionen mal durchzutesten.
Exception has occured: OSError
exception: access violation writing 0x00000006
Natürlich funktioniert der folgende Code mit der Funktion auf Seite 3 vom PDF.

Code: Alles auswählen

from ctypes import *

lib = CDLL('tolledll.dll')
generate_key_exopt = lib.GenerateKeyEx
generate_key_exopt.argtypes = [
    c_char_p,
    c_uint,
    c_uint,
    c_char_p,
    c_char_p,
    c_int,
    POINTER(c_uint),
]
generate_key_exopt.restype = c_uint

seed = b'\x00\x00\xAF\xBF\x04\xB9\x23\x8D'
seed_size = 8
security_level = 1
variant = b'\0' * 5
options = b'E00S00'

max_key_size = c_int(6)
key = (c_char * 6)()
actual_key_size = c_uint()


response = generate_key_exopt(
    seed,
    len(seed),
    security_level,
    variant,
    key,
    max_key_size,
    actual_key_size,
)
print(response, actual_key_size, key.value[: actual_key_size.value])
Die ich erhaltenen Informationen und PDFs waren ungleich. Entschuldigt den Aufwand aber ich bedanke mich troztdem für eure Hilfe, ohne diese hätte ich mich noch die nächsten Tage damit gequält.

Das ist fast der gleiche Code wie von __blackjack__, ich habe lediglich die options Variable entfernt, da die in der alten Funktion nicht vertreten war. Nochmal danke an alle für die Hilfe.
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

Die PDF-Datei enthält also falsche Informationen zu GenerateKeyExOpt, aber die Funktion GenerateKeyEx funktioniert. Dann solltest Du die Funktion in Python aber nicht generate_key_exopt nennen, denn das verwirrt dann wieder. `seed_size` und `options` werden nicht verwendet und können weg.
Benutzeravatar
__blackjack__
User
Beiträge: 12984
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Sirius3: Oder die DLL hat die Funktion falsch implementiert, denn zu `GenerateKeyExOpt` hatte ich gestern mindestens zwei Codebeispiele in C gefunden die mit der Signatur in dem PDF übereinstimmen.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten