Umsetzung C++-Struktur
-
Hi,
also ich habe folgende C++-Struktur vor mir liegen und muss diese in C# übertragen:
#define CTRLTELE_MAX_GUID 10 typedef SQLGUID CTRLTELE_GUID[CTRLTELE_MAX_GUID]; typedef struct { DWORD dwCrc32, dwVersion, dwSize; char cType; union { struct // cType 'M' { ULONG ulFlags; CTRLTELE_GUID gGUID; }; struct // cType 'W' { long iFlags; TCHAR szMsg[513]; }; struct // cType 'R' { long iDelay; }; struct // cType 'A' { long lAuftragID; }; }; }CTRLTELE;
[StructLayoutAttribute(LayoutKind.Sequential)] public struct CTRLTELE { public uint dwCrc32; public uint dwVersion; public uint dwSize; public byte cType; public CtrlTypes Types; } [StructLayoutAttribute(LayoutKind.Explicit)] public struct CtrlTypes { [FieldOffsetAttribute(0)] public TypeM M; [FieldOffsetAttribute(0)] public TypeW W; [FieldOffsetAttribute(0)] public TypeR R; [FieldOffsetAttribute(0)] public TypeA A; } [StructLayoutAttribute(LayoutKind.Sequential)] public struct TypeM { public uint ulFlags; public GUID[] gGUID; } [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct TypeW { public int iFlags; [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 513)] public string szMsg; } [StructLayoutAttribute(LayoutKind.Sequential)] public struct TypeR { public int iDelay; } [StructLayoutAttribute(LayoutKind.Sequential)] public struct TypeA { public int lAuftragID; } [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct GUID { public uint Data1; public ushort Data2; public ushort Data3; [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 8)] public string Data4; }
530 Bytes groß ist die "originale" Struktur, bis 560 hab ich die C#-Variante gekriegt.
Und eine Exception fliegt wegen der CtrlTypes-Struct: "...konnte nicht geladen werden, da sie bei Offset 0 ein Objektfeld enthält, das falsch ausgerichtet ist oder von einem Feld überlappt wird, das kein Objektfeld ist."Ich verstehe das schon ungefähr, weiß nur nicht, wie ich das beheben kann bzw. wie die Umsetzung der Struktur wirklich aussehen soll.
Wer kann mir da helfen ?
-
Eine C++ Struktur ist das nicht wirklich, eher eine äusserst hässliche C Struktur
Habe mich kurz mit dem Problem beschäftigt, bin aber vorerst essen und danach noch mit anderem beschäftigt. Die "einfachste" Lösung, welche ich bis jetzt finden konnte, wäre:[StructLayout(LayoutKind.Sequential)] public struct CtrlTele { public uint dwCrc32; public uint dwVersion; public uint dwSize; public uint cType; [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 517)] public byte[] Types; }
Unter der Voraussetzung, dass es ein Padding bei
cType
gibt (deswegen deruint
) und dassTCHAR
im Typ W zu einemchar
expandiert. Danach kann man mit einemMemoryStream
und einemBinaryReader
die Sache auslesen und konvertieren. Du könntest entsprechende Methoden inCtrlTele
zur Verfügung stellen, welche dann auch gleich die Typprüfung mitcType
durchführen. Nicht wirklich ideal, aber die Struktur ist auch alles andere als ideal für P/InvokeGrüssli
PS: Bei Attributen kannst du das "Attribute" am Ende des Namen weglassen.
-
Hi,
ja, C++-Struktur war tatsächlich übertrieben. :):)
Grundsätzlich ist der Aufbau der Struktur nicht ideal für C#, ich will in einer Assembly mit meinen nativen Windows Services per Socket kommunizieren und dazu gibt es dieses Telegramm.
Notwendig von den Typen ist nur 'W', der Rest interessiert mich nicht. Jedoch sollte es korrekt auf der anderen Seite aussehen (deshalb die Angabe der Größe vorhin).
Ich muss also setzen:- dwVersion
- dwSize
- cType (= 'W')
- iFlags
- szMsg (tatsächlich mehr als 1 Zeichen)
Wenn szMsg nicht wäre, wär' der Vorschlag von dir ideal...
Das ist irgendwie doof hier.
-
R3dNeXX schrieb:
Notwendig von den Typen ist nur 'W', der Rest interessiert mich nicht.
Sag das doch gleich! Das macht die Sache EXTREM viel einfacher!
[StructLayout(LayoutKind.Sequential)] public struct CtrlTele { public uint dwCrc32; public uint dwVersion; public uint dwSize; public byte cType; public TypeW W; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct TypeW { public int iFlags; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 513)] public string szMsg; }
So funktioniert es. CharSet.Unicode oder CharSet.Ansi musst du noch auswählen. Auf einem Windows NT und später ist TCHAR meistens WCHAR. Aber kommt halt darauf an, wie die DLL kompiliert wurde, bzw. mit UNICODE oder nicht.
Grüssli
-
Oh, entschuldige, hab das echt vergessen zu erwähnen.
Super, funktioniert einwandfrei !! Nur ein Pack = 1 bei CtrlTele und TypeW hat noch gefehlt, damit ich bei 530 Bytes ankomme, aber ich habe dafür auch das #pragma pack(1) im 1. Post vergessen.
Gut, in meinem Fall noch Ansi, dann ist alles ok.Vielen Dank für deine Hilfe !!!!!!!
Schönes Wochenende