简体   繁体   中英

How to marshal C++ struct containing DWORD bitfields in C#

I'm working with an unmanaged SDK and have a struct that I am needing to marshal in C#:

struct DEV_TIME
{
    DWORD  second:6;
    DWORD  minute:6;
    DWORD  hour:5;
    DWORD  day:5;
    DWORD  month:4;
    DWORD  year:6;
}

I've searched around and have tried a number of things but can't seem to figure it out. Here is my latest attempt after reading numerous posts:

    [StructLayout(LayoutKind.Sequential)]
    public struct DHDEVTIME
    {
        internal uint secData;
        internal uint minData;
        internal uint hourData;
        internal uint dayData;
        internal uint monData;
        internal uint yearData;

        public uint second
        {
            get { return secData & 0x3F; }
            set { secData = (secData % ~0x3Fu) | (value & 0x3F); }
        }

        public uint minute
        {
            get { return minData & 0x3F; }
            set { minData = (minData % ~0x3Fu) | (value & 0x3F); }
        }

        public uint hour
        {
            get { return hourData & 0x1F; }
            set { hourData = (hourData % ~0x1Fu) | (value & 0x1F); }
        }

        public uint day
        {
            get { return dayData & 0x1F; }
            set { dayData = (dayData % ~0x1Fu) | (value & 0x1F); }
        }

        public uint month
        {
            get { return monData & 0xF; }
            set { monData = (monData % ~0xFu) | (value & 0xF); }
        }

        public uint year
        {
            get { return yearData & 0x3F; }
            set { yearData = (yearData % ~0x3Fu) | (value & 0x3F); }
        }
    }

This struct is part of a call to the SDK, which contains other structs, etc. etc. Long story short, I'm not 100% sure if this is even wrong and is what is causing the call to not work correctly. I've never had to deal with a struct like this, so I'm thinking this is the most likely cause. If this appears to be correct, let me know and I'll post some more of the other code. Just trying to be minimalistic at first.

UPDATE

Thanks to @Ben Voigt for pointing me in the right direction. Below is the correct code for future reference:

[StructLayout(LayoutKind.Sequential)]
public struct DHDEVTIME
{
    internal uint data;

    public uint second
    {
        get { return data & 0x3F; }
        set { data = (data & ~0x3Fu) | (value & 0x3F); }
    }

    public uint minute
    {
        get { return (data >> 6) &  0x3F; }
        set { data = (data & ~(0x3Fu << 6)) | (value & 0x3F) << 6; }
    }

    public uint hour
    {
        get { return (data >> 12) & 0x1F; }
        set { data = (data & ~(0x1Fu << 12)) | (value & 0x1F) << 12; }
    }

    public uint day
    {
        get { return (data >> 17) & 0x1F; }
        set { data = (data & ~(0x1Fu << 17)) | (value & 0x1F) << 17; }
    }

    public uint month
    {
        get { return (data >> 22) & 0xF; }
        set { data = (data & ~(0xFu << 22)) | (value & 0xF) << 22; }
    }

    public uint year
    {
        get { return (data >> 26) & 0x3F; }
        set { data = (data & ~(0x3Fu << 26)) | (value & 0x3F) << 26; }
    }
}

There's only ONE 32-bit integer in that entire structure. All the various components are packed into different subsets of the 32-bit structure.

You'll probably want to use exactly one UInt32 field on the .NET side, and properties for access to the individual components. The .NET BitVector32 class can help you with extracting and updating the bitfields within the single 32-bit field.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM