Я создаю управляемую оболочку в 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;
И тогда это работаетКак колдовство.Какое волшебство делается при использовании второго метода и что происходит с данными в первом методе, который я представил?