将bstr从c#传递到COM函数的约定(COM互操作)

本文关键字:COM 函数 约定 互操作 bstr | 更新日期: 2023-09-27 18:05:24

我正在用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接口,还是我应该在我的函数中释放它?谢谢!

将bstr从c#传递到COM函数的约定(COM互操作)

From分配和释放BSTR内存:

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

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

额外的google-fu发现了这个:托管和非托管代码之间的封送处理

…关于所有权问题,CLR遵循com风格约定:

  • 作为[in]传递的内存由调用者拥有,并且应该是
    由调用方分配,由调用方释放。被调用者应该
    不要试图释放或修改记忆。
  • 由被调用者分配并作为[out]传递或返回的内存归调用方所有,并且应该由调用方释放。
  • 被调用者可以释放从调用者那里传入的[in, out]内存。为它分配新的内存,并覆盖旧的指针值,从而把它传递出去。新的内存由调用者拥有。这需要两层间接,如char **。

在互操作世界中,调用者/被调用者变成了CLR/本机代码。规则上面暗示在未固定的情况下,如果在本机代码中

接收一个指向[out]传递给你的内存块的指针CLR,你需要释放它。另一方面,如果CLR接收到
从本机代码作为[out]传递的指针,CLR需要
免费的。显然,在第一种情况下,本机代码需要执行
在第二种情况下,托管代码需要执行
重新分配。

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

您是指从c#开发人员的角度还是从c++开发人员的角度?


c#开发人员在处理COM+时不应该担心任何内存管理。

在c++中创建一个COM+组件,你不必知道是谁在调用你,内存语义是一样的。如果它是一个in参数,调用者负责管理内存,无论它是c++还是c#。在c#中,CLR会为它们处理。