Структура Marshal с массивом фиксированного размера для неуправляемого вызова API - PullRequest
0 голосов
/ 13 апреля 2019

Я создаю управляемую оболочку в C # для API сервера DHCP, и у меня возникла проблема с неуправляемой структурой, которая определяет буфер фиксированного размера.Я хочу добавить фильтр на DHCP-сервер, и API (dhcpsapi.h) определяет следующее:

#define MAX_PATTERN_LENGTH      255
#define MAC_ADDRESS_LENGTH      6
#define HWTYPE_ETHERNET_10MB    1

typedef enum _DHCP_FILTER_LIST_TYPE {
    Deny,
    Allow
} DHCP_FILTER_LIST_TYPE, *LPDHCP_FILTER_LIST_TYPE;

typedef struct _DHCP_ADDR_PATTERN {
    BOOL MatchHWType;
    BYTE HWType;
    BOOL IsWildcard;
    BYTE Length;
    BYTE Pattern[MAX_PATTERN_LENGTH];
} DHCP_ADDR_PATTERN, *LPDHCP_ADDR_PATTERN;

typedef struct _DHCP_FILTER_ADD_INFOV4 {
    DHCP_ADDR_PATTERN     AddrPatt;
    LPWSTR                Comment;
    DHCP_FILTER_LIST_TYPE ListType;
} DHCP_FILTER_ADD_INFO, *LPDHCP_FILTER_ADD_INFO;

Поэтому я определил следующие структуры / перечисления / функции:

    [StructLayout(LayoutKind.Sequential)]
    unsafe internal struct DHCP_FILTER_ADD_INFO
    {
        public DHCP_ADDR_PATTERN AddrPatt;
        public char* Comment;
        public DhcpFilterListType ListType;
    }

    [StructLayout(LayoutKind.Sequential)]
    unsafe internal struct DHCP_ADDR_PATTERN
    {
        public bool MatchHWType;
        public HWTYPE HWType;
        public bool IsWildcard;
        public byte Length;   
        public fixed byte Pattern[255];
    }

    internal enum HWTYPE : byte
    {
        HWTYPE_ETHERNET_10MB = 1
        ...
    }

    // NativeMethods.DhcpAddFilterV4 signature
    [DllImport("dhcpsapi.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern DHCP_ERROR_CODES DhcpAddFilterV4(string serverIpAddress, IntPtr addFilterInfoPtr, bool forceFlag);

    // Wrapper function
    unsafe public static void AddFilter(string serverAddressString, byte[] macAddress, DhcpFilterListType listType)
    {
        if (macAddress == null)
            throw new ArgumentNullException(nameof(macAddress));
        if (macAddress.Length < 6)
            throw new ArgumentException("Invalid mac address", nameof(macAddress));
        if (!Enum.IsDefined(typeof(DhcpFilterListType), listType))
            throw new ArgumentOutOfRangeException(nameof(listType));

        var addressPattern = new DHCP_ADDR_PATTERN
        {
            HWType = HWTYPE.HWTYPE_ETHERNET_10MB,
            IsWildcard = false,
            MatchHWType = true,
            Length = 6
        };
        // Copy the mac address into the fixed size array
        fixed (byte* macPtr = macAddress)
        {
            Buffer.MemoryCopy(macPtr, addressPattern.Pattern, 255, 6);
        }
        var filterAddInfo = new DHCP_FILTER_ADD_INFO
        {
            ListType = listType,
            AddrPatt = addressPattern
        };
        IntPtr filterAddInfoPtr = Marshal.AllocHGlobal(Marshal.SizeOf(filterAddInfo));
        try
        {
            Marshal.StructureToPtr(filterAddInfo, filterAddInfoPtr, true);
            DHCP_ERROR_CODES result = NativeMethods.DhcpAddFilterV4(serverAddressString, filterAddInfoPtr, true);
            if (result != DHCP_ERROR_CODES.ERROR_SUCCESS)
                throw DhcpServerException.GetExceptionForErrorCode(result);
        }
        finally
        {
            Marshal.FreeHGlobal(filterAddInfoPtr);
        }
    }

Итак, когда я вызываю функцию и пытаюсь добавить фильтр для mac-адреса «ABCDEF123456», DHCP MMC показывает запись с mac-адресом «AB0000000000».Поэтому я немного изменил структуру DHCP_ADDR_PATTERN, чтобы использовать атрибут MarshalAs-Attribute в поле Pattern:

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 255)]
public byte[] Pattern;

Это потребовало от меня также изменения функции оболочки:

byte[] pattern = new byte[255];
Buffer.BlockCopy(macAddress, 0, pattern, 0, 6);
addressPattern.Pattern = pattern;

И тогда это работаетКак колдовство.Какое волшебство делается при использовании второго метода и что происходит с данными в первом методе, который я представил?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...