编组包含 ByValTStr 字符串的结构时是否需要调用 Marshal.DestroyStructure

Do I need to call Marshal.DestroyStructure when marshalling structures containing ByValTStr strings

我正在为从 C#/.NET 到非托管 DLL 的互操作做一些手动封送处理。

考虑以下结构:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct LockInfo
{
    ushort lockVersion;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    public string lockName;
}

我将其编组到非托管内存:

var lockInfo = new LockInfo();
var lockInfoPtr = Marshal.AllocHGlobal(Marshal.SizeOf(lockInfo));
Marshal.StructureToPtr(lockInfo, lockInfoPtr, false);

完成后,我是否需要在 lockInfoPtr 上调用 Marshal.DestroyStructure

我知道需要调用 Marshal.FreeHGlobal,但在此之前,在这种情况下实际上需要 Marshal.DestroyStructure 吗?

我发现很难理解微软的 documentation 围绕这一点。 Google 搜索没有帮助,可能是因为我还不太了解编组(但我正在学习)。

类似问题...

我已经查看了类似的问题“”,但是这个问题没有解决 content 结构应该包含的问题,这需要使用 DestroyStructure。我有限的理解是 DestroyStructure 并不总是需要调用,只有当结构包含某些类型的字段时才需要调用。在我的例子中,我不确定一个被编组为 ByValTStr 的字符串是否需要使用 DestroyStructure.

编组是个复杂的东西,一个完整的答案可能会写一整本书的一章,当然这在这里不合适。所以,简而言之:

通常,当从托管代码调用本机函数时,.NET 会将字符串和数组编组为本机 BSTR 字符串和 SafeArray 数组。

为此,封送拆收器分别调用 SysAllocString and SafeArrayCreate

在某些时候,当不再需要这些本机端字符串和数组时,封送拆收器将分别调用 SysFreeString and SafeArrayDestroy 来释放内存。

如果您接管 .NET 的自动封送处理,并调用类似 Marshal.StructureToPtr to manually marshal a structure, you become responsible for freeing/destroying those native-side BSTRs and SafeArrays. That's exactly what Marshal.DestroyStructure 的方法。

然而...

通过将 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] 属性添加到您的字符串字段,您指示编组器 将字符串编组为 BSTR 字符串,而是分配一个固定的-本机端结构本身中的长度字符数组。

既然如此,就没有必要调用Marshal.DestroyStructure,因为没有要释放的BSTR 字符串。当然,你仍然需要调用 Marshal.FreeHGlobal,我看你已经知道了。

感谢 @SimonMourier 他的评论让所有内容都点击了。