You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET调用Native DLL:如何释放含LPWSTR的结构体数组

Properly Releasing a Struct Array with LPWSTR Fields from a Native DLL in .NET

Hey there, let's walk through how to safely handle the allocation and cleanup of your ADDRESS_SET structure and its nested string fields when calling NativeDll.dll from .NET. The key here is to lean on the native cleanup function provided (FreeAddressSet) instead of trying to manually free memory from .NET, since the native code owns that memory.

Step 1: Define .NET Structs That Match the Native Layout

First, we need to mirror the native structs in C# with the correct memory layout and type mappings:

using System;
using System.Runtime.InteropServices;

// Matches the native _ADDRESS struct
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct ADDRESS
{
    // Use IntPtr for LPWSTR here—we don't want .NET to automatically free this memory
    public IntPtr City;
}

// Matches the native _ADDRESS_SET struct
[StructLayout(LayoutKind.Sequential)]
public struct ADDRESS_SET
{
    public uint AddressCount;
    // IntPtr points to the start of the ADDRESS array (PADDRESS in native code)
    public IntPtr AddressList;
}

Step 2: Declare the Native DLL Imports

Next, set up the DllImport definitions for the native functions, making sure the parameter types align correctly:

public static class NativeDllInterop
{
    // GetAddressSet returns a pointer to an ADDRESS_SET pointer, so we use out IntPtr
    [DllImport("NativeDll.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern uint GetAddressSet(out IntPtr addressSetPtr);

    // FreeAddressSet takes an ADDRESS_SET pointer—pass the IntPtr we received
    [DllImport("NativeDll.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern void FreeAddressSet(IntPtr addressSetPtr);
}

Step 3: Call the Native Function and Process the Data

Here's how to safely retrieve, process, and clean up the address data:

IntPtr addressSetPtr;
uint resultCode = NativeDllInterop.GetAddressSet(out addressSetPtr);

// Check if the call succeeded (adjust the success code based on your native DLL's specs)
if (resultCode != 0) // Assuming 0 is ERROR_SUCCESS
{
    throw new System.ComponentModel.Win32Exception((int)resultCode);
}

try
{
    // Convert the native ADDRESS_SET pointer to a .NET struct
    ADDRESS_SET addressSet = Marshal.PtrToStructure<ADDRESS_SET>(addressSetPtr);

    // Iterate through each ADDRESS in the AddressList array
    for (int i = 0; i < addressSet.AddressCount; i++)
    {
        // Calculate the pointer to the current ADDRESS in the array
        IntPtr currentAddressPtr = IntPtr.Add(addressSet.AddressList, i * Marshal.SizeOf<ADDRESS>());
        ADDRESS currentAddress = Marshal.PtrToStructure<ADDRESS>(currentAddressPtr);

        // Convert the LPWSTR (IntPtr) to a .NET string
        string cityName = Marshal.PtrToStringUni(currentAddress.City);
        Console.WriteLine($"Address {i+1}: {cityName}");
    }
}
finally
{
    // Critical: Always call the native cleanup function, even if an error occurs
    NativeDllInterop.FreeAddressSet(addressSetPtr);
}

Key Notes for Safe Cleanup

  • Never manually free native memory from .NET: Don't use Marshal.FreeHGlobal or Marshal.FreeCoTaskMem on addressSetPtr, AddressList, or City pointers. The native DLL allocated this memory, so only its FreeAddressSet function knows how to properly deallocate it (including freeing each LPWSTR city string and the struct arrays).
  • Use a finally block: This ensures FreeAddressSet gets called even if an exception is thrown while processing the data, preventing memory leaks.
  • Avoid reusing pointers after cleanup: Once you call FreeAddressSet, all pointers associated with the ADDRESS_SET are invalid—don't try to access them again.

内容的提问来源于stack exchange,提问作者Green Apple

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:12:49