LabVIEWForum.de
Einbinden externen Code mit unbekannter Parameterstruktur - Druckversion

+- LabVIEWForum.de (https://www.labviewforum.de)
+-- Forum: LabVIEW (/Forum-LabVIEW)
+--- Forum: LabVIEW Allgemein (/Forum-LabVIEW-Allgemein)
+---- Forum: DLL & externer Code (/Forum-DLL-externer-Code)
+---- Thema: Einbinden externen Code mit unbekannter Parameterstruktur (/Thread-Einbinden-externen-Code-mit-unbekannter-Parameterstruktur)

Seiten: 1 2


Einbinden externen Code mit unbekannter Parameterstruktur - ghostwhisperer - 16.12.2009 10:40

Hallo ! Ich weiss einfach nicht weiter und finde bislang auch hier kein passendes Thema...

Ich möchte Funktionen einer API einbinden, die für die Ansteuerung von Lichtschnittkameras geschrieben wurde.
Nun funktionierte von Anfang an nichtmal die Initialisierung der Kamera, da diese die Instanz eines sehr kompliziert aufgebauten Handlers erfordert.
Hab mir vom Händler eine API-Zusatzfunktion schreiben lassen, die die Instanzierung selbst vornimmt und mir "nur" den Zeiger auf die Datenstruktur
zurückgeben sollte. Das alles, damit ich in LabVIEW nicht alles neu programmieren muss, da der Aufwand ernorm wäre (Instanz einer Struktur mit unendlich vielen weiteren Unter-Strukturen).

Mich interessiert weder der Aufbau des Handlers noch der Inhalt. Ich muss nur den Zeiger auf den Handler an die Funktionen zur Kamerasteuerung weitergeben könnnen.

Und genau das schaff ich nicht. der Funktionsaufruf sieht so aus:

int LIBCALL SR_API_SetupCam ( Camdesc* cd1, Param* pars1)

Hab die Konfiguration des Knotens schon zigmal durchprobiert. Unter den vielen Möglichkeiten find ich einfach nicht die richtige....
Müsste doch eigentlich als Zeiger ein uint32 mit Übergabe "Zeiger auf wert" reichen oder nicht? Zeiger heisst doch einfach (Start-)Adresse im Speicher der Struktur-Instanz???? Bekomme aber immer das zurück, was ich auch reingebe, nämlich nen Nullpointer.

Wenn ich void* nehme funktioniert auch nix. Cstring-pointer, Arrayzeiger usw generieren LV-Abstürze.
Was ist eigentlich der Unterschied zwischen "Zeiger durch Wert" und "Zeiger in Handles" ??? Mich verwirrt das alles nur.

HILFÄÄ

Wer weiss Rat ??

MFG Torsten


Einbinden externen Code mit unbekannter Parameterstruktur - Y-P - 16.12.2009 10:54

Scheint eine Frage für "rolfk" oder "IchSelbst" zu sein. Big Grin
Was anderes: Ist LabVIEW 6.1 echt noch Deine aktuelle Version? Wenn nicht, dann bitte Profil_ergaenzen

Gruß Markus


Einbinden externen Code mit unbekannter Parameterstruktur - ghostwhisperer - 16.12.2009 11:26

Hallo !
Ich ARBEITE mit LV2009. War nur ewig nicht im Forum.
Keine Ahnung wie ich vorgehen muss?
Hab eben was über Zeiger und Referenzen in C++ gelesen. Jetzt bin ich doppelt verwirrt. Was habe ich denn hier nun??


' schrieb:Scheint eine Frage für "rolfk" oder "IchSelbst" zu sein. Big Grin
Was anderes: Ist LabVIEW 6.1 echt noch Deine aktuelle Version? Wenn nicht, dann bitte Profil_ergaenzen

Gruß Markus



Einbinden externen Code mit unbekannter Parameterstruktur - rolfk - 16.12.2009 13:19

' schrieb:Und genau das schaff ich nicht. der Funktionsaufruf sieht so aus:

int LIBCALL SR_API_SetupCam ( Camdesc* cd1, Param* pars1)

Hab die Konfiguration des Knotens schon zigmal durchprobiert. Unter den vielen Möglichkeiten find ich einfach nicht die richtige....
Müsste doch eigentlich als Zeiger ein uint32 mit Übergabe "Zeiger auf wert" reichen oder nicht? Zeiger heisst doch einfach (Start-)Adresse im Speicher der Struktur-Instanz???? Bekomme aber immer das zurück, was ich auch reingebe, nämlich nen Nullpointer.

Wenn ich void* nehme funktioniert auch nix. Cstring-pointer, Arrayzeiger usw generieren LV-Abstürze.
Was ist eigentlich der Unterschied zwischen "Zeiger durch Wert" und "Zeiger in Handles" ??? Mich verwirrt das alles nur.

Das ist zwar ein Pointer aber nicht einer der von der DLL zurückgegben wird sondern der vom Aufrufer bereitgestellt wird. Auch wenn Du den Inhalt dieses Pointers in LabVIEW nicht anschauen willst musst Du der Funktion halt schon einen Speicherbereich zur Verfügung stellen in den sie schreiben darf. Am einfachsten geht das mit Initialize Array indem du ein U8 Array erzeugst. Dann noch die richtige Länge in Bytes herausfinden und den entsprechenden Parameter in der Call Library Node als C Array Pointer konfigurieren und alles sollte soweit in Ordnung sein.


Einbinden externen Code mit unbekannter Parameterstruktur - ghostwhisperer - 16.12.2009 14:22

Hallo und Danke erstmal.
Eigentlich stellt die Funktion der DLL schon einen speicherbereich zur Verfügung. Alle weiteren Funktionen brauchen als parameter nur "*camdesc". Dieser Parameter wird ja tatsächlich im Header der DLL beschrieben und nur von der DLL verwendet.
Reicht die Startadresse da wirklich nicht aus?
Ich habs mal mit dem u8 array probiert. Bekomme immer noch Nullwerte, wenn ich mir das Ausgangsarray betrachte. Oder liegt das nur an der falschen länge?
Andere Frage : wirklich u8? Ich dachte heut wird alles mit 32 bit adressiert.

MFG Torsten

' schrieb:Das ist zwar ein Pointer aber nicht einer der von der DLL zurückgegben wird sondern der vom Aufrufer bereitgestellt wird. Auch wenn Du den Inhalt dieses Pointers in LabVIEW nicht anschauen willst musst Du der Funktion halt schon einen Speicherbereich zur Verfügung stellen in den sie schreiben darf. Am einfachsten geht das mit Initialize Array indem du ein U8 Array erzeugst. Dann noch die richtige Länge in Bytes herausfinden und den entsprechenden Parameter in der Call Library Node als C Array Pointer konfigurieren und alles sollte soweit in Ordnung sein.



Einbinden externen Code mit unbekannter Parameterstruktur - rolfk - 16.12.2009 14:37

' schrieb:Hallo und Danke erstmal.
Eigentlich stellt die Funktion der DLL schon einen speicherbereich zur Verfügung. Alle weiteren Funktionen brauchen als parameter nur "*camdesc". Dieser Parameter wird ja tatsächlich im Header der DLL beschrieben und nur von der DLL verwendet.
Reicht die Startadresse da wirklich nicht aus?
Ich habs mal mit dem u8 array probiert. Bekomme immer noch Nullwerte, wenn ich mir das Ausgangsarray betrachte. Oder liegt das nur an der falschen länge?
Andere Frage : wirklich u8? Ich dachte heut wird alles mit 32 bit adressiert.

MFG Torsten

Also da ich nicht die ganze Headerdatei sehen kann muss ich hier natürlich Vermutungen machen aber die Deklaration

int LIBCALL SR_API_SetupCam ( Camdesc* cd1, Param* pars1)

lässt halt die Vermutung aufkommen dass es zwar ein Pointer ist aber eben nicht einer der von der DLL kommt. Das darum weil Camdesc und Param ziemlich sicher struct Deklarationen sind und nicht Pointer darauf. Also so was wie:

typedef struct {
sometype elm1;
sometype elm2;
.....
} Camdesc;

und nicht:

typedef struct {
sometype elm1;
sometype elm2;
.....
} *Camdesc;

Das heisst cd1 und pars1 sind zwar Pointer auf eine Struktur aber eben nicht Pointer die aus der DLL herauskommen. In C kann man nur Werte in einem Parameter zurückgeben indem man diesen Parameter als Referenz verwendet. Wenn die DLL also den Pointer zurückgeben wollte müsste der Pointer als Referenz übergeben werden was so aussehen würde:

int LIBCALL SR_API_SetupCam ( Camdesc* *cd1, Param* *pars1)

Da das wahrscheinlich hier nicht der Fall ist muss LabVIEW den entsprechenden Buffer bereitstellen.

Was den Inhalt der Struktur angeht, da können durchaus viele Nullen drin sein. Ich weiss ja nicht was da alles drinsteht aber warum den nicht auch Nullen?

Ob das Array nun U8 oder U32 ist macht nicht soviel aus. Die Struktur selber wird eh nicht alles U8 oder U32 enthalten und Du sagtest ja selber dass Du am Inhalt des Pointers selber nicht interessiert bist. Bei Verwendung von U8 musst Du einfach soviele Elemente allozieren als die Struktur in Bytes lang ist, bei Verwendung von U32 reicht es (Länge + 3 MOD 4) Elemente anzulegen.


Einbinden externen Code mit unbekannter Parameterstruktur - ghostwhisperer - 16.12.2009 15:47

Sorry hab mich wohl zu knapp ausgedrückt.

In einem hast recht, das sind Strukturen mit Ints, Strings, Arrays, weiteren Pointern usw drin.

Der generelle Programm-Ablauf soll zb so aussehen.

Int SR_API_Init (void) //Init der Kamera-Api
Int SR_API_SetupCam ( Camdesc* cd1, Param* pars1) // instanziert 1* Camdesc und 1*Parameter mit standardwerten Rückgabe sollen Pointer auf Instanzen sein
Int SR_API_StartCamConMan (Camdesc* cd1) // versucht Verbindung zur Kamera herzustellen, die im Camdescriptor beschrieben ist
Str SR_API_GETIP (Camdesc* cd1) // Beispiel: Kontrolle der IP der Kamera
...
INT SR_API_StopCamConMan (Camdesc* cd1) // schließt Kamera-Connection
Int SR_Api_Exit(void) // beendet Api

Mehr kann ich hier leider nicht sagen, da ich den Quellcode nicht hab. Der Programmierer der Firma ist sich eigentlich sicher, dass für die Ausführung aller Kamerafunktionen der Adresspointer auf den extern angelegten Speicherbereich für Camdesc ausreichend ist. Ich kriegs nur nicht in LabVIEW hin.

' schrieb:Also da ich nicht die ganze Headerdatei sehen kann muss ich hier natürlich Vermutungen machen aber die Deklaration
int LIBCALL SR_API_SetupCam ( Camdesc* cd1, Param* pars1)
lässt halt die Vermutung aufkommen dass es zwar ein Pointer ist aber eben nicht einer der von der DLL kommt. Das darum weil Camdesc und Param ziemlich sicher struct Deklarationen sind und nicht Pointer darauf. Also so was wie:
typedef struct {
sometype elm1;
sometype elm2;
.....
} Camdesc;
und nicht:
typedef struct {
sometype elm1;
sometype elm2;
.....
} *Camdesc;
Das heisst cd1 und pars1 sind zwar Pointer auf eine Struktur aber eben nicht Pointer die aus der DLL herauskommen. In C kann man nur Werte in einem Parameter zurückgeben indem man diesen Parameter als Referenz verwendet. Wenn die DLL also den Pointer zurückgeben wollte müsste der Pointer als Referenz übergeben werden was so aussehen würde:
int LIBCALL SR_API_SetupCam ( Camdesc* *cd1, Param* *pars1)
Da das wahrscheinlich hier nicht der Fall ist muss LabVIEW den entsprechenden Buffer bereitstellen.
Was den Inhalt der Struktur angeht, da können durchaus viele Nullen drin sein. Ich weiss ja nicht was da alles drinsteht aber warum den nicht auch Nullen?
Ob das Array nun U8 oder U32 ist macht nicht soviel aus. Die Struktur selber wird eh nicht alles U8 oder U32 enthalten und Du sagtest ja selber dass Du am Inhalt des Pointers selber nicht interessiert bist. Bei Verwendung von U8 musst Du einfach soviele Elemente allozieren als die Struktur in Bytes lang ist, bei Verwendung von U32 reicht es (Länge + 3 MOD 4) Elemente anzulegen.



Einbinden externen Code mit unbekannter Parameterstruktur - rolfk - 17.12.2009 08:44

Ich denke dass der Programmierer voll recht hat. Wo's happert sind Deine C Kenntnisse und speziell was Pointer sind. Die Funktion Int SR_API_SetupCam() schreibt zwar Informationen in die Speicherbuffer den Du als cd1 und pars1 übergibt, legt aber diese Bereiche nicht selber an. Dass muss der Aufrufer. Da Du sagst dass da Pointer drin sind ist das schon mal nichts was Du mit LabVIEW selber machen kannst.

Deine Optionen sind folgende:

1) Berechnen der Bytegrösse dieser Strukturen. Dabei auch auf Alignment achten. Alignment besagt das ein Struktureelement immer auf einem Vielfachen der kleineren der beiden Werte Elementgrösse und Alignmentsetting ist. Bei Visual C DLLs ist das Aligment default auf 8 Byte eingestellt, kann aber in den Projecteinstellungen oder mittels pragmas vor den entsprechenden Deklarationen jederzeit verändert werden. Wenn Du diese Grösse hast ein entsprechendes Array mit sovielen Elementen met Intilialize Array anlegen und diesen Funktionen übergeben. Dabei macht es nichts aus dass die Funktion eine Struktur erwartet und Du ihr ein Array übergibst. Solange nur der Speicherbereich den das Array belegt gross genug ist um die ganze Struktur abzudecken. Dass Du die Information innerhalb des Arrays nicht einfach interpretieren kannst da es nicht mit dem Strukturlayout übereinstimmt ist ja nach Deiner eigenen Aussage kein Problem. Bei allen Funktionen wo dieser Buffer übergeben werden muss, wird der entsprechende Parameter dann als Array konfiguriert und als C Array Pointer.

2) Du baust Dir einen entsprechenden Cluster in LabVIEW der genau mit der Struktur in C übereinstimmt. Auch hier musst Du auf das Alignment der Library achten. LabVIEW macht nie Alignment, also packt die Daten immer so kompakt als möglich. Das kann bedeuten dass man in den Cluster sogenannte Fillerbytes einfügen muss um die Elementgrenzen auf die selben Offsets zu kriegen wie in der C Struktur. Pointer kannst Du auf diese Weise nicht wirklich anlegen aber Du kannst sie als 32Bit Integer in 32 Bit LabVIEW oder 64Bit Integer in 64 Bit LabVIEW in den Cluster legen und auch hier natürlich auf das Alignment achten. Du siehst dann im Cluster den Wert des Pointers in der Integerzahl aber natürlich nicht den Inhalt und solange das nicht absolut mit aller Macht nötig ist lassen wir das bitteschön so, da ich vermute dass Du wahrscheinlich jetzt schon nicht mehr durchblickst. Diesen Cluster kannst Du dann an die Funktion übergeben indem Du den Parameter als Adapt to Source einstellst wonach LabVIEW einen Pointer auf diesen Cluster an die Funktion übergibt.

Dies ist so ein bischen die ausführlichste Erklärung die ich geben kann ohne die ganze Arbeit ganz für Dich zu machen (was ohne die Headerdateien sowieso nicht möglich ist). Bei Variante 1 kannst Du eventuel wegkommen mit einer groben Schätzung der Bufferlänge für die Struktur und dann noch eine Sicherheitsmarge hinzufügen um für extra Alignment Bytes Rechnung zu tragen. So oder so wirst Du dich ein wenig mit C Syntax und Datentypen, und deren Speichergrösse abgeben müssen.


Einbinden externen Code mit unbekannter Parameterstruktur - IchSelbst - 17.12.2009 09:00

' schrieb:Mich interessiert weder der Aufbau des Handlers noch der Inhalt. Ich muss nur den Zeiger auf den Handler an die Funktionen zur Kamerasteuerung weitergeben könnnen.
Wenn ich das richtig interpretiere, bekommst du von der Funktion also lediglich zwei Pointer zurück. Man hätte - da es dich nicht interessiert, wie die jeweiligen Cluster ausfgebaut sind - den Prototypen auch machen können als "Int SR_API_SetupCam (int* MyIntVar1, int* MyIntVar2)". Wobei INT hier missbraucht wird als Zwischenspeicher für einen Pointer. Der Wert von MyIntVar2 interessiert dich überhaupt nicht. Lediglich MyIntVar1 musst du an die anderen Funktionen übergeben.

[*grübel*]
Für was brauchst du denn dann die DLL, wenn du nie Daten heraus liest ? Hat die ein eigenes "Frontpanel"?
[/*grübel*]

Sehe ich das richtig?



Wenn dem so ist, müsstest du lediglich im DLL-Knoten angeben: Typ UI32, Zeiger auf Wert. Für Int SR_API_SetupCam zweimal, für alle anderen einmal.


Einbinden externen Code mit unbekannter Parameterstruktur - ghostwhisperer - 17.12.2009 11:39

Hallo !!
Richtich 2 Pointer. Die DLL umfasst alle Funktionen zur Kamerasteuerung, die ich brauche. Aber alle anderen Funktionen funzen erst, wenn der Handler einwandfrei ist. Diese SetupCam hat der Mann der Firma extra dafür geschrieben, dass ich die Riesenhandler für die Kamerasteuerung eben nicht selber in LV rekonstruieren muss. Müsste ich eigentlich um die anderen Funktionen überhaupt nutzen zu können.
Ich hab da noch ne Messkarte die ohne Probleme funktioniert. Ist ähnlich aufgebaut: importierte DLL-Funktionen. Hier ist es so, dass zB DIO_Config auch einen Handler instanziert aber nur das int "taskid" zurückgibt. Das ist, wenn ich das richtig verstehe, ein Pointer (also inhalt = speicheradresse) auf den Messkarten-Handler.
Hier steht aber, genau wie du auch grad grübelst, wirklich nur ein uint32 T *taskid, und eben nicht *structure (welcher Art auch immer) und das ganze als "Zeiger auf Wert". Genau prüfen kann ich das leider nicht, da ich hier nur die DLL hab und weder Header noch Quellcode.

Der Herr von Smartray meint nun Camdesc* cd1 gibt mir die Adresse raus.
Wenn ich das aber mit uint und zeiger auf Wert versuche geht gar nix.

Rolfk meint ja, dass cd1 und pars1 zwar Pointer auf eine Struktur sind aber eben nicht Pointer die aus der DLL herauskommen. Und in C kann man nur Werte in einem Parameter zurückgeben indem man diesen Parameter als Referenz verwendet.

Der Herr von Smartray hat entgegengesetzt gemeint, das wäre nicht so. Woher die Unstimmigkeit? Was gibt mir der Funktionsaufruf denn nun? Muss der so umgeschrieben werden, dass wirklich ein int bzw int* rauskommt? Kann ich die Kamerafunktionen dann denn noch ungeändert nutzen? die Erwarten ja *Camdesk und kein Int. Oder hat nur LabVIEW das Problem sowas wie Adressoperatoren usw eigentlich nicht zu kennen? Mit anderen Worten, angenommen ich krieg meinen uint32bitzeigerinhaltadresse aus der Setup, versteht der nächste Funktionsaufruf dessen Inhalt dann richtig ? Nämlich als Adresse der Instanz und eben nicht als einfachen Int und infolge als falschen Variablentyp.

Wenn das alles nicht gehen sollte.... Der Mann schreibt grad an der Api so rum, dass ich die Kamerafunktionen ganz ohne Handler nutzen kann. Der wird dann per ApiStart instanziert und verkapselt und im übrigen als globale Variable übergeben. Ich krieg dann einfach ne Schnittstelle zum Ändern oder Lesen von Inhalten des Handlers.

MFG Torsten

' schrieb:Wenn ich das richtig interpretiere, bekommst du von der Funktion also lediglich zwei Pointer zurück. Man hätte - da es dich nicht interessiert, wie die jeweiligen Cluster ausfgebaut sind - den Prototypen auch machen können als "Int SR_API_SetupCam (int* MyIntVar1, int* MyIntVar2)". Wobei INT hier missbraucht wird als Zwischenspeicher für einen Pointer. Der Wert von MyIntVar2 interessiert dich überhaupt nicht. Lediglich MyIntVar1 musst du an die anderen Funktionen übergeben.

[*grübel*]
Für was brauchst du denn dann die DLL, wenn du nie Daten heraus liest ? Hat die ein eigenes "Frontpanel"?
[/*grübel*]

Sehe ich das richtig?
Wenn dem so ist, müsstest du lediglich im DLL-Knoten angeben: Typ UI32, Zeiger auf Wert. Für Int SR_API_SetupCam zweimal, für alle anderen einmal.