Thanks to AI, you can really be productive in dealing with unions in C.
CM_PARTIAL_RESOURCE_DESCRIPTOR (wdm.h) - Windows drivers | Microsoft Learn
using System; using System.Runtime.InteropServices; // // Windows types for clarity // using PHYSICAL_ADDRESS = System.Int64; // LARGE_INTEGER using KAFFINITY = System.UIntPtr; // ULONG_PTR namespace NativeInterop { /// <summary> /// C# equivalent of CM_PARTIAL_RESOURCE_DESCRIPTOR (winnt.h). /// </summary> [StructLayout(LayoutKind.Explicit, Pack = 1)] public struct CM_PARTIAL_RESOURCE_DESCRIPTOR { // ---- common header ------------------------------------------------- [FieldOffset(0)] public byte Type; [FieldOffset(1)] public byte ShareDisposition; [FieldOffset(2)] public ushort Flags; // ---- union: one of these is valid, chosen by <Type> --------------- [FieldOffset(4)] public GENERIC_RESOURCE Generic; [FieldOffset(4)] public PORT_RESOURCE Port; [FieldOffset(4)] public MEMORY_RESOURCE Memory; [FieldOffset(4)] public MEMORY40_RESOURCE Memory40; [FieldOffset(4)] public MEMORY48_RESOURCE Memory48; [FieldOffset(4)] public MEMORY64_RESOURCE Memory64; [FieldOffset(4)] public INTERRUPT_RESOURCE Interrupt; [FieldOffset(4)] public MESSAGE_INTERRUPT_RESOURCE MessageInterrupt; [FieldOffset(4)] public DMA_RESOURCE Dma; [FieldOffset(4)] public DMAV3_RESOURCE DmaV3; [FieldOffset(4)] public DEVICE_PRIVATE_RESOURCE DevicePrivate; [FieldOffset(4)] public BUSNUMBER_RESOURCE BusNumber; [FieldOffset(4)] public DEVICESPECIFIC_RESOURCE DeviceSpecificData; [FieldOffset(4)] public CONNECTION_RESOURCE Connection; } #region simple (start,length) pairs [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct GENERIC_RESOURCE { public PHYSICAL_ADDRESS Start; public uint Length; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct PORT_RESOURCE { public PHYSICAL_ADDRESS Start; public uint Length; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct MEMORY_RESOURCE { public PHYSICAL_ADDRESS Start; public uint Length; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct MEMORY40_RESOURCE { public PHYSICAL_ADDRESS Start; public uint Length40; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct MEMORY48_RESOURCE { public PHYSICAL_ADDRESS Start; public uint Length48; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct MEMORY64_RESOURCE { public PHYSICAL_ADDRESS Start; public uint Length64; } #endregion #region interrupt resources [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct INTERRUPT_RESOURCE { public uint Level; // ULONG for both x86/x64 builds public uint Vector; public KAFFINITY Affinity; } // Message‑signalled interrupt has an inner union (Raw vs Translated) [StructLayout(LayoutKind.Explicit, Pack = 1)] public struct MESSAGE_INTERRUPT_RESOURCE { [FieldOffset(0)] public MESSAGE_INTERRUPT_RAW Raw; [FieldOffset(0)] public MESSAGE_INTERRUPT_TRANSLATED Translated; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct MESSAGE_INTERRUPT_RAW { public ushort Group; public ushort Reserved; public ushort MessageCount; public uint Vector; public KAFFINITY Affinity; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct MESSAGE_INTERRUPT_TRANSLATED { public uint Level; public uint Vector; public KAFFINITY Affinity; } #endregion #region DMA [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct DMA_RESOURCE { public uint Channel; public uint Port; public uint Reserved1; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct DMAV3_RESOURCE { public uint Channel; public uint RequestLine; public byte TransferWidth; public byte Reserved1; public byte Reserved2; public byte Reserved3; } #endregion #region miscellaneous [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct DEVICE_PRIVATE_RESOURCE { public uint Data0; public uint Data1; public uint Data2; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct BUSNUMBER_RESOURCE { public uint Start; public uint Length; public uint Reserved; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct DEVICESPECIFIC_RESOURCE { public uint DataSize; public uint Reserved1; public uint Reserved2; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct CONNECTION_RESOURCE { public byte Class; public byte Type; public byte Reserved1; public byte Reserved2; public uint IdLowPart; public uint IdHighPart; } #endregion }
Declare the two structs in the union as C# structs in the usual way. Then declare a type for the union, using an explicit layout.
[StructLayout(LayoutKind.Explicit)]
public struct _WAITCHAIN_NODE_INFO_UNION
{
[FieldOffset(0)]
_WAITCHAIN_NODE_INFO_LOCK_OBJECT LockObject;
[FieldOffset(0)]
_WAITCHAIN_NODE_INFO_THREAD_OBJECT ThreadObject;
}
Then add the union to your struct:
[StructLayout(LayoutKind.Sequential)]
public struct WAITCHAIN_NODE_INFO
{
public WCT_OBJECT_TYPE ObjectType;
public WCT_OBJECT_STATUS ObjectStatus;
public _WAITCHAIN_NODE_INFO_UNION Union;
}
When you overlay objects like this, extra requirements are placed on the types involved. You cannot overlay a type containing a string or an array for instance. So the character array will have to be implemented as a value type, for instance a fixed array. This is inconvenient to operate with but MS did not define the types with C# in mind.
No comments:
Post a Comment