简体   繁体   中英

PInvoke marshal value from pointer to struct

I want to call the method DhcpEnumSubnets() from the Dhcpsapi.dll.

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

CsWin32 autogenerated the method and the structs needed to call the method.

https://github.com/microsoft/CsWin32

Here is my example:

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;
}

I was told to write 2 for loops to produce the full items and then release them appropriate.

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 autogenerated this:

// ------------------------------------------------------------------------------
// <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;
    }
}

The way with the 2 for loops is not working for me, am I missing something? The first code sample works for me, I am unsure is this really the right way to call this method? This part is causing my confusion:

DHCP_IP_ARRAY info = enumInfo[0]

Is this valid to access the pointer like an array? basically I am passing the value from the pointer to the struct. Does this assign all needed values to the sruct? Does a pointer only hold one value in the index 0 ? I am wondering if this will work with other methods form the dhcpsapi.dll and will the index 0 give me all results?

According to DhcpEnumSubnets function, EnumInfo is a pointer to a DHCP_IP_ARRAY structure and it is valid to access the pointer like an array.
Yes, this assigns all needed values to the sruct and whether a pointer only holds one value in the index 0 or not depends on DhcpEnumSubnets function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM