我正在用C#为DHCP服务器API创建托管包装器,并且定义了固定大小缓冲区的非托管结构有问题。我想在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:
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 255)]
public byte[] Pattern;
这还需要我更改包装函数:
byte[] pattern = new byte[255];
Buffer.BlockCopy(macAddress, 0, pattern, 0, 6);
addressPattern.Pattern = pattern;
然后它就像一种魅力。 使用第二种方法时有什么魔力,我介绍的第一种方法中的数据会怎样?