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 手动释放内存。

浙公网安备 33010602011771号