Anbindung DLL an Python

Python in C/C++ embedden, C-Module, ctypes, Cython, SWIG, SIP etc sind hier richtig.
thomasgull
User
Beiträge: 48
Registriert: Samstag 2. Februar 2013, 18:52

Hallo zusammen

ich möchte ein DLL aus python ansprechen.

Momentan stehe ich mir irgendwie selber auf dem Schlauch.

folgender Code gibt es in VB als Beispiel.

**************
Declare Sub AGL_GetVersion Lib "AGLink40.DLL" ( ByRef Major As Long, ByRef Minor As Long )
**************

Wie muss ich es unter Python lösen?

dieser Code findet zwar die DLL aber ein ansprechen der Funktion geht nicht.

***************
from ctypes import*

aglink = windll.LoadLibrary(r"C:\Program Files\DELTALOGIC\ACCON-AGLink\Redist\AGLink40.dll")



version= aglink.AGL_doGetVersion(0,0)

*************
es endet mit folgendem Fehler:

>>>
Traceback (most recent call last):
File "C:/Python26/aglink2.py", line 9, in <module>
version= aglink.AGL_doGetVersion(0,0)
File "C:\Python26\lib\ctypes\__init__.py", line 366, in __getattr__
func = self.__getitem__(name)
File "C:\Python26\lib\ctypes\__init__.py", line 371, in __getitem__
func = self._FuncPtr((name_or_ordinal, self))
AttributeError: function 'AGL_doGetVersion' not found
>>>

für eine kleine denkanstoss wäre ich dankbar.

für weitere Fragen bin ich da.

Grüsse und danke im Voraus

Thomas
Sirius3
User
Beiträge: 17781
Registriert: Sonntag 21. Oktober 2012, 17:20

@thomasgull: heißt die Funktion jetzt AGL_GetVersion oder AGL_doGetVersion?
BlackJack

Als nächstes dürfte dann das `ByRef` Probleme machen — die Funktion möchte keine Zahlen sondern Zeiger auf Zahlen.
thomasgull
User
Beiträge: 48
Registriert: Samstag 2. Februar 2013, 18:52

Besten Dank

Ja es heisst AGL_GetVersion.

wieso weit suchen wenn es vor der Haustüre liegt.

Trotzdem Besten Dank

das mit dem By Val hat sich auch erledigt.
thomasgull
User
Beiträge: 48
Registriert: Samstag 2. Februar 2013, 18:52

So nun brauche ich doch Pointer:

Die DLL erwartet ein Integer als Pointer im Speicherbereich und gibt diesen auch wieder so zurück.

Wie muss ich den Pointer in Python als Int aufbereiten dass es in der DLL zur verfügung steht und das ganze auch noch zurück?

Thomas
BlackJack

@thomasgull: Ich glaube es ist besser eine formale Signatur zu sehen statt aus dem Text zu raten was da genau gefordert ist.
thomasgull
User
Beiträge: 48
Registriert: Samstag 2. Februar 2013, 18:52

Ich habe folgendes versucht:

Code: Alles auswählen

from ctypes import *


a=c_int(10)
pA=byref(a)
print pA

erhalte als Ergebniss:

Code: Alles auswählen

IDLE 2.6.5      ==== No Subprocess ====
>>> 
<cparam 'P' (014FA3C8)>
>>> 

als C-Vorlage habe ich folgendes:

C/C++-Syntax:

Code: Alles auswählen

int WINAPI AGL_PLCConnect( int DevNr, int PlcNr, int *ConnNr, int Timeout, LONG_PTR UserVal );

Parameter:
DevNr Die Nummer des Devices
PlcNr Nummer des Busteilnehmers
ConnNr Verbindungshandle
Timeout Der zu verwendende Timeoutwert
UserVal Wert zur freien Verwendung
Zuletzt geändert von Anonymous am Montag 17. November 2014, 20:36, insgesamt 1-mal geändert.
Grund: Quelltexte in Code-Tags gesetzt.
BlackJack

@thomasgull: Was hast Du denn da jetzt ”versucht”? Das Ergebnis von `byref()` auszugeben bringt ja nichts, zumal das ja eh nur zur Übergabe als Parameter beim Aufruf einer C-Funktion taugt. Das wird man also eigentlich immer nur im Zusammenhang mit so einem Aufruf sehen. Also bei der gezeigten C-Funktion beim `ConnNr`-Argument und beim `UserVal`.
thomasgull
User
Beiträge: 48
Registriert: Samstag 2. Februar 2013, 18:52

Ok war auch nur so ein Kurztest was in der Übergabe steht.

Nun die DLL bearbeitet den übergebenen Wert und gibt ihn an gleicher Speicherposition zurück.

Nun welche Funktion empfiehlt sich für solche Transaktionen?

Danke
BlackJack

@thomasgull: `byref()`. Ist schneller/leichtgewichtiger als `pointer()` was man auch nehmen könnte.
thomasgull
User
Beiträge: 48
Registriert: Samstag 2. Februar 2013, 18:52

danke

welches wäre die "genenfunktion" um aus der Pointervariable wieder den wert zu lesen?


Thomas
BlackJack

@thomasgull: Das hat mit Pointern doch gar nichts zu tun. Die Wertobjekte haben ein `value`-Attribut. Ansonsten wenn Du tatsächlich mal irgendwo Pointer hast, die haben ein `content`-Attribut.
thomasgull
User
Beiträge: 48
Registriert: Samstag 2. Februar 2013, 18:52

also mit byref kann ich den zürückgeschrieben Wert ja nicht mehr lesen oder sehe ich das falsch?
BlackJack

@thomasgull: Du übergibst `byref()` doch irgendein Objekt das ein C-Wert repräsentiert. Das musst Du an einen Namen binden, dann kannst Du da doch hinterher problemlos drauf zugreifen. Sagen wir Du hast eine C-Bibliothek `some_library` und da gibt es eine Funktion mit folgender Signatur: ``void multiply_by_two(int *argument_and_result)``:

Code: Alles auswählen

x = ctypes.c_int(42)
some_library.multiply_by_two(byref(x))
print x.value  # -> 84
thomasgull
User
Beiträge: 48
Registriert: Samstag 2. Februar 2013, 18:52

Besten Dank

Problematik war dass ich nur from Ctypes import* gemacht habe und da hat er beim Ausdruck x.value gemeckert.

So das funktioniert einwandfrei, nun wie geht das auf der Stringebene?

üBergeben mit:

Code: Alles auswählen

mlfb=c_char_p("xxx")
mlfbref=byref(mlfb)
Funktioniert anscheinend

wie muss ich es wieder auslesen?

wenn ich einen Versuch direkt mache ( mit byval in eine Variable und dort wieder als Variable.value auslese klappt es) anscheined modifiziert die DLL irgendwas.

Code: Alles auswählen

x=mlfb.value 
meldet es invalid String pointer 0xirgendwas

Danke

Thomas
BlackJack

@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``?
thomasgull
User
Beiträge: 48
Registriert: Samstag 2. Februar 2013, 18:52

Ok folgender Code:

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
Antwort:

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
>>> 
Danke
Sirius3
User
Beiträge: 17781
Registriert: Sonntag 21. Oktober 2012, 17:20

@thomasgull: wenn ich das richtig sehe, erwartet AGL_ReadMLFBNr Zahlen! Was erwartest Du, wenn Du statt dessen einen Pointer auf einen Pointer auf einen String übergibst?
BlackJack

@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):

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; 
thomasgull
User
Beiträge: 48
Registriert: Samstag 2. Februar 2013, 18:52

Richtig die DLL erwartet eine String mit 21 Zeichen.
Antworten