从指向结构的指针 PInvoke 编组值

时间:2021-04-30 05:44:54

标签: c# pointers winapi pinvoke

我想从 Dhcpsapi.dll 中调用 DhcpEnumSubnets() 方法。

https://docs.microsoft.com/en-us/windows/win32/api/dhcpsapi/nf-dhcpsapi-dhcpenumsubnets

CsWin32 自动生成方法和调用该方法所需的结构。

https://github.com/microsoft/CsWin32

这是我的例子:

public static unsafe List<string> DhcpEnumSubnets(string serverAddress)
{
    uint resumeHandle = 0;
    uint preferredMaximum = 65536;
    DHCP_IP_ARRAY* enumInfo = null;
    List<string> subnets = new();
    while (PInvoke.DhcpEnumSubnets(serverAddress,
        ref resumeHandle,
        preferredMaximum,
        ref enumInfo,
        out uint elementsRead,
        out uint elementsTotal).IsEqual(DhcpErrorCode.SUCCESS))
    {
        try
        {
            DHCP_IP_ARRAY info = enumInfo[0];
            for (uint j = 0; j < info.NumElements; j++)
            {
                uint nativeSubnetAddress = info.Elements[j];
                var subnetAddress = DhcpHelper.NativeIpAddressToString(nativeSubnetAddress);
                subnets.Add(subnetAddress);
            }
        }
        finally
        {
            DhcpRpcFreeMemory(enumInfo);
        }
    }
    return subnets;
}

我被告知要编写 2 个 for 循环来生成完整的项目,然后适当地释放它们。

try
{
    for (uint i = 0; i < elementsRead; i++)
    {
        DHCP_IP_ARRAY info = enumInfo[i];
        for (uint j = 0; j < info.NumElements; j++)
        {
            uint nativeSubnetAddress = info.Elements[j];
            var subnetAddress = DhcpHelper.NativeIpAddressToString(nativeSubnetAddress);
            subnets.Add(subnetAddress);
        }
    }
}
finally
{
    for (uint i = 0; i < elementsRead; i++)
    {
        DhcpRpcFreeMemory(enumInfo[i].Elements);
    }
    DhcpRpcFreeMemory(enumInfo);
}

CsWin32 自动生成:

// ------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------
#pragma warning disable CS1591, CS1573, CS0465, CS0649, CS8019, CS1570, CS1584, CS1658
namespace Microsoft.Windows.Sdk
{
    using global::System;
    using global::System.Diagnostics;
    using global::System.Runtime.CompilerServices;
    using global::System.Runtime.InteropServices;

    /// <content>
    /// Contains extern methods from "DHCPSAPI.dll".
    /// </content>
    internal static partial class PInvoke
    {
        /// <inheritdoc cref = "DhcpEnumSubnets(PCWSTR, uint *, uint, DHCP_IP_ARRAY**, uint *, uint *)"/>
        internal static unsafe uint DhcpEnumSubnets(string ServerIpAddress, ref uint ResumeHandle, uint PreferredMaximum, ref DHCP_IP_ARRAY*EnumInfo, out uint ElementsRead, out uint ElementsTotal)
        {
            fixed (uint *ElementsTotalLocal = &ElementsTotal)
            {
                fixed (uint *ElementsReadLocal = &ElementsRead)
                {
                    fixed (DHCP_IP_ARRAY**EnumInfoLocal = &EnumInfo)
                    {
                        fixed (uint *ResumeHandleLocal = &ResumeHandle)
                        {
                            fixed (char *ServerIpAddressLocal = ServerIpAddress)
                            {
                                uint __result = PInvoke.DhcpEnumSubnets(ServerIpAddressLocal, ResumeHandleLocal, PreferredMaximum, EnumInfoLocal, ElementsReadLocal, ElementsTotalLocal);
                                return __result;
                            }
                        }
                    }
                }
            }
        }

        /// <summary>The DhcpEnumSubnets function returns an enumerated list of subnets defined on the DHCP server.</summary>
        /// <param name = "ServerIpAddress">Unicode string that specifies the IP address or hostname of the DHCP server.</param>
        /// <param name = "ResumeHandle">Pointer to a <a href = "https://docs.microsoft.com/previous-versions/windows/desktop/dhcp/dhcp-server-management-type-definitions">DHCP_RESUME_HANDLE</a> value that identifies the enumeration operation. Initially, this value should be zero, with a successful call returning the handle value used for subsequent enumeration requests. For example, if <i>PreferredMaximum</i> is set to 100, and 200 subnet addresses  are stored on the server, the resume handle can be used after the first 100 subnets are retrieved to obtain the next 100 on a subsequent call, and so forth.</param>
        /// <param name = "PreferredMaximum">Specifies the preferred maximum number of subnet addresses to return. If the number of remaining unenumerated options is less than this value, then that amount will be returned.</param>
        /// <param name = "EnumInfo">Pointer to a <a href = "https://docs.microsoft.com/windows/desktop/api/dhcpsapi/ns-dhcpsapi-dhcp_ip_array">DHCP_IP_ARRAY</a> structure that contains the subnet IDs available on the DHCP server. If no subnets are defined, this value will be null.</param>
        /// <param name = "ElementsRead">Pointer to a <b>DWORD</b> value that specifies the number of subnet addresses returned in <i>EnumInfo</i>.</param>
        /// <param name = "ElementsTotal">Pointer to a <b>DWORD</b> value that specifies the  number of subnets defined on the DHCP server that have not yet been enumerated.</param>
        /// <returns>This function returns <b>ERROR_SUCCESS</b> upon a successful call. If a call is made with the same <i>ResumeHandle</i> value and all items on the server have been enumerated, this method returns <b>ERROR_NO_MORE_ITEMS</b> with <i>ElementsRead</i> and <i>ElementsTotal</i> set to 0. Otherwise, it returns one of the <a href = "/previous-versions/windows/desktop/dhcp/dhcp-server-management-api-error-codes">DHCP Server Management API Error Codes</a>.</returns>
        /// <remarks>
        /// <para><see href = "https://docs.microsoft.com/windows/win32/api//dhcpsapi/nf-dhcpsapi-dhcpenumsubnets">Learn more about this API from docs.microsoft.com</see>.</para>
        /// </remarks>
        [DllImport("DHCPSAPI", ExactSpelling = true)]
        [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
        internal static extern unsafe uint DhcpEnumSubnets(PCWSTR ServerIpAddress, uint *ResumeHandle, uint PreferredMaximum, DHCP_IP_ARRAY**EnumInfo, uint *ElementsRead, uint *ElementsTotal);
    }
}
// ------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------
#pragma warning disable CS1591, CS1573, CS0465, CS0649, CS8019, CS1570, CS1584, CS1658
namespace Microsoft.Windows.Sdk
{
    using global::System;
    using global::System.Diagnostics;
    using global::System.Runtime.CompilerServices;
    using global::System.Runtime.InteropServices;

    /// <summary>The DHCP_IP_ARRAY structure defines an array of IP addresses.</summary>
    /// <remarks>
    /// <para><see href = "https://docs.microsoft.com/windows/win32/api//dhcpsapi/ns-dhcpsapi-dhcp_ip_array">Learn more about this API from docs.microsoft.com</see>.</para>
    /// </remarks>
    internal partial struct DHCP_IP_ARRAY
    {
        /// <summary>Specifies the number of IP addresses in <b>Elements</b>.</summary>
        internal uint NumElements;
        /// <summary>Pointer to a list of <a href = "https://docs.microsoft.com/previous-versions/windows/desktop/dhcp/dhcp-server-management-type-definitions">DHCP_IP_ADDRESS</a> values.</summary>
        internal unsafe uint *Elements;
    }
}

使用 2 个 for 循环的方式对我不起作用,我错过了什么吗? 第一个代码示例对我有用,我不确定这真的是调用此方法的正确方法吗? 这部分引起了我的困惑:

DHCP_IP_ARRAY info = enumInfo[0]

像数组一样访问指针是否有效?基本上我将值从指针传递给结构。这是否为结构分配了所有需要的值?一个指针是否只在 index 0 中保存一个值?我想知道这是否适用于 dhcpsapi.dll 中的其他方法,index 0 是否会给我所有结果?

1 个答案:

答案 0 :(得分:0)

根据DhcpEnumSubnets函数,EnumInfo是一个指向DHCP_IP_ARRAY结构的指针,可以像数组一样访问该指针。
是的,这会将所有需要的值分配给结构体,指针是否只在索引 0 中保存一个值取决于 DhcpEnumSubnets 函数。

相关问题