Verständnisfrage zu ctypes/DLL/struct Teil II

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
Damaskus
Administrator
Beiträge: 995
Registriert: Sonntag 6. März 2005, 20:08
Wohnort: Schwabenländle

Fortsetzung zu http://www.python-forum.de/topic-14459.html


Hallo Blackjack,
irgendwie scheitere ich noch immer an dem ganzen. Liegt aber wohl eher daran dass ich das gesamte Zusammenspiel von Pointern / Strukturen und ctypes noch nicht ganz verstehe.

Gibts dazu noch irgendwelche "leichte Kost" außer dem Python Manual?
Entweder bekomme ich als Rückmeldung eine SUCCESS und gleichzeitig eine Lesefehler auf Byte 0x000000 (was auch verständlich ist) oder ich bekomme je nachdem wie ich die Funktion aufrufe "ValueError: Procedure probably called with too many arguments (116 bytes in excess)"

Wäre toll wenn du mir noch einige Hinweise und Tipps hättest.

Hier mein bisheriges Script: http://paste.pocoo.org/show/47502/

Danke!

Gruß
Damaskus
BlackJack

Nach der Signatur im Vorgängerthread erwartet `xlGetDriverConfig` einen *Zeiger* auf eine `XLdriverConfig`-Struktur, der ist je nach Architektur 4 oder 8 Bytes gross. Du übergibst aber die Struktur als Wert, das sind ein paar Bytes zu viel.

Wie sieht's denn mit Deinem C-Wissen aus? Das Sternchen gehört zum Typ und nicht zum Namen und bedeutet "Zeiger". In `struct_xlGetApplConfig` sind auch ein paar Namen mit Sternchen, die eigentlich in die Typangabe gehören. Das könnte zwar zufällig so funktionieren, aber es ist nicht garantiert, dass ``int`` und ``int*`` die gleiche Anzahl von Bytes belegen.
Benutzeravatar
Damaskus
Administrator
Beiträge: 995
Registriert: Sonntag 6. März 2005, 20:08
Wohnort: Schwabenländle

Mein C Wissen ist sehr bescheiden :oops:
Und mit dem Projekt versuch ich mich gleichzeitig in C und in ctypes etwas einzuarbeiten. Wobei ich inzwischen schon gemerkt habe dass ich mich evtl. etwas damit übernommen hab.
Aber interresieren tuts mich trotzdem und deshalb versuch ich weiterhin das ganze zu lernen. Auch wenns warscheinlich am C Grundwissen scheitert.
Das Sternchen gehört zum Typ und nicht zum Namen und bedeutet "Zeiger". In `struct_xlGetApplConfig` sind auch ein paar Namen mit Sternchen, die eigentlich in die Typangabe gehören.
Ok, wenn ich das richtig verstanden habe dann muss ich das Struct als Zeiger (Pointer) übergeben. Richtig?
Also z.B.

Code: Alles auswählen

        # Treiber Konfig
        #s = struct_xlGetDriverConfig()
        s = pointer(struct_xlGetDriverConfig())
        XLstatus = dll.xlGetDriverConfig(s)
        print c_char_p(dll.xlGetErrorString(c_int(XLstatus))).value
Und in dem Struct selber auch noch Pointer definieren. An den geforderten Stellen halt.
BlackJack

Sofern Du auf die Struktur von Python aus zugreifen möchtest oder musst, würde ich ein Exemplar von der Struktur an `s` binden und nur für die Übergabe an die DLL-Funktion einen Zeiger mit `byref()` erzeugen. Sonst hast Du beim Zugriff auf `s` ja immer die Indirektion über den Zeiger.

Code: Alles auswählen

        # Treiber Konfig
        s = struct_xlGetDriverConfig()
        XLstatus = dll.xlGetDriverConfig(byref(s))
        print c_char_p(dll.xlGetErrorString(c_int(XLstatus))).value
Benutzeravatar
Damaskus
Administrator
Beiträge: 995
Registriert: Sonntag 6. März 2005, 20:08
Wohnort: Schwabenländle

Moin,
jetzt hats geklappt!
Lag nicht daran dass ich einen falschen Aufruf hatte sondern im Struct hatte ich einen Fehler.
Und ich hab die ganze Zeit im Prinzip den Fehler an der falschen Stelle, nämlich dem Aufruf der Funktion gesucht.

Danke für die Hilfe und die Geduld :D

Gruß
Damaskus
Benutzeravatar
Damaskus
Administrator
Beiträge: 995
Registriert: Sonntag 6. März 2005, 20:08
Wohnort: Schwabenländle

Ich muss den Thread hier doch nochmal beleben...

Folgendes Problem gibts noch immer mit der Funktion.
Wenn ich die Funktion xlGetDriverConfig aufrufe läuft diese auch sauber durch und liefert "Success". Allerdings werden alle Felder ab dem "channel" Array nicht richtig gefüllt. Vor dem Aufruf enthalten die Felder None und nach dem Aufruf enthalten alle Felder 0 und nicht die gewünschten Werte.

Wenn ich den selben Aufruf in C mache wird das Struct korrekt befüllt.

Gibts da noch irgendwas zu beachten?

Gruß
Damaskus
BlackJack

Zumindest hier http://paste.pocoo.org/show/47502/ stimmt `struct_xlGetDriverConfig` nicht mit dem ``struct`` aus http://www.python-forum.de/post-97401.html#97401 überein.

'reserved' und 'channels' sind Arrays, das müsste also so aussehen:

Code: Alles auswählen

class struct_xlGetDriverConfig(Structure):
    _fields_ = [
        ("dllVersion", c_uint),
        ("channelCount", c_uint),
        ("reserved", c_uint * 10),
        ("channel", struct_XLchannelConfig * XL_CONFIG_MAX_CHANNELS)
    ]
Benutzeravatar
Damaskus
Administrator
Beiträge: 995
Registriert: Sonntag 6. März 2005, 20:08
Wohnort: Schwabenländle

Das hab ich alles beachtet.
Ohne die Arrays läuft der Aufruf sowieso nicht fehlerfrei durch.

hier die Structs: http://paste.pocoo.org/show/49740/

Und hier das Programm dazu: http://paste.pocoo.org/show/49741/

Eigentlich müssten so alle Werte gefüllt werden. Bei anderen Funktionsaufrufen funktioniert es auch. Allerdings hat von denen keines eine SubStruktur.

Gruß
Damaskus
BlackJack

In `struct_XLchannelConfig` gleich das erste Feld hat den falschen Typ. Du hast da ein Array von 32 *Zeigern* auf Zeichen deklariert, was im Original ein Array von 32 *Zeichen* ist. (Vorausgesetzt ``XL_MAX_LENGTH + 1 == 32``)
Benutzeravatar
Damaskus
Administrator
Beiträge: 995
Registriert: Sonntag 6. März 2005, 20:08
Wohnort: Schwabenländle

(XL_MAX_LENGHT + 1) == 32 Stimmt!

Du meinst ich hab ein Array mit 32 Einträgen erstellt und ich brauch eins mit einem Eintrag der 32 Zeichen lang ist. Richtig?
Wenn das so richtig ist wie erstelle ich dann eines mit 32 Zeichen?

Ich hätte das dann so gemacht, was aber auch nicht richtig ist.

Code: Alles auswählen

name = c_char_p
name(32)

class struct_XLchannelConfig(Structure):
    _fields_ = [
        ("name", name)
        ...
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

Es müsste ``ctypes.c_char * 32`` sein.
Benutzeravatar
Damaskus
Administrator
Beiträge: 995
Registriert: Sonntag 6. März 2005, 20:08
Wohnort: Schwabenländle

Trundle hat geschrieben:Es müsste ``ctypes.c_char * 32`` sein.
Danke!
Genau das wars! Jetzt werden alle Felder richtig gefüllt.

Gruß
Damaskus

EDIT:
Wer lesen kann ist im Vorteil :wink: :
class c_char
Represents the C char datatype, and interprets the value as a single character. The constructor accepts an optional string initializer...
Benutzeravatar
Damaskus
Administrator
Beiträge: 995
Registriert: Sonntag 6. März 2005, 20:08
Wohnort: Schwabenländle

Und nochmal ne Frage zu dem ganzen Thema.

Wenn ich c_uint Werte aus dem Struct auslese bekomme ich unter C++ den Wert "02" und unter Python den Wert "2". Allerdings steht dann im nächsten Feld unter C++ z.B. der Wert "16" drinn und unter Python hat das nächste Feld den Wert "0" und erst das übernächste Feld den Wert "16".

Code: Alles auswählen

- hwtype            --> 15    -
- hwindex           --> 00    -
- hwchannel         --> 00    -
- transceiverType   --> 01    -
- transceiverState  --> 16    -
- channelIndex      --> 00    -

Code: Alles auswählen

hwtype                 15
hwindex                0
hwchannel              0
transceiverType        1
transceiverState       0
channelIndex           16
Hat dazu noch jemand eine Idee bzw. einen Tip?

Gruß
Damaskus
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

Sicher, dass ``transceiverType`` ein `c_uint` ist und kein `c_ushort`? Das würde es nämlich erklären.
Benutzeravatar
Damaskus
Administrator
Beiträge: 995
Registriert: Sonntag 6. März 2005, 20:08
Wohnort: Schwabenländle

Laut API ist es c_uint!
Allerdings hab ich mehrere solcher "Fehler" schon gehabt und deshalb ist es gut möglich. Werd ich morgen im Büro mal ausprobieren.

Danke!

Gruß
Damaskus
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

Naja, beim Thread Teil I hast du
unsigned short transceiverType;
geschrieben.
Benutzeravatar
Damaskus
Administrator
Beiträge: 995
Registriert: Sonntag 6. März 2005, 20:08
Wohnort: Schwabenländle

Trundle hat geschrieben:Naja, beim Thread Teil I hast du
unsigned short transceiverType;
geschrieben.
Stimmt! Hab ich vor lauter ausprobieren gar nciht mehr gesehen.
Wobei ich festgestellt hab dass es oftmals egal ist ob es uint, ubyte oder sonstwas ist. Zumindest bei der DLL.

Ist das eigentlich Normal?

Gruß
Damaskus
BlackJack

Nein das würde ich nicht als Normal bezeichnen. Du legst damit ja das Speicherlayout fest. Es kann höchstens sein, dass Du immer soviel unverschämtes Glück hattest, dass die Ausrichtung auf Wortgrenzen und die geschickte Kombination von zu grossen und zu kleinen Typen Deine Fehler teilweise wieder ausgeglichen haben. Das ist aber schon ziemlich unwahrscheinlich.
Antworten