首页 > 解决方案 > 在 C# 中正确地马歇尔 ioctl

问题描述

我正在尝试通过 C# 中的 ioctl 获取有关 DVD 的信息

C 结构看起来像这样,并且在混合的 CLR C++ 库中工作

typedef enum {
    DvdChallengeKey = 0x01,
    DvdBusKey1,
    DvdBusKey2,
    DvdTitleKey,
    DvdAsf,
    DvdSetRpcKey = 0x6,
    DvdGetRpcKey = 0x8,
    DvdDiskKey = 0x80,
    DvdInvalidateAGID = 0x3f
} DVD_KEY_TYPE;

typedef struct DVD_COPY_PROTECT_KEY
{
ULONG KeyLength;
DVD_SESSION_ID SessionId;
DVD_KEY_TYPE KeyType;
ULONG KeyFlags;
union
{
    struct
    {
        ULONG FileHandle;
        ULONG Reserved;   // used for NT alignment
    };
    LARGE_INTEGER TitleOffset;
} Parameters;
UCHAR KeyData[0];
} DVD_COPY_PROTECT_KEY, * PDVD_COPY_PROTECT_KEY;

我的 C# 等效外观

public enum DVD_KEY_TYPE
    {
        DvdChallengeKey = 0x01,
        DvdBusKey1,
        DvdBusKey2,
        DvdTitleKey,
        DvdAsf,
        DvdSetRpcKey = 0x6,
        DvdGetRpcKey = 0x8,
        DvdDiskKey = 0x80,
        DvdInvalidateAGID = 0x3f
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct DVD_COPY_PROTECT_KEY
    {
        public uint KeyLength;
        public int SessionId;
        public DVD_KEY_TYPE KeyType;
        public uint KeyFlags;

        [MarshalAs(UnmanagedType.Struct)]
        public DVD_COPY_PROTECT_KEY_Parameters Parameters;
        
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
        private byte[] KeyData;
        
        public DVD_COPY_PROTECT_KEY(DVD_KEY_TYPE keyType, int sessionId)
        {
            SessionId = sessionId;
            KeyType = keyType;
            KeyFlags = 0;
            KeyData = new byte[10];
            KeyLength = 32;//GetKeyLength(this);
            
            Parameters = new DVD_COPY_PROTECT_KEY_Parameters();
            

            var t = Marshal.SizeOf(Parameters);
            var t1 = Marshal.SizeOf(Parameters.Inner); 
            var t2 = Marshal.SizeOf(Parameters.TitleOffset);

            var challenge = GetChallenge();

            /* Get challenge from host */
            for (int i = 0; i < 10; ++i)
            {
                KeyData[9 - i] = challenge[i];
            }
            
        }

        public static byte[] GetChallenge()
        {
            byte[] p_challenge = new byte[10];

            /* Setup a challenge, any values should work */
            for (int i = 0; i < 10; ++i)
            {
                p_challenge[i] = (byte)i;
            }
            return p_challenge;
        }

        public static uint GetKeyLength(DVD_COPY_PROTECT_KEY dcpk)
        {
            int size = Marshal.SizeOf(dcpk);
            switch (dcpk.KeyType)
            {
                case DVD_KEY_TYPE.DvdChallengeKey:
                    return (uint)(12 + size); //36
                case DVD_KEY_TYPE.DvdBusKey1:
                    return (uint)(8 + size); //32
                case DVD_KEY_TYPE.DvdBusKey2:
                    return (uint)(8 + size);
                default:
                    return 0;
            }
        }
    }

    [StructLayout(LayoutKind.Explicit)]
    public struct DVD_COPY_PROTECT_KEY_Parameters
    {
        [FieldOffset(0)]
        public DVD_COPY_PROTECT_KEY_Parameters_Inner Inner;
        [FieldOffset(0)]
        public int TitleOffset;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct DVD_COPY_PROTECT_KEY_Parameters_Inner
    {
        public IntPtr FileHandle;
        public uint Reserved;
    }

如果我调用 DeviceIoControl,我会得到一个异常 PInvokeStackImbalance,如果我改用类,我会从 Marshal.GetLastWin32Error(); 得到 ErrorCode 87;

有人有什么想法吗?

更新 我的 DeviceIoControl

[System.Runtime.InteropServices.DllImport("Kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
    public extern static int DeviceIoControl(IntPtr hDevice, uint IoControlCode, ref DVD_COPY_PROTECT_KEY dcpk, uint InBufferSize, ref DVD_COPY_PROTECT_KEY dcpk2, uint OutBufferSize, ref uint BytesReturned, IntPtr Overlapped);

我现在添加了 ref 关键字,我得到的结构没有异常但 ErrorCode 87

我的代码可以在这里找到

标签: c#c++marshallingioctldeviceiocontrol

解决方案


推荐阅读