如何将非托管EC_VARIANT结构体转换为C#结构体?
非托管C++结构体EC_VARIANT转C#结构体问题
原C++结构体定义
typedef struct _EC_VARIANT { union { BOOL BooleanVal; UINT32 UInt32Val; ULONGLONG DateTimeVal; LPCWSTR StringVal; PBYTE BinaryVal; BOOL *BooleanArr; INT32 *Int32Arr; LPWSTR *StringArr; EC_OBJECT_ARRAY_PROPERTY_HANDLE PropertyHandleVal; }; DWORD Count; DWORD Type; } EC_VARIANT, *PEC_VARIANT;
我尝试的C#实现(未成功)
调用代码:
uint get = Internals.EcOpenSubscription("adfs", (uint)WecAcessTypes.EC_READ_ACCESS, (uint)WecFlags.EC_OPEN_EXISTING); Console.WriteLine($"addr :{get}"); byte[] some = new byte[16]; uint a = 0; bool success = Internals.EcGetSubscriptionProperty(get, (uint)EC_SUBSCRIPTION_PROPERTY_ID.EcSubscriptionEventSources, 0, 128, some, out a); if (!success) { Console.WriteLine("err EcSubscriptionEventSources"); Console.ReadKey(); return; } foreach (byte b in some) { Console.Write(b); } GCHandle gCHandle = GCHandle.Alloc(some, GCHandleType.Pinned); EC_VARIANT eC = (EC_VARIANT)Marshal.PtrToStructure(gCHandle.AddrOfPinnedObject(), typeof(EC_VARIANT)); Console.WriteLine($"\n{eC.Type} {eC.EC_OBJECT_ARRAY_PROPERTY_HANDLE}"); Console.WriteLine($"length {a}"); Console.ReadKey();
定义的C#结构体:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct EC_VARIANT { public uint BooleanVal; public uint UInt32Val; public ulong DateTimeVal; public IntPtr StringVal; public IntPtr BinaryVal; public IntPtr BoolArr; public IntPtr Int32Arr; public IntPtr StringArr; public int EC_OBJECT_ARRAY_PROPERTY_HANDLE; public int Type; public int Count; }
我曾尝试使用LayoutKind.Explicit调整字段布局,但仍无法解决问题,请求技术帮助。
正确的C#结构体转换方案
C++中的union需要用C#的LayoutKind.Explicit配合FieldOffset模拟,所有union成员共享同一块内存起始地址,同时要严格匹配字段类型和内存顺序:
// 先定义EC_OBJECT_ARRAY_PROPERTY_HANDLE的类型,适配Windows API的实际定义 public struct EC_OBJECT_ARRAY_PROPERTY_HANDLE { public uint Value; // 若为64位平台也可改用IntPtr } [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)] public struct EC_VARIANT { // Union成员共享FieldOffset(0) [FieldOffset(0)] public int BooleanVal; // Windows BOOL是typedef int BOOL,对应C# int [FieldOffset(0)] public uint UInt32Val; [FieldOffset(0)] public ulong DateTimeVal; [FieldOffset(0)] public IntPtr StringVal; [FieldOffset(0)] public IntPtr BinaryVal; [FieldOffset(0)] public IntPtr BooleanArr; [FieldOffset(0)] public IntPtr Int32Arr; [FieldOffset(0)] public IntPtr StringArr; [FieldOffset(0)] public EC_OBJECT_ARRAY_PROPERTY_HANDLE PropertyHandleVal; // Union之后的字段,偏移为union的最大成员尺寸(8字节,对应ULONGLONG) [FieldOffset(8)] public uint Count; // DWORD对应C# uint [FieldOffset(12)] public uint Type; // DWORD对应C# uint }
额外优化建议
- 类型匹配细节:Windows API中的
DWORD对应C#uint,BOOL对应int,指针类型用IntPtr自动适配32/64位平台。 - 调用方式简化:无需用
byte[]中转,直接分配结构体内存更可靠(需确保EcGetSubscriptionProperty的P/Invoke定义支持直接输出结构体):
uint get = Internals.EcOpenSubscription("adfs", (uint)WecAcessTypes.EC_READ_ACCESS, (uint)WecFlags.EC_OPEN_EXISTING); EC_VARIANT variant = new EC_VARIANT(); uint size = (uint)Marshal.SizeOf(typeof(EC_VARIANT)); bool success = Internals.EcGetSubscriptionProperty(get, (uint)EC_SUBSCRIPTION_PROPERTY_ID.EcSubscriptionEventSources, 0, size, out variant, out size); if (!success) { Console.WriteLine("err EcSubscriptionEventSources"); Console.ReadKey(); return; } Console.WriteLine($"Type: {variant.Type}, PropertyHandle: {variant.PropertyHandleVal.Value}"); Console.WriteLine($"Length: {size}"); Console.ReadKey();
内容的提问来源于stack exchange,提问作者nikolya92
相关产品推荐
相关产品推荐

