编组包含 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 他的评论让所有内容都点击了。
我正在为从 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 搜索没有帮助,可能是因为我还不太了解编组(但我正在学习)。
类似问题...
我已经查看了类似的问题“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 他的评论让所有内容都点击了。