Tuesday, June 17, 2025

CM_PARTIAL_RESOURCE_DESCRIPTOR c# equivalent


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