COM内存管理

时间:2011-08-25 19:02:54

标签: memory-management com

我对COM内存管理有一些疑问:

  1. 我有一个COM方法:

    STDMETHODIMP CWhitelistPolicy :: GetWebsitesStrings(SAFEARRAY **结果)

  2. result = SAFEARRAY(BSTR)。如果我从另一个接口方法(为了设置*结果)收到另一个SAFEARRAY(BSTR),我是否必须复制收到的字符串,以便将它们传递给*结果和外部客户端?或者考虑到我不会自己使用字符串,我可以将它们传递给客户端(并传递所有权)?

    2

    STDMETHODIMP CWhitelistPolicy::SetWebsitesStrings(SAFEARRAY* input)
    

    这里我收到一个BSTR数组作为输入。我的方法再次负责输入中分配的内存?

    3

    STDMETHOD(SetUsers)(SAFEARRAY* input);
    

    这里我在另一个接口(SetUsers)上调用一个方法,并为输入SAFEARRAY分配内存。我打电话给SetUsers后我可以处理SAFEARRAY吗?在编组发生时总是复制内存不是吗? (在我的情况下,在我的进程中作为COM DLL托管的接口上调用SetUsers方法)

1 个答案:

答案 0 :(得分:3)

我想回答这个问题的方法是考虑跨越机器的COM调用。然后它显然是一个[out] param;我的调用者拥有并且必须释放内存,因为远程编组层无法执行此操作。对于[in]参数,显然编组层必须复制我的数据,并且远程封送层不能再释放我传入的内容。

COM中的核心原则是位置中立,在同一公寓中呼叫的规则是跨机器使用DCOM时的规则。

  1. 您有责任免费 - 当您拨打下一个fnc时,您没有通过所有权,因为它可能是远程的并且是获取副本,而不是原始数据。

  2. 不 - 作为被叫方,您不必释放它。如果是公寓内部,则是呼叫者提供的内存,呼叫者必须释放它。如果是远程调用,则服务器存根会分配它,并在方法返回时释放它。

  3. 是的,你释放它 - 不,它并不总是被复制(可能是),这就是为什么2的答案是否定的原因。如果它被复制,则会分配一个存根,存根将释放它。

  4. 请注意,我对您的问题的回答并未涉及[in,out]参数的情况 - 有关此案例的更多详细信息,请参阅问题Who owns returned BSTR?

    Com allocation rules复杂但理性。如果您想了解/查看所有案例的示例,请获取Don Box的书“必备com”。你仍然会犯错误,所以你应该有一个检测它们的策略。我使用gflags(Windbg的一部分)及其堆检查标志来捕获何时发生双重释放(显示调试消息并在使用INT 3的调用时暂停执行)。 Vstudio的调试器用于在启动可执行文件时打开它们(它可能仍然可以)但你可以在图像选项选项卡下用gflags强制它们。

    您还应该知道如何使用UMDH(也是windbg的一部分)来检测泄漏。 DebugDiag是更新的工具,似乎更容易使用,但遗憾的是,您只能安装32位或64位版本,但不能同时安装。

    然后问题是BSTR,它被缓存,使得检测双重释放和泄漏变得棘手,因为与堆的交互被延迟。您可以通过将环境变量OANOCACHE设置为1或调用函数SetOaNoCache来关闭ole字符串缓存。该函数未在头文件中定义,因此请参阅此问题Where is SetOaNoCache defined?。请注意,接受的答案显示了通过GetProcAddress()调用它的困难方法。接受的答案下面的答案显示你需要的是一个extern“C”,因为它在oleaut32 export lib中。最后,请参阅this Larry Osterman博客文章,了解缓解漏洞时缓存所带来的困难。