DhcpEnumFilterV4 (P/Invoke) always reports ERROR_NO_MORE_ITEMS

210 Views Asked by At

I try to programmatically enumerate the DHCP filters on my Windows 2012 R2 DHCP server. Using P/Invoke, the code looks like:

public const uint ERROR_SUCCESS = 0;
public const uint ERROR_MORE_DATA = 234;
public const uint ERROR_NO_MORE_ITEMS = 259;

public const int MAX_PATTERN_LENGTH = 255;

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct DHCP_ADDR_PATTERN {
    public bool MatchHWType;
    public byte HWType;
    public bool IsWildCard;
    public byte Length;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_PATTERN_LENGTH)]
    public byte[] Pattern;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct DHCP_FILTER_ENUM_INFO {
    public uint NumElements;
    public IntPtr pEnumRecords;
}

public enum DHCP_FILTER_LIST_TYPE : uint { 
    Deny = 0x1,
    Allow = 0x2
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct DHCP_FILTER_RECORD {
    public DHCP_ADDR_PATTERN AddrPatt;
    public string Comment;
}


[DllImport("dhcpsapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern uint DhcpEnumFilterV4(string ServerIpAddress,
    ref DHCP_ADDR_PATTERN ResumeHandle, uint PreferredMaximum, 
    DHCP_FILTER_LIST_TYPE ListType, out IntPtr EnumFilterInfo,
    out uint ElementsRead, out uint ElementsTotal);

public static IEnumerable<DHCP_FILTER_RECORD> DhcpEnumFilterV4(
        string serverIpAddress, DHCP_FILTER_LIST_TYPE listType, 
        uint preferredMaximum = 1024) {
    uint cntRead = 0;
    uint cntTotal = 0;
    uint error = ERROR_SUCCESS;
    var hResume = new DHCP_ADDR_PATTERN();
    var data = IntPtr.Zero;
    var size = Marshal.SizeOf(typeof(DHCP_FILTER_RECORD));

    do {
        error = DhcpEnumFilterV4(serverIpAddress, ref hResume,
            preferredMaximum, listType, out data, out cntRead, 
            out cntTotal);
        //
        // PROBLEM OCCURS HERE: 'error' is always 259
        //
        if ((error == ERROR_SUCCESS) || (error == ERROR_MORE_DATA)) {
            var array = data.ToStructure<DHCP_FILTER_ENUM_INFO>();
            for (uint i = 0; i < array.NumElements; ++i) {
                var ptr = new IntPtr((long) array.pEnumRecords + i * size);
                var obj = (DHCP_FILTER_RECORD) Marshal.PtrToStructure(ptr, typeof(DHCP_FILTER_RECORD));
                yield return obj;
            }

            DhcpRpcFreeMemory(array.pEnumRecords);
            DhcpRpcFreeMemory(data);
            data = IntPtr.Zero;

        } else if (error != ERROR_NO_MORE_ITEMS) {
            Debug.Assert(data == IntPtr.Zero);
            throw new Win32Exception((int) error);
        }

    } while (error == ERROR_MORE_DATA);
}

[DllImport("dhcpsapi.dll", SetLastError = true)]
public static extern void DhcpRpcFreeMemory(IntPtr BufferPointer);

The documentation (http://msdn.microsoft.com/en-us/library/windows/desktop/dd897526(v=vs.85).aspx) of the whole DHCP APIs is imho a bit sketchy, so I am not completely sure whether I am doing the right thing.

The problem is: I never get any results, DhcpEnumFilterV4 always returns ERROR_NO_MORE_ITEMS. Any suggestions?

1

There are 1 best solutions below

1
On BEST ANSWER

I just stumbled over an important user comment regarding DHCP_FILTER_LIST_TYPE in MSDN (http://msdn.microsoft.com/en-us/library/windows/desktop/dd897586(v=vs.85).aspx). It seems that the definition of the enumeration in MSDN is wrong. The following

typedef enum  { 
    Deny   = 0x1, // This is wrong!
    Allow  = 0x2  // This is wrong!
} DHCP_FILTER_LIST_TYPE;

should be

typedef enum  { 
    Deny   = 0x0, // This is correct!
    Allow  = 0x1  // This is correct!
} DHCP_FILTER_LIST_TYPE;

Using the updated constants, my code works.