Hallo alle zusammen
Habe da ein Problem, was wie ich finde auf den meisten Seiten nicht wirklich gelöst wurde, daher dachte ich mir ich frage hier mal.
Ich habe ein .dll welche unter Fortran 77 compiliert wurde. Ich möchte diese in Python importieren, und eine Funktion in dieser .dll aufrufen. Die .dll hat den Namen Eth.dll und ich möchte gerne die Funktion CP_ABC_Eth(A,B,C) aus dieser aufrufen.
Hier vielleicht mal kurz was ich bisher habe:
from ctypes import *
# give location of dll
Eth = cdll.LoadLibrary("Eth.dll")
# call the functions in the dll
A=1
B=1
C=-1000
CP= Eth.CP_ABC_Eth(A,B,C)
print "CP"
wenn ich das versuche zu rechnen, erhalte ich folgende Fehlermeldung:
Traceback (most recent call last):
File "C:\...\testfile", line 11, in <module>
CP= Eth.CP_ABC_Eth(A,B,C)
WindowsError: exception: access violation reading 0x00000001
Hoffe mir kann einer weiterhelfen.
Vielen Dank im Voraus
Fortran 77 dll importieren + function aufrufen
@liddokun88: Versuche einmal, die Signatur dieser Funktion so wie in der ctypes-Dokumentation angegeben zu spezifizieren. Ohne wird implizit angenommen, dass die Argumente von C-Typ "int" sind.
-
- User
- Beiträge: 18
- Registriert: Montag 5. März 2012, 16:11
Viellen Dank erstmal für die Anwort.
Irgendwie stehe ich da auf dem Schlauch. Die dll an sich wird bei mir eingelesen, aber der Aufruf der Funktion klappt ja nicht. Aber in der Docu finde ich unter ctypes nicht unbedingt wie du das meinst mit dem deklarieren als andere Datentyp. Für die Inputvariablen A,B,C ist das kein Problem, aber für die Funktion finde ich nichts direkt.
Irgendwie stehe ich da auf dem Schlauch. Die dll an sich wird bei mir eingelesen, aber der Aufruf der Funktion klappt ja nicht. Aber in der Docu finde ich unter ctypes nicht unbedingt wie du das meinst mit dem deklarieren als andere Datentyp. Für die Inputvariablen A,B,C ist das kein Problem, aber für die Funktion finde ich nichts direkt.
-
- User
- Beiträge: 18
- Registriert: Montag 5. März 2012, 16:11
Hallo alle zusammen.
Bin der Sache näher gekommen. Ich kann nun die dll einlesen und die Funktion darin aufrufen.
Es rechnet zwar noch nicht richtig, aber denke das bekommt man auch noch hin.
Vom Syntax her sieht das nun wie folgt aus:
Wenn ich nun die definierte Funktion CP_ABC aufrufe,die entsprechenden inputparameter eingebe, dann rechnet er mir aber noch unsinn aus. wenn ich also z.B.
eingebe, erhalte ich als Lösung None . Es sollte aber eigentlich ein double heraus kommen. Hat da einer eine Ahnung woran das liegen kann?
Bin der Sache näher gekommen. Ich kann nun die dll einlesen und die Funktion darin aufrufen.
Es rechnet zwar noch nicht richtig, aber denke das bekommt man auch noch hin.
Vom Syntax her sieht das nun wie folgt aus:
Code: Alles auswählen
from ctypes import *
# give location of dll
Eth = windll.LoadLibrary("Eth.dll");
# call the functions in the dll
def CP_ABC(A,B,C):
A =c_double()
B=c_double()
C =c_double()
CP_ABC= Eth.CP_AB_Eth(byref(A),byref(B),byref(C))
Code: Alles auswählen
print CP_ABC(10,100,-1000)
Zuletzt geändert von Anonymous am Mittwoch 7. März 2012, 11:48, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
Grund: Quelltext in Python-Code-Tags gesetzt.
1. Bitte benutz Python code-tags, damit man das lesen kann
2. Du hast das immer noch nicht verstanden, wie du einer Funktion eine Signatur verpasst. Damit kann das ganze dann nicht funktionieren. Bitte erzaehl uns doch mal, wie genau die Funktion deklariert ist. Also in C zb sowas wie
Anhand dieser Signatur musst du dann ctypes mitteilen, wie die Parameter der Funktion auszusehen haben.
2. Du hast das immer noch nicht verstanden, wie du einer Funktion eine Signatur verpasst. Damit kann das ganze dann nicht funktionieren. Bitte erzaehl uns doch mal, wie genau die Funktion deklariert ist. Also in C zb sowas wie
Code: Alles auswählen
int do_somenthing(int a, int *b);
-
- User
- Beiträge: 18
- Registriert: Montag 5. März 2012, 16:11
Die Funktion ist wie gesagt Fortran 77 und vom Typ
es handelt sich also hierbei beim In- und Output um double Werte.
Code: Alles auswählen
REAL*8 FUNCTION CP_ABC_ETH (REAL*8 A,REAL*8 B, REAL*8 C)
@liddokun88: Deine `CP_ABC()`-Funktion gibt `None` zurück weil das alle Python-Funktionen machen, bei denen man nicht explizit etwas zurück gibt. Dafür gibt es die ``return``-Anweisung. Stell Dir einfach ein ``return None`` am Ende von jeder Funktionsdefinition vor. An der Stelle solltest Du vielleicht ein Python-Tutorial durcharbeiten für die Grundlagen.
Laut Fortran-Signatur erwartet die Funktion Argumente vom C-Typ `double`, Du übergibst in Deiner Funktion aber Werte vom C-Typ *Pointer auf `double`*.
Damit `ctypes` weiss wie die Argumente übergeben werden müssen und welchen Typ das Ergebnis hat, musst Du wie schon gesagt diese Informationen an die dafür vorgesehenen Attribute des Funktionsobjektes binden, das Du von der DLL abfragst. Siehe den Abschnitt in der Dokumentation, den ich weiter oben verlinkt habe und auch den darauf folgenden Abschnitt für den Typ des Rückgabewertes.
Laut Fortran-Signatur erwartet die Funktion Argumente vom C-Typ `double`, Du übergibst in Deiner Funktion aber Werte vom C-Typ *Pointer auf `double`*.
Damit `ctypes` weiss wie die Argumente übergeben werden müssen und welchen Typ das Ergebnis hat, musst Du wie schon gesagt diese Informationen an die dafür vorgesehenen Attribute des Funktionsobjektes binden, das Du von der DLL abfragst. Siehe den Abschnitt in der Dokumentation, den ich weiter oben verlinkt habe und auch den darauf folgenden Abschnitt für den Typ des Rückgabewertes.
-
- User
- Beiträge: 18
- Registriert: Montag 5. März 2012, 16:11
Ich habe mal versucht aus ctypes schlau zu werden. Wahrscheinlich ist das aber auch wieder total falsch.
Wäre nett wenn einer mal sagen könnte wie das den nun in meinem bsp. aussehen muss.
bei der Variante erhalte ich ebenfalls einen Fehler und zwar:
Wäre nett wenn einer mal sagen könnte wie das den nun in meinem bsp. aussehen muss.
Code: Alles auswählen
# call the functions in the dll
def CP_ABC(A,B,C):
CP = Eth.CP_ABC_Eth #name of function
CP.restype = c_double #deklaration output
CP.argtypes= [c_double,c_double,c_double] #deklaration input
CP = CP(p,t,x)
return CP
Code: Alles auswählen
File "C:\...\testfile", line 12, in CP_ABC
CP = CP(A,B,C)
WindowsError: exception: access violation reading 0x00000000
@liddokun88: Das sollte eigentlich richtig sein. Jetzt könnte es noch sein, dass die DLL eine andere Aufrufkonvention verwendet. Also das man sie mit `windll` statt `cdll` laden muss.
Oder die Parameterübergabe funktioniert bei Fortran ganz anders als bei C. Dann wäre ich ein wenig ratlos.
Bei Deinem Beispiel ist die Python-Funktion relativ nutzlos, weil man das erstellen des C-Types-Funktionsobjektes auch aus der Funktion heraus ziehen kann — das muss man ja nicht jedes mal aufs neue bei jedem Aufruf machen. Dann besteht die Python-Funktion nur noch aus einem weiterreichen der Argumente.
Etwas ungünstig ist es auch den selben Namen (`CP`) innerhalb einer Funktion für so grundverschiedene Dinge zu verwenden.
Oder die Parameterübergabe funktioniert bei Fortran ganz anders als bei C. Dann wäre ich ein wenig ratlos.
Bei Deinem Beispiel ist die Python-Funktion relativ nutzlos, weil man das erstellen des C-Types-Funktionsobjektes auch aus der Funktion heraus ziehen kann — das muss man ja nicht jedes mal aufs neue bei jedem Aufruf machen. Dann besteht die Python-Funktion nur noch aus einem weiterreichen der Argumente.
Etwas ungünstig ist es auch den selben Namen (`CP`) innerhalb einer Funktion für so grundverschiedene Dinge zu verwenden.
@liddokun88: Kurze Suche im Netz nach der Aufrufkonvention von Fortran (Suchanfrage „fortran77 library calling convention from c”) ergab als ersten Treffer folgende Seite: http://www.math.utah.edu/software/c-wit ... ence-diffs
Demnach muss man immer Pointer übergeben, auch auf skalare Werte. Ungetestet:
Demnach muss man immer Pointer übergeben, auch auf skalare Werte. Ungetestet:
Code: Alles auswählen
c_double_p = POINTER(c_double)
eth_lib = windll.LoadLibrary('Eth.dll') # oder `cdll`...
_cp_ab = eth_lib.CP_AB_Eth
_cp_ab.argtypes = [c_double_p, c_double_p, c_double_p]
_cp_ab.restype = c_double
def cp_abc(a, b, c):
a = c_double(a)
b = c_double(b)
c = c_double(c)
return _cp_ab(byref(a), byref(b), byref(c))
-
- User
- Beiträge: 18
- Registriert: Montag 5. März 2012, 16:11
Danke für die schnelle Nachricht. Hab das mal geändert so dass es nun wie folgt aussieht.
Als Rückgabewert erhalte ich
Was sagt mir das jetzt ?
Code: Alles auswählen
# import all functions from ctypes
from ctypes import *
# deklaration of double in/output
c_double_p = POINTER(c_double)
# give location of dll
Eth = windll.LoadLibrary("Eth.dll");
# call the functions in the dll
def CP_ABC(A,B,C):
_cp_ptx = Eth.CP_ABC_Eth #select function in dll
_cp_ptx.argtypes = [c_double_p,c_double_p,c_double_p] # input to double
_cp_ptx.restype = c_double_p
# change imput implicit to double
A = c_double(A)
B = c_double(B)
B = c_double(C)
# return value to console
return _cp_ptx(byref(A), byref(B), byref(C))
Code: Alles auswählen
_main__.LP_c_double object at 0x02983260>
Zuletzt geändert von liddokun88 am Donnerstag 8. März 2012, 14:24, insgesamt 1-mal geändert.
@liddokun88: Das sagt Dir dass `ctypes` versucht den Rückgabewert als „Pointer auf double” zu interpretieren, weil Du das fälschlicherweise so angegegen hast. `restype` muss nur `c_double` sein.
Und ich hätte ja einen `NameError` erwartet, weil den Namen `p`, `t`, und `x` nirgends etwas zugewiesen wird.
Und ich hätte ja einen `NameError` erwartet, weil den Namen `p`, `t`, und `x` nirgends etwas zugewiesen wird.
-
- User
- Beiträge: 18
- Registriert: Montag 5. März 2012, 16:11
ahhh endlich funktioniert es
Hattest recht mit dem c_double bei restype. Habe das geändert und alles geht.
Viellen Dank für die Hilfe
Hattest recht mit dem c_double bei restype. Habe das geändert und alles geht.
Viellen Dank für die Hilfe
-
- User
- Beiträge: 18
- Registriert: Montag 5. März 2012, 16:11
als nachtrag nochmal eine Frage,
wie kann ich dem Algorithmus sagen, das der input C z.B. ein Array sein muss ?
Also angenommen C ist ein double Array mit 8 Argumenten, wie müsste ich das Argument C dann ändern?
wie kann ich dem Algorithmus sagen, das der input C z.B. ein Array sein muss ?
Also angenommen C ist ein double Array mit 8 Argumenten, wie müsste ich das Argument C dann ändern?
@liddokun88: Arraytypen werden bei `ctypes` mit dem ``*``-Operator erzeugt.
Code: Alles auswählen
In [1]: import ctypes as ct
In [2]: ct.c_double * 8
Out[2]: <class '__main__.c_double_Array_8'>
-
- User
- Beiträge: 18
- Registriert: Montag 5. März 2012, 16:11
Ich stehe heute auf dem Schlauch, wie soll das nun aussehen?
meinst du das so in der Richtung?
Code: Alles auswählen
from ctypes import *
c_double_p = POINTER(c_double)
test = windll.LoadLibrary("test.dll");
# call the functions in the dll
def A(B,C): # wobei C ein double array mit 8 argumenten ist
A = test.A_BC #select function in dll
A.argtypes = [c_double_p,ctypes.c_double * 8] # input to double
A.restype = c_double_p
B = c_double(B)
# return value to console
return A(byref(B), byref(class '__main__.c_double_Array_8'))
Das ist doch noch nicht mal gueltiges Python.
Es steht in der ctypes-Doku wie man Array-Typen anlegt, und damit arbeitet um konkrete Arrays und Referenzen darauf zu erzeugen.
http://python.net/crew/theller/ctypes/t ... tml#arrays
Es steht in der ctypes-Doku wie man Array-Typen anlegt, und damit arbeitet um konkrete Arrays und Referenzen darauf zu erzeugen.
http://python.net/crew/theller/ctypes/t ... tml#arrays