C++ Union nach C# migrieren.
-
Liebe Forumianer,
nach langem Stöbern bin ich zu keinem vernünftigen Ergebnis gekommen. Hier meine Frage:
... wie bilde ich folgendes Union-Konstrukt in C# nach???typedef union { struct { unsigned char reserve; unsigned char ain[12]; unsigned char aout[8]; unsigned char cntr; unsigned char fef_zyklus; unsigned char fef_projekt; } rd; unsigned char wr[12 + 8 + 4]; } PRM_t;
mein Ansatz ist
public struct Union_PRM_t { public struct rd { public byte reserve; public static byte[] ain = new byte[12]; public static byte[] aout = new byte[8]; public byte cntr; public byte fef_zyklus; public byte fef_projekt; } public static byte[] wr = new byte[12 + 8 + 4]; } //Deklaration Union_PRM_t data;
Die Funktion in einer DLL sieht so aus:
DPR_DWORD DP_read_slv_par (DPR_DWORD user_handle,// in DPR_WORD slv_add, // in DPR_WORD type, // in DPR_WORD *data_len; // out DPR_BYTE *data; // out DP_ERROR_T *error ); // out
Wie übergebe ich an *data die Adresse von data.wr???
Vielen-vielen Dank für Eure unterstützung!
-
Kannst du ein bisschen näher beschreiben was du vor hast?
-
ganz allgemein: ich muss über Profibus-Kommunikationskarte eine SPS-Baugruppe ansprechen.
Ich habe:
- eine DLL (c++)
- ein paar Header, die die Strukturen der Parameter und die Deklarationen der Funktionen für diese DLL beschreiben (c++)In einem Header wird eine Funktion so beschrieben:
DPR_DWORD DP_read_slv_par (DPR_DWORD user_handle,// in DPR_WORD slv_add, // in DPR_WORD type, // in DPR_WORD *data_len, // out DPR_BYTE *data, // out DP_ERROR_T *error ); // out
Diese habe ich folgendermaßen importiert:
[DllImport("dp_base.dll", CharSet = CharSet.Ansi)] public static extern DPR_DWORD DP_read_slv_par (DPR_DWORD user_handle,// in DPR_WORD slv_add, // in DPR_WORD type, // in out DPR_WORD data_len, // out out DPR_BYTE data, // out out DP_ERROR_T error ); // out
Für DPR_BYTE *data habe ich folgende Struktur als Vorgabe:
typedef union { struct { unsigned char reserve; unsigned char ain[12]; unsigned char aout[8]; unsigned char cntr; unsigned char fef_zyklus; unsigned char fef_projekt; } rd; unsigned char wr[12 + 8 + 4]; } PRM_t;
Diese habe ich folgendermaßen versucht mit C# nachzubilden:
public struct Union_PRM_t { public struct rd { public byte reserve; public static byte[] ain = new byte[12]; public static byte[] aout = new byte[8]; public byte cntr; public byte fef_zyklus; public byte fef_projekt; } public static byte[] wr = new byte[12 + 8 + 4]; }
Ich deklariere eine Variable der Struktur Union_PRM_t:
//Deklaration Union_PRM_t data;
im Anschluss muss ich das Member wr an DP_read_slv_par übergeben:
dpd_RetErrClass = DP_Master.DP_read_slv_par(glb_dpdUserHandle, glb_SlvAdr[0], DP_IF.DP._SLV_PRM, out DP_parlen, out data.wr, out dpt_ErrStruct);
Nun was mache ich falsch?
-
Mach einfach 2 structs raus
(StructLayout würde ich immer angeben)
-
In C# kann man Unions mit
LayoutKind.Explicit
undFieldOffsetAttribute
nachbauen. Dies ist aber in deinem Fall nicht nötig, wenn ich das richtig sehe. Du wirst im C# Programm sowieso nie auf das Arraywr
zugreifen. Daher mach es doch gleich so:[StructLayout(LayoutKind.Sequential)] public struct Union_PRM_t { public byte reserve; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public byte[] ain; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] aout; public byte cntr; public byte fef_zyklus; public byte fef_projekt; } [DllImport("dp_base.dll", CharSet = CharSet.Ansi)] public static extern DPR_DWORD DP_read_slv_par( DPR_DWORD user_handle, DPR_WORD slv_add, DPR_WORD type, out DPR_WORD data_len, ref Union_PRM_t data, out DP_ERROR_T error);
Warnung: Dieser User ist sehr müde und kann daher für die Korrektheit der Informationen nicht garantieren.
Grüssli
-
Hallo Dravere,
interessanter Ansatz. Funktioniert das auch bei Unions, die unterschiedliche Große elemente im Speicher liegen haben? Eine Enum orientiert sich ja an dem größtmöglichen Wert, damit es beim Iterieren durch ein Array keine Schwierigkeiten gibt.
Grüße
-
Hi Dravere,
Danke, es hat geklappt!
Kannst du mir bitte vielleicht in einem anderen Thread weiterhelfen:
http://www.c-plusplus.net/forum/285493
???
-
@2AndAHalfBit,
Ich würde aufpassen, wenn es unterschiedliche Grössen drin hat und zusätzlich nicht primitive Typen. Aber mit demFieldOffsetAttribute
kann man einiges erreichen. Z.B. sowas ist kein Problem:[StructLayout(LayoutKind.Explicit)] struct Test { [FieldOffset(0)] public int a; [FieldOffset(0)] public long b; }
Dies ist sogar eine Union in C# selber. Also das folgende Program gibt 10 aus:
Test t = new Test(); t.a = 10; Console.WriteLine(t.b);
Grüssli
-
Hallo Dravere,
das dein Beispiel funktioniert, ist unkritisch. Aber was wäre, wenn ich ein Array von deinem Enum habe? Bei der ausgabe des zweiten Arrayelements würde das auch noch passen? Ich habs nun nicht ausprobiert, also glaub ichs dir erstmal.
Greez.
-
2AndAHalfBit schrieb:
das dein Beispiel funktioniert, ist unkritisch. Aber was wäre, wenn ich ein Array von deinem Enum habe? Bei der ausgabe des zweiten Arrayelements würde das auch noch passen? Ich habs nun nicht ausprobiert, also glaub ichs dir erstmal.
Enum
ist in C# standardmässigInt32
. Falls du einen anderen Typen willst, dann musst du dies angeben.
http://msdn.microsoft.com/en-us/library/sbbt4032.aspx2AndAHalfBit schrieb:
Eine Enum orientiert sich ja an dem größtmöglichen Wert, ...
In C# nicht.
Grüssli