使用MarshalAs(UnmanagedType.LPWStr)会清理内存吗?

问题描述 投票:0回答:1

我正在尝试为 ITaskTrigger::GetTriggerString 方法编写一个 pinvoke(定义于 http://msdn.microsoft.com/en-us/library/windows/desktop/aa381866(v=vs.85).aspx )。如果您查看该页面,它会显示该方法的调用者负责释放通过第一个参数引用的 LPSTR 的内存(通过 CoTaskMemFree)。虽然我可以在 .NET 中手动执行此操作,或者可以使用 ICustomMarshaler 编写自定义封送拆收器,但我想知道对该特定参数使用 MarshalAs(UnmanagedType.LPStr) 属性是否会适当释放内存。

任何人都可以提供一些见解吗?

c# pinvoke marshalling
1个回答
7
投票

首先要做的事情是:这里讨论的是 COM Interop(

ITaskTrigger
是 COM 接口),而不是 P/Invoke。两者有不同的互操作规则,因此保持它们的一致性很重要。例如,您需要为整个接口定义 C# 互操作包装器,而不仅仅是您想要的方法。这些应该可以帮助您入门:pinvoke.net

简短的回答是,您很幸运,因为 CLR 应该为您妥善处理事情。

较长的答案涉及 COM 互操作代码执行的不同类型的编组,具体取决于参数类型、方向以及添加到互操作签名中的属性。

在这种情况下,您将在调用中获得的参数类型是“

out string
”参数,具有
MarshalAs(UnmanagedType.LPWSTR)
属性。当 COM 服务器公开具有
LPWSTR
字符串类型的“out”参数的调用时,假设服务器正在处理其交易结束,它将分配一个带有
CoTaskMemAlloc()
的内存缓冲区并将其返回给您。 (如果是不同的字符串类型,例如
BSTR
,具体的内存分配调用可能会有所不同,但基本概念是相同的。)此时,您有责任在不再需要该内存时清理该内存它,使用匹配的
CoTaskMemFree()
调用。

这是一种特殊类型的操作,称为“引用更改”:您发送的参数已经是引用参数,但 COM 服务器将用“不同”引用来“替换”它。 这篇 MSDN 杂志文章 的“内存所有权”部分对此过程有很好的解释。正如您从该文章中看到的,当 CLR 从引用类型的“out”参数接收回数据时,它会认识到它正在负责释放该内存。在封送该回调到托管代码时,它使用 MarshalAs 属性来确定这是 COM 中的 LPWSTR 字符串类型指针,因此应该使用

CoTaskMemAlloc()
对其进行分配。从数据中创建托管字符串后,它将代表您在原始缓冲区上调用
CoTaskMemFree()
。您取回的数据将得到全面管理,您无需处理任何所有权问题。
    

© www.soinside.com 2019 - 2024. All rights reserved.