我正在编写用C ++编写COM的API,还编写一个在C#中使用这个API的程序。我的问题是关于将BSTR传递给COM函数时的BSTR内存管理语义。说我的IDL看起来像:
HRESULT SomeFunction([in] BSTR input);
目前这个功能是这样实现的:
HRESULT SomeFunction(BSTR input) {
// Do stuff ..., then:
SysFreeString(input);
}
当我使用类似SomeFunction(myString)
之类的C#调用它时,C#会生成类似这样的内容(伪代码):
myString = SysAllocString("string");
SomeFunction(myString);
或者更喜欢这样:
myString = SysAllocString("string");
SomeFunction(myString);
SysFreeString(myString);
也就是说,C#是否释放它生成的BSTR来编组COM接口,还是应该在我的函数中释放它?谢谢!
答案 0 :(得分:14)
来自Allocating and Releasing Memory for a BSTR:
当你调用一个需要
BSTR
参数的函数时,你 必须在通话之前为BSTR
分配内存 之后发布它。 ...
所以如果是输入参数,请不要释放它。 C#(以及使用COM对象的任何其他运行时)必须遵守用于管理内存传入和传出COM对象的COM约定,因此必须管理字符串的内存(如果它是输入参数)。否则,COM对象如何知道它是从C#或其他语言运行库调用的?
其他google-fu出现了这个问题:Marshaling between Managed and Unmanaged Code
...关于所有权问题,CLR遵循COM风格 约定:
- 作为[in]传递的内存由调用者拥有,并且应该都是
由呼叫者分配并由呼叫者释放。被叫者应该是 不要试图释放或修改那个记忆。- 被叫方分配的内存,并作为[out]传递或返回 由调用者拥有,应由调用者释放。
- 被叫方可以释放作为[in,out]从调用方传递的内存, 为它分配新的内存,并覆盖旧的指针值, 从而将它传递出去。新内存由调用者拥有。这个 需要两个间接级别,例如char **。
在互操作世界中,调用者/被调用者变为CLR /本机代码。规则 以上暗示在未固定的情况下,如果在本机代码中你 收到指向传递给你的内存块的指针,作为[out] CLR,你需要释放它。另一方面,如果CLR收到了 一个从本机代码传递为[out]的指针,CLR需要为 释放它。显然,在第一种情况下,本机代码需要执行 取消分配,在第二种情况下,托管代码需要执行 解除分配。
因此CLR遵循内存所有权的COM规则。 QED。
答案 1 :(得分:0)
您是从C#开发人员还是从C ++开发人员的角度来看。
在处理COM +时,C#开发人员不必担心任何内存管理。
在C ++中创建COM +组件,您不必知道谁在调用您,内存语义是相同的。如果它是in参数,则调用者负责管理内存,无论它是C ++还是C#。在C#中,CLR为它们负责。