LabView dll in Python einbinden

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
HarryPython
User
Beiträge: 60
Registriert: Freitag 8. Juni 2007, 07:39

Hi

Ich hab mal wieder eine schöne ctypes Aufgabe. :roll:

Ich hab in LabView ein einfaches Beispiel erstellt. Die addition von zwei Zahlen. "Zahl1" als Eingabewert, "Zahl2" als Festwert und ein "Ergebnis" als Ausgabewert. Aus diesem Programm hab ich dann eine dll erstellt, wo ich auch "Zahl1" und "Ergebnis" in der dll veröffentlich hab. Fein nach Anleitung. Ich denke das sollte alles richtig sein.

Nun möchte ich an die dll einen Wert für "Zahl1" übergeben und "Ergebnis" wieder auslesen.

Hier einmal die Anleitung von der NI Seite für C++:

Code: Alles auswählen

To dynamically load the DLL, you must define function types and function 
pointers for all the functions in the DLL. You then load the DLL into 
memory when necessary using the LoadLibrary function. After loading the
 DLL, use the GetProcAddress function to obtain the addresses of the 
functions. After you call all the functions, unload the DLL using the 
FreeLibrary function.

Aus dem ctypes Tutorial hab ich zwei Ansätze erstellt, wobei der 2.Ansatz wahrscheinlich besser ist wegen:"you must define function types and function pointers for all the functions in the DLL"

Ansatz1:

Code: Alles auswählen

from ctypes import *


dll = cdll.LoadLibrary("addition.dll")

Funk = getattr(dll, "Addition")
print Funk
Ansatz2:

Code: Alles auswählen

from ctypes import *


dll = cdll.LoadLibrary("addition.dll")


class struct_frozen(Structure):
      _fields_ = [("Zahl1", c_int),
                   ("Ergebnis", c_int)]

FrozenTable=POINTER(struct_frozen)
opt_flag=FrozenTable.in_dll(dll, "Addition")

Also meine Funktion heißt Addition. Das läuft so weit auch schon und ich bekomme keine Fehlermeldung zurück. Aber wie komme ich jetzt an das Ergebnis bzw kann ein Wert in Zahl1 an die dll übergeben???????


Kann mir da jemand weiterhelfen?

Danke :D

mfg
HarryPython
BlackJack

Wie sieht denn die Funktion aus? Was erwartet sie? Was gibt sie zurück? Deine Beschreibung jedenfalls ziemlich wirr.
HarryPython
User
Beiträge: 60
Registriert: Freitag 8. Juni 2007, 07:39

Hi Black.


Findst du? :lol:
Wie sieht denn die Funktion aus? Was erwartet sie? Was gibt sie zurück?
ein addition zweier Zahlen, eine "Zahl1", ein "Ergebnis"



Hab das hier unter LabView "VI Prototype Definition" gefunden

Code: Alles auswählen

void Addition(long Zahl1, double *Ergebnis)
und mein Structure auch schon geändert.

Code: Alles auswählen

class struct_frozen(Structure):
      _fields_ = [("Zahl1", c_long),
                   ("Ergebnis", POINTER(c_double))]
Außerdem wird beim Erzeugen der dll auch eine .h Datei erstellt. In der dann das steht:

Code: Alles auswählen

#include "extcode.h"
#pragma pack(push)
#pragma pack(1)

#ifdef __cplusplus
extern "C" {
#endif

double __stdcall Addition(long Zahl1, double *Ergebnis);

long __cdecl LVDLLStatus(char *errStr, int errStrLen, void *module);

#ifdef __cplusplus
} // extern "C"
#endif

#pragma pack(pop)

Gruß
Harry
BlackJack

Ja ich finde die Beschreibung wirr. Zum Beispiel ist mir immer noch nicht klar welche Zahlen addiert werden. `Zahl1` und `Ergebnis`? Dann ist das aber ein bescheidener Name für das zweite Argument.

Aber die Deklaration in der Header-Datei ist wenigstens eine handfeste, klare Information:

Code: Alles auswählen

from ctypes import byref, CDLL, c_long, c_double, POINTER


def main():
    dll = CDLL('./_test.so')
    addition = dll.Addition
    addition.argtypes = (c_long, POINTER(c_double))
    addition.restype = c_double
    print addition(42, byref(c_double(47.11)))
Das sollte man vielleich in eine Python-Funktion kapseln um nicht bei jedem Aufruf dieses `byref(c_double(…))`-Tänzchen hinschreiben zu müssen.

Und wozu brauchst Du jetzt das `struct`!?
HarryPython
User
Beiträge: 60
Registriert: Freitag 8. Juni 2007, 07:39

Hi Black,


danke für die Antwort. Also Ergebnis als zweite Zahl wäre echt besch... :lol:

Die addition von zwei Zahlen. "Zahl1" als Eingabewert, "Zahl2" als Festwert und ein "Ergebnis" als Ausgabewert.
Damit wollte ich sagen, dass "Zahl2" eine Konstante im LabView Programm ist, auf die man keinen Einfluss hat. Somit werden"Zahl1" und "Zahl2" addiert und "Ergebnis" ist natürlich das Ergebnis. :wink:

Mit dem struct wollte ich die Variablen in meiner Funktion ansprechen. Hab das Beispiel in dem ctypes Tutorial gefunden. War wohl nicht die beste Lösung. :?

Aber hast Recht, man kann es echt falsch verstehen. Ich wollte "Ergebnis" mit übergeben, damit meine Funktion die Variable mit der Summe von "Zahl1" und "Zahl2" füllt. Aber ich hab jetzt bei LabView gefunden, wie man "Ergebnis" als Rückgabewert deklarieren kann. Jupi

Danke für das Code Beispiel. Das sieht richtig gut aus. Werd ich gleich ausprobieren.
HarryPython
User
Beiträge: 60
Registriert: Freitag 8. Juni 2007, 07:39

DANKE BlackJack !!!

Hier nun die Lösung:


Ich hab im LabView unter "VI-Prototyp definieren" dem return value mein "Ergebnis" zugewiesen und "Zahl1" als Eingabe-Parametertyp hinzugefügt.


Dadurch ergibt folgender Funktionsprototyp:

Code: Alles auswählen

double Addition(long Zahl1)

Python Lösung:

Code: Alles auswählen

from ctypes import byref, c_long, c_double, POINTER, windll


def main():
    dll = windll.LoadLibrary("addition.dll")
    addition = dll.Addition
    addition.argtypes = [c_long]
    addition.restype = c_double
    print addition(34)

main()

CDLL liefert bei mir den Fehler:

Code: Alles auswählen

    print addition(34)
ValueError: Procedure called with not enough arguments (4 bytes missing) or wrong calling convention
Der vollständigkeits halber: Kann jemand was dazu sagen??


mfg
HarryPython
Zuletzt geändert von HarryPython am Freitag 26. Oktober 2007, 13:50, insgesamt 1-mal geändert.
BlackJack

Hm, was für einen Rechner hast Du denn? 32 oder 64 Bit? Und passen Python und LabView bzw. Deine DLL da zusammen?
HarryPython
User
Beiträge: 60
Registriert: Freitag 8. Juni 2007, 07:39

32 Bit.

Damit man die dll laden kann, muss man die passende LabView Runtime Engine installieren.
BlackJack

Ach ich habe gerade gesehen das Du gar kein Problem hast mit `windll`. Hatte ich glatt überlesen. Der Unterschied ist, wie die Fehlermeldung ja schon nahelegt, dass es mehrere Aufrufkonventionen gibt, also was wer wie bei einem Aufruf einer Funktion auf den Stack packt und nach dem Aufruf wieder entfernt.
HarryPython
User
Beiträge: 60
Registriert: Freitag 8. Juni 2007, 07:39

Nachtrag:

Bei der Dokumentation meines Programms ist mir die CDLL und windll noch einmal aufgefallen, sowie der Beitrag von BlackJack. Es geht genau um diese Stack Geschichte.

In LabView hat man beim Erstellen einer dll die Auswahl zwischen der Standard-Aufrufkonvention (stdcall) und der C-Aufrufkonvention (cdecl). Je nachdem wie man sich hier entscheidet, muss auch der Aufruf der dll in Python geschehen.

Bei cdecl muss man die dll mit CDLL aufrufen und bei stdcall mit windll. Es sind also beide Wege möglich.

Hintergrund:
Bei stdcall bereinigt die aufgerufene Funktion den Stack, bei cdecl die Aufrufende.

Gruß
HP
Antworten