.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.FreeHGlobalorMarshal.FreeCoTaskMemonaddressSetPtr,AddressList, orCitypointers. The native DLL allocated this memory, so only itsFreeAddressSetfunction knows how to properly deallocate it (including freeing eachLPWSTRcity string and the struct arrays). - Use a
finallyblock: This ensuresFreeAddressSetgets 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 theADDRESS_SETare invalid—don't try to access them again.
内容的提问来源于stack exchange,提问作者Green Apple
相关产品推荐
相关产品推荐

