问题描述
我正在用 C++ 在 COM 中编写 API,并且还在 C# 中编写使用该 API 的程序.我的问题是关于将 BSTR 传递给 COM 函数时的 BSTR 内存管理语义.假设我的 IDL 看起来像:
I am writing writing an API in COM in C++, and also writing a program which consumes this API in C#. My question is about BSTR memory management semantics when passing BSTRs into COM functions. Say my IDL looks like:
HRESULT SomeFunction([in] BSTR input);
目前这个功能是这样实现的:
Currently this function is implemented like this:
HRESULT SomeFunction(BSTR input) {
// Do stuff ..., then:
SysFreeString(input);
}
当我从 C# 中用 SomeFunction(myString)
之类的东西调用它时,C# 会生成类似这样的东西(伪代码):
When I call it from C# with something like SomeFunction(myString)
, will C# generate something like this (pseudocode):
myString = SysAllocString("string");
SomeFunction(myString);
或者更确切地说:
myString = SysAllocString("string");
SomeFunction(myString);
SysFreeString(myString);
也就是说,C# 是释放它生成的 BSTR 以编组到 COM 接口,还是应该在我的函数中释放它?谢谢!
That is, does C# free the BSTR that it generates to marshal to the COM interface, or should I free it inside my function? Thanks!
推荐答案
来自 为 BSTR 分配和释放内存:
当你调用一个需要 BSTR
参数的函数时,你必须在调用之前为 BSTR
分配内存,并且之后释放它....
When you call into a function that expects a
BSTR
argument, you must allocate the memory for theBSTR
before the call and release it afterwards. ...
所以如果是输入参数就不要释放它.C#(以及任何其他使用 COM 对象的运行时)必须遵守 COM 约定来管理内存传入和传出 COM 对象,因此如果字符串是输入参数,则必须管理字符串的内存.否则,COM 对象如何知道它是从 C# 或其他语言运行时调用的?
So don't free it if it is an input parameter. C# (and any other runtime that uses COM objects) must respect the COM convention for managing memory pass in and out of COM objects, and must therefore manage the memory for the string if it is an input parameter. Otherwise, how would a COM object know that it is being called from C# or some other language runtime?
其他 google-fu 出现了这个:托管和非托管代码之间的封送处理
Additional google-fu turned up this: Marshaling between Managed and Unmanaged Code
...关于所有权问题,CLR 遵循 COM 风格约定:
... Regarding ownership issues, the CLR follows COM-style conventions:
- 作为 [in] 传递的内存归调用者所有,并且应该是两者
由调用者分配并由调用者释放.被调用者应该
不要尝试释放或修改该内存. - 被调用者分配的内存并作为[out]传递或返回由调用者拥有,应由调用者释放.
- 被调用者可以从调用者那里释放以 [in, out] 形式传递的内存,为其分配新内存,并覆盖旧指针值,从而传递出去.新内存归调用者所有.这需要两级间接,例如 char **.
在互操作世界中,调用者/被调用者变为 CLR/本机代码.规则以上暗示在未固定的情况下,如果在本机代码中您
从
接收作为 [out] 传递给您的内存块的指针CLR,你需要释放它.另一方面,如果 CLR 收到
从本机代码作为 [out] 传递的指针,CLR 需要
释放它.显然,在第一种情况下,本机代码需要执行以下操作
取消分配,在第二种情况下,托管代码需要执行
取消分配.
In the interop world, caller/callee becomes CLR/native code. The rules
above imply that in the unpinned case, if when in native code you
receive a pointer to a block of memory passed to you as [out] from
the CLR, you need to free it. On the other hand, if the CLR receives
a pointer that is passed as [out] from native code, the CLR needs to
free it. Clearly, in the first case, native code needs to do the
de-allocation and in the second case, managed code needs to do
de-allocation.
所以 CLR 遵循 COM 的内存所有权规则.QED.
So the CLR follows the COM rules for memory ownership. QED.
这篇关于从 C# 将 BSTR 传递到 COM 函数的约定(COM 互操作)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!