@thomasgull: Den Satz mit „byval” (was ist das?) habe ich nicht verstanden. Ansonsten nimm die Meldung einfach mal so wie sie da steht: irgendwie bekommst Du da einen Zeiger rein der ungültig ist.
Ansonsten sind Beschreibungen wie „hat er beim Ausdruck x.value gemeckert” oder „meldet es invalid String pointer 0xirgendwas” sehr ungenau. Wenn es Ausnahmen gibt, dann wäre der komplette Traceback und der dazugehörige Quelltext in der Regel hilfreicher für helfende.
Kann es sein, dass die Funktion irgendwie auf eine andere Weise anzeigt, dass ein Fehler aufgetreten ist und man deshalb den Zeiger gar nicht erst benutzen darf? Wird da überhaupt ein Zeiger auf einen Zeiger auf ``char`` erwartet? Also ist die C-Signatur an der Stelle wirklich ``char **argument``?
Anbindung DLL an Python
-
- User
- Beiträge: 48
- Registriert: Samstag 2. Februar 2013, 18:52
Ok folgender Code:
Antwort:
Danke
Code: Alles auswählen
#mlfb lesen
mlfbnr=ctypes.c_char_p("xxxxxxxxxxxxxxxxxxxx")
mlfbnrref=byref(mlfbnr)
timeout=2000
egal=0
print mlfbnr.value
mlfb= aglink.AGL_ReadMLFBNr(connectNrRet,mlfbnrref,timeout,egal)
if mlfb ==0:
print "MLFB erfolgreich"
x=mlfbnr.value
print x
else:
error=" "
errtxt= aglink.AGL_GetErrorMsg(mlfb,error,256)
print error
Code: Alles auswählen
xxxxxxxxxxxxxxxxxxxx
MLFB erfolgreich
Traceback (most recent call last):
File "C:\Python26\DLLs\aglink3.py", line 112, in <module>
x=mlfbnr.value
ValueError: invalid string pointer 0x37534536
>>>
@thomasgull: Ein Pointer dessen Bytewerte alle im ASCII-Bereich liegen und bei etwas das eine ”Nummer” ermittel zwei ASCII-Ziffern enthält ist zumindest verdächtig. Ich bleibe bei meiner Vermutung das hier kein Zeiger auf einen Zeiger auf ``char`` erwartet wird sondern nur ein Zeiger auf ``char``. Und Du möchtest da vielleicht auch besser keinen `c_char_p()`-Wert übergeben der auf eine eigentlich unveränderbare Python-Zeichenkette zeigt. Da können böse Sachen passieren. `c_buffer()` oder `create_string_buffer()` verwendet man dafür.
@Sirius: Da wird ein Zeiger auf ein Byte-Array der Länge 21 erwartet wo ein Nullterminierter String reingeschrieben wird, laut API-Dokumentation. → http://www.sumelco.com/wp-content/uploa ... k_4_HB.pdf (Seite 156):
@Sirius: Da wird ein Zeiger auf ein Byte-Array der Länge 21 erwartet wo ein Nullterminierter String reingeschrieben wird, laut API-Dokumentation. → http://www.sumelco.com/wp-content/uploa ... k_4_HB.pdf (Seite 156):
Code: Alles auswählen
int WINAPI AGL_ReadMLFBNr( int ConnNr, LPMLFB MLFBNr, int Timeout, long UserVal );
typedef struct tagMLFB
{
BYTE MLFB[21]; // MLFB number as a zero-terminated string
} MLFB, *LPMLFB;
-
- User
- Beiträge: 48
- Registriert: Samstag 2. Februar 2013, 18:52
Richtig die DLL erwartet eine String mit 21 Zeichen.
@thomasgull: Naja korrekter eher einen Speicherbereich in den man bis zu 21 Bytes ablegen kann. Ob da vor dem Aufruf Daten drinstehen die als C-String durchgehen und bei `strlen()` tatsächlich 20(!) als Ergebnis liefern ist egal. 21 Zeichen kann die Zeichenkette nicht haben, denn dann müsste der Speicherbereich 22 Bytes gross sein.
-
- User
- Beiträge: 48
- Registriert: Samstag 2. Februar 2013, 18:52
Danke mit c_Buffer funktioniert es bestens
Danke
Danke
-
- User
- Beiträge: 48
- Registriert: Samstag 2. Februar 2013, 18:52
Nochmals besten Dank
Langsam habe ich die C-Funktionen begriffen
Langsam habe ich die C-Funktionen begriffen
-
- User
- Beiträge: 48
- Registriert: Samstag 2. Februar 2013, 18:52
Nochmals eine Frage
wie würdet ihr das mit Strukturen lösen?
Bei dieser Funktion werden ganze Strukturen übergeben und danach wieder Ausgelesen.
Beschreibung:
Erweiterter Leseauftrag für Antriebe (AGL_Drive_ReadMixEx)
Mit dieser Funktion können Sie die Werte verschiedener Datentypen und Datengrößen in einem Auftrag lesen. Gegenüber der Funktion AGL_Drive_ReadMix darf hier die Strukturvariable DATA_RW40_DRIVE.OpAnz auch größer 1 sein. Dies bedeutet, dass mit einem Strukturelement mehrere aufeinanderfolgende Operandenwerte gelesen werden können.
C/C++-Syntax:
int WINAPI AGL_Drive_ReadMixEx( int ConnNr, LPDATA_RW40_DRIVE Buff, int Num, int Timeout, LONG_PTR UserVal );
Parameter:
ConnNr Verbindungshandle
Buff Zeiger auf Lesestrukturen
Num Anzahl der Strukturen
Timeout Der zu verwendende Timeoutwert
UserVal Wert zur freien Verwendung
Rückgabewert:
>= 0 Auftragsnummer bei asynchronem Aufruf und synchronem Aufruf mit AGL_ReturnJobNr( 1 ) oder AGL40_SUCCESS bei synchronem Aufruf ohne AGL_ReturnJobNr( 1 )
< 0 Eine Fehlernummer (s. AGL_Defines.H, AGL_Defines.BAS oder AGL_Defines.PAS)
Code in C++
Viele Grüsse
Thomas
wie würdet ihr das mit Strukturen lösen?
Bei dieser Funktion werden ganze Strukturen übergeben und danach wieder Ausgelesen.
Beschreibung:
Erweiterter Leseauftrag für Antriebe (AGL_Drive_ReadMixEx)
Mit dieser Funktion können Sie die Werte verschiedener Datentypen und Datengrößen in einem Auftrag lesen. Gegenüber der Funktion AGL_Drive_ReadMix darf hier die Strukturvariable DATA_RW40_DRIVE.OpAnz auch größer 1 sein. Dies bedeutet, dass mit einem Strukturelement mehrere aufeinanderfolgende Operandenwerte gelesen werden können.
C/C++-Syntax:
int WINAPI AGL_Drive_ReadMixEx( int ConnNr, LPDATA_RW40_DRIVE Buff, int Num, int Timeout, LONG_PTR UserVal );
Parameter:
ConnNr Verbindungshandle
Buff Zeiger auf Lesestrukturen
Num Anzahl der Strukturen
Timeout Der zu verwendende Timeoutwert
UserVal Wert zur freien Verwendung
Rückgabewert:
>= 0 Auftragsnummer bei asynchronem Aufruf und synchronem Aufruf mit AGL_ReturnJobNr( 1 ) oder AGL40_SUCCESS bei synchronem Aufruf ohne AGL_ReturnJobNr( 1 )
< 0 Eine Fehlernummer (s. AGL_Defines.H, AGL_Defines.BAS oder AGL_Defines.PAS)
Code in C++
Code: Alles auswählen
int doDrive_ReadMixEx(int connnr, int timeout, int userval)
{
int num = 3;
LPDATA_RW40 rwfield = (LPDATA_RW40)calloc(num, sizeof(DATA_RW40));
rwfield[0].Dev = 1;
rwfield[0].ParaInd = 0;
rwfield[0].ParaNum = 0;
rwfield[0].OpAnz = 1;
rwfield[0].OpType = DTYP_UNKNOWN;
rwfield[0].Result = 0;
rwfield[0].Buff = (float*)calloc(rwfield[0].OpAnz, sizeof(float));
((float*)rwfield[0].Buff)[0] = 0;
rwfield[1].Dev = 0;
rwfield[1].ParaInd = 1;
rwfield[1].ParaNum = 0;
rwfield[1].OpAnz = 5;
rwfield[1].OpType = DTYP_UNKNOWN;
rwfield[1].Result = 0;
rwfield[1].Buff = (DWORD*)calloc(rwfield[1].OpAnz, sizeof(DWORD));
((DWORD*)rwfield[1].Buff)[0] = 1;
((DWORD*)rwfield[1].Buff)[1] = 0;
((DWORD*)rwfield[1].Buff)[2] = 0;
((DWORD*)rwfield[1].Buff)[3] = 0;
((DWORD*)rwfield[1].Buff)[4] = 0;
rwfield[2].Dev = 0;
rwfield[2].ParaInd = 1;
rwfield[2].ParaNum = 0;
rwfield[2].OpAnz = 1;
rwfield[2].OpType = DTYP_UNKNOWN;
rwfield[2].Result = 0;
rwfield[2].Buff = (byte*)calloc(rwfield[2].OpAnz, sizeof(byte));
((byte*)rwfield[2].Buff)[0] = 1;
// For a successful call, a connection must be built up to the AG.
int result = AGL_DriveReadMixEx(connnr, rwfield, num, timeout, userval);
if (result != AGL40_SUCCESS)
{
// Error happened.
char errormsg[256];
AGL_GetErrorMsg(result, errormsg, 256);
}
// clean up the memory
free(rwfield[0].Buff);
free(rwfield[1].Buff);
free(rwfield[2].Buff);
return result;
}
Viele Grüsse
Thomas
@thomasgull: Was ist denn dabei die konkrete Frage? Wie man Proxy-Objekte für Strukturtypen mit `ctypes` definiert steht in der Python-Dokumentation im `ctypes`-Tutorial.
Und wie man so eine komplette Funktion konkret übersetzt hängt auch ein bisschen davon ab wie man die Python API zu den Funktionen gestaltet. Das wird man ja hoffentlich nicht 1:1 machen sondern eine „pythonische” API entwerfen. Sonst stellt sich nämlich die Frage warum man das überhaupt in Python macht wenn der Code am Ende aussieht wie C-Code in Python-Syntax verkleidet.
In dem gezeigten Quelltext wird der Speicher von `rwfield` nicht wieder freigegeben. Das sieht nach einem Speicherleck aus.
Und wie man so eine komplette Funktion konkret übersetzt hängt auch ein bisschen davon ab wie man die Python API zu den Funktionen gestaltet. Das wird man ja hoffentlich nicht 1:1 machen sondern eine „pythonische” API entwerfen. Sonst stellt sich nämlich die Frage warum man das überhaupt in Python macht wenn der Code am Ende aussieht wie C-Code in Python-Syntax verkleidet.
In dem gezeigten Quelltext wird der Speicher von `rwfield` nicht wieder freigegeben. Das sieht nach einem Speicherleck aus.