将BSTR传递到C#(COM互操作)的COM函数的约定

fyh*_*ang 9 c# c++ com com-interop

我正在编写用C++编写COM的API,还编写一个在C#中使用这个API的程序.我的问题是关于将BSTR传递给COM函数时的BSTR内存管理语义.说我的IDL看起来像:

HRESULT SomeFunction([in] BSTR input);
Run Code Online (Sandbox Code Playgroud)

目前这个功能是这样实现的:

HRESULT SomeFunction(BSTR input) {
    // Do stuff ..., then:
    SysFreeString(input);
}
Run Code Online (Sandbox Code Playgroud)

当我用C#调用它时,C#SomeFunction(myString)会生成这样的东西(伪代码):

myString = SysAllocString("string");
SomeFunction(myString);
Run Code Online (Sandbox Code Playgroud)

或者更喜欢这样:

myString = SysAllocString("string");
SomeFunction(myString);
SysFreeString(myString);
Run Code Online (Sandbox Code Playgroud)

也就是说,C#是否释放它生成的BSTR来编组COM接口,还是应该在我的函数中释放它?谢谢!

MSN*_*MSN 15

为BSTR分配和释放内存:

当您调用需要BSTR参数的函数时,必须为BSTR调用之前分配内存并在之后释放它....

因此,如果它是输入参数,请不要释放它.C#(以及使用COM对象的任何其他运行时)必须遵守用于管理内存传入和传出COM对象的COM约定,因此必须管理字符串的内存(如果它是输入参数).否则,COM对象如何知道它是从C#或其他语言运行库调用的?

额外的google-fu发现了这一点:托管和非托管代码之间的密钥

...关于所有权问题,CLR遵循COM风格的约定:

  • 作为[in]传递的内存由调用者拥有,并且应由调用者
    分配并由调用者释放.被调用者不应该
    尝试释放或修改该内存.
  • 被调用者分配并作为[out]传递或返回的内存由调用者拥有,并应由调用者释放.
  • 被调用者可以释放作为[in,out]从调用者传递的内存,为其分配新内存,并覆盖旧指针值,从而将其传递出去.新内存由调用者拥有.这需要两个间接级别,例如char**.

在互操作世界中,调用者/被调用者变为CLR /本机代码.上面的规则意味着在未固定的情况下,如果在本机代码中,您
收到一个指向从
CLR 传递给您的内存块的指针,则需要释放它.另一方面,如果CLR收到
一个从本机代码传递为[out]的指针,则CLR需要
释放它.显然,在第一种情况下,本机代码需要进行
解除分配,而在第二种情况下,托管代码需要进行
解除分配.

所以CLR遵循内存所有权的COM规则.QED.