' schrieb:Danke Rolf, hat sich einfach angehört. Klappt aber logischerweise nicht, da dann die Datentypen nicht zusammenpassen.
[attachment=36545:Screecshot1.jpg]
Auch hätte ich da Bedenken, dass die dll damit zurecht kommt. Die erwartet doch einen Pointer auf die angegebene Struktur!? Aber ich bin kein C-Freak..
Ebenso wird doch dann der Returnwert nicht passen. Da sollten die Daten dann in der definierten Struktur/Cluster vorhanden und verwendbar sein.
Cluster sind etwas lästig, aber C technisch ist es auch nur ein Speicherbereich einer bestimmten Anzahl Bytes und als Funktionsparameter wird da eben auch nur ein Pointer auf diesen Speicherbereich übergeben. Das Lästige an Clustern sind zweierlei Dinge. Erstens wenn Du Pointers in der Struktur hast. Das kann LabVIEW so nicht tun. Wenn es dagegen ein fixed size Array ist werden alle Bytes dieses Arrays innerhalb der Struktur selber embedded, d.h. die Struktur wird um soviele Bytes länger.
Das lästigere Problem ist Padding. Für bestimmte Prozessorarchitecturen ist es SEHR nachteilig wenn ein Programm eine Variable im Speicher ansprechen will, die nicht auf einer Adresse beginnt die ein Vielfaches der Grösse dieser Variablen ist. Das heisst z.B. wenn Du eine double Fliesskommazahl hast (8 Bytes im Speicher) sollte die auf einer Adresse im Specher liegen die ohne Rest durch 8 teilbar ist. Auf x86 Prozessoren hält sich der extra Aufwand um so eine Specherstelle anzusprechen in Grenzen, da er ja ohnehin immer noch eine 8bit Vergangenheit mitschleppt. Sparc um nur ein Vorbild zu nennen braucht dazu aber eine Vielzahl der Taktzyklen die ein korrekt aligned Operand benötigen würde.
Wenn man also ein Programm kompiliert, gibt man das Padding als Compileroption mit an, oder fügt eine entsprechende #pragma Anweisung in den C source code. Der auf diese Weise an den Compiler mitgegebene Paddingparameter bestimmt wie der Compiler die verschiedenen Datentypen im Speicher anordnet. Dabei gilt dass ein Operand immer auf einer Adresse angelegt wird die ein ganzzahliges Vielfaches des kleineren der zwei Werte Operandsize und Padding ist. Wenn das Padding 8 ist (der Default für Visual C 32 Bit) dann wird ein Word (16 Bit) also immer auf einer geraden Adresse liegen, ein Long (32 Bit) auf einer durch 4 teilbaren Adresse und ein Double (8 Byte Fliesskommazahl) auf einer durch 8 teilbaren Adresse. Nicht benützte Bytes die auf diese Weise durch den Compiler in die Struktur eingefügt werden, nennt man Paddingbytes oder Fillbytes und sind ohne krumme C Tricks gar nicht ansprechbar.
Unter Windows kann man also davon ausgehen, dass die meisten DLLs ein 8 Byte Padding benützen. Ob das aber bei einer bestimmten DLL so ist muss aus der Dokumentation hervorgehen oder kann eventuel anhand der #pragma Anweisung aus dem Headerfile ersehen werden.
Aber: LabVIEW verwendet aus historischen Gründen unter Windows ein 1 Byte Padding für seine Speicherstrukturen und damit auch für Clusters. Das heisst die Clusters sind immer packed und ohne Fillbytes. An sich ist das keine Katastrophe, mit einem packed Compiler kann man padded Strukturen immer nachbilden, umgekehrt ginge aber nicht. Man muss beim Aufbau der Cluster in LabVIEW einfach aufpassen, dass man diese Fillbytes expliziet mit in den Cluster einbaut, bevor man den Cluster an die Call Library Node gibt.
Im Falle eines Clusters der keine String oder Arraykontrolls enthält ist übrigens die Verwendung des "Pass Native Datatype" die einfachste Weise um doch einen C kompatible structure zu erhalten. Man muss einfach aufpassen dass das Speicherlayout des Clusters mit dem übereinkommt was die DLL als structure erwartet.
ABER: das gilt wirklich nur für flache Cluster. Sobald ein LabVIEW Array oder String in irgendeiner Weise direkt als CLN Parameter oder indirekt in einem Cluster der als CLN Parameter benützt wird vorkommt, ist "Pass als Native Datatype" in 99.999999% der Fälle garantiert falsch!!!!!
Alternativ kann man auch ein genügend grosses Bytearray anlegen in LabVIEW, die entsprechenden Daten vor dem Aufruf da am richtigen Offset hineinbasteln, und nach dem Aufruf die gewünschten Daten am richtgen Offset innerhalb des Arrays wieder herausbasteln. Das ist aber supermühselig und nur in sehr seltenen Fällen sinnvoll (aber war in älteren LabVIEW Versionen die noch kein "Pass native Datatype" hatten die einzige Variante um keine Wrapper DLL schreiben zu müssen).
Zu Deinem Problem selbst, für einen Cluster also "Pass Native Datatype" gebrauchen (aber bitte nur wenn da keine Strings oder Arrays drin sind).
Die Alternative ist um den Cluster zu Typecasten. Das hat aber den Nachteil das Typecast immer einen Big Endian Transformation durchführt und Deine x86 DLL Little Endian Zahlen im Cluster erwartet. Abhilfe ist um den Cluster für VIs die unter einem x86 OS laufen müssen erst mit Swap Bytes and Swap Words zu verkehren, so dass die Big Endianisierung des Typecasts wieder ungeschehen gemacht wird.
Oder seit LabVIEW 8.0 kann man einfach Flatten To String verwenden und dort selektiert man dann die gewünschte Endianess. Aber diesen String sollte man nicht als C String Pointer an die CLN übergeben, wenn man ihn nach dem Aufruf wieder in einen Cluster Unflatten möchte um die darin enthaltenen Daten auszuwerten, da LabVIEW bei der Rückkehr diesen String beim ersten Nullbyte abkappt. Also zuerst in ein Bytearray verwandeln, dann an die CLN als Arraypointer auf U8 übergeben, danach wieder zurückvervandeln in einen String und dann Unflatten. Aber dies ist wirklich mehr rethorisch da ja der Native Datatype das alles auch viel einfacher macht.
Wie dem auch sei, alle diese Varianten funktionieren wirklich nur für Cluster die garantiert keine Strings oder Arrays enthalten.
Rolf Kalbermatter