Marshal.StringToHGlobalUni

Marshal.StringToHGlobalUni 是 .NET 中 System.Runtime.InteropServices.Marshal 类的一个静态方法。

它的作用是:将托管字符串(System.String)复制到非托管内存中,使用 Unicode(UTF-16)编码,并返回指向该内存的指针(IntPtr

分配的内存来自进程的全局堆(GlobalAlloc),通常用于 COM 互操作或需要与 C/C++ 代码交换宽字符串的场景。

方法签名

public static IntPtr StringToHGlobalUni(string? s);
  • 参数 s:要复制的托管字符串。

  • 返回值:指向非托管内存中字符串副本的指针(IntPtr)。如果输入 s 为 null,则返回 IntPtr.Zero

与相似方法的区别

方法编码内存分配器用途
StringToHGlobalUni UTF-16 (Unicode) LocalAlloc / 全局堆 默认的 Windows 宽字符串(wchar_t*
StringToHGlobalAnsi ANSI (当前代码页) LocalAlloc 传统 C 字符串(char*
StringToCoTaskMemUni UTF-16 COM 任务分配器 与 COM BSTR 或 CoTaskMemAlloc 配对
StringToCoTaskMemAnsi ANSI COM 任务分配器 同上

 

内存管理(非常重要)

  • 用 StringToHGlobalUni 分配的非托管内存必须手动释放,否则会造成内存泄漏。

  • 释放方法:调用 Marshal.FreeHGlobal(IntPtr ptr)

  • 因为分配的是非托管内存,GC 不会自动回收,务必在 finally 或 using 等确保释放的代码块中调用 FreeHGlobal

典型使用场景(C# 调用 C++ DLL)

假设 C++ 函数接收一个宽字符串参数:

extern "C" __declspec(dllexport) void PrintText(const wchar_t* text);

C# 端调用时:

[DllImport("MyDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void PrintText(IntPtr text);

string message = "Hello, C++!";
IntPtr ptr = Marshal.StringToHGlobalUni(message);
try
{
    PrintText(ptr);
}
finally
{
    Marshal.FreeHGlobal(ptr);
}

也可以直接用 [MarshalAs(UnmanagedType.LPWStr)] 让 P/Invoke 自动处理,不需要手动 StringToHGlobalUni

[DllImport("MyDll.dll", CharSet = CharSet.Unicode)]
public static extern void PrintText(string text);

但手动方式适合需要持久化指针或精细控制内存生命周期的场合。

注意事项

  • 返回的指针指向的是字符串的副本,修改非托管内存不会影响原始托管字符串。

  • 字符串末尾会自动添加一个 null 终止符\0),因此 C++ 端可以作为常规 wchar_t* 使用。

  • 分配的字节长度 = (s.Length + 1) * sizeof(wchar_t)

  • 如果频繁调用,建议考虑缓存或使用 System.Buffers 等方案避免大量小对象分配。

一句话总结

Marshal.StringToHGlobalUni 将 .NET 字符串转为非托管的 wchar_t*(UTF-16),返回 IntPtr,需配合 Marshal.FreeHGlobal 手动释放内存。

posted @ 2026-05-29 16:18  家煜宝宝  阅读(9)  评论(0)    收藏  举报