【问题标题】:Convention for passing BSTRs into COM functions from C# (COM interop)从 C# 将 BSTR 传递到 COM 函数的约定(COM 互操作)
【发布时间】:2011-10-25 09:23:40
【问题描述】:

我正在用 C++ 在 COM 中编写 API,并且还在 C# 中编写使用该 API 的程序。我的问题是关于将 BSTR 传递给 COM 函数时的 BSTR 内存管理语义。假设我的 IDL 看起来像:

HRESULT SomeFunction([in] BSTR input);

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

HRESULT SomeFunction(BSTR input) {
    // Do stuff ..., then:
    SysFreeString(input);
}

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

myString = SysAllocString("string");
SomeFunction(myString);

或者更确切地说是这样的:

myString = SysAllocString("string");
SomeFunction(myString);
SysFreeString(myString);

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

【问题讨论】:

    标签: c# c++ com com-interop


    【解决方案1】:

    来自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。

    【讨论】:

    • 这个答案与 CLR 自动为互操作执行的操作无关,这是 OP 所要求的全部内容。
    • @Alf :事实上,描述手动 COM 内存管理的文档与关于 CLR可能或可能不代表您做什么的问题无关。即,问题是关于 CLR COM 编组的,而这个答案不是。
    • @ildjarn,问题是是否释放COM接口中的参数。答案是否定的,因为 CLR 对参数的内存所有权使用 COM 约定。事实上,这是一个实际的问题:“也就是说,C# 是释放它生成的 BSTR 以编组到 COM 接口,还是应该在我的函数中释放它?谢谢!”
    • CLR 管理通过 COM+ 提供的内存,不是吗?这个问题是关于你需要在 C# 中做什么。在 C# 中,是否需要释放 out 参数? CLR 会为您做到这一点,不是吗?如果答案是肯定的,否定的,肯定的——关于 CLR 和 COM+ 内存管理的 cmets 是没有用的,因为它们没有回答关于 C# 的问题。 QED
    • 好吧,我是从 C# 开发人员的角度来阅读它的,“我应该在我的函数中释放它吗?” - 不,CLR 应该为你做这件事。再读一遍后,我相信他是在问是否应该从他的 C++ 函数中释放它,这取决于它是从 C# 还是 C++ 调用的。如果这确实是他的意思,那么你的回答就很合理了。
    【解决方案2】:

    您的意思是从 C# 开发人员的角度还是从 C++ 开发人员的角度。

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

    在 C++ 中创建一个 COM+ 组件,您不必知道是谁在调用您,内存语义是相同的。如果是 in 参数,则调用者负责管理内存,无论是 C++ 还是 C#。在 C# 中,CLR 会替他们处理。

    【讨论】:

      猜你喜欢
      • 2010-11-20
      • 2011-06-28
      • 1970-01-01
      • 2019-02-12
      • 2010-12-14
      • 1970-01-01
      • 2012-12-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多