使用COM互操作编组从C++到C#的BSTR

And*_*son 6 c# c++ com interop atl

我有一个用C++编写的进程外COM服务器,它由一些C#客户端代码调用.其中一个服务器接口上的方法将大型BSTR返回给客户端,我怀疑这会导致内存泄漏.该代码有效,但我正在寻找有关编组BSTR的帮助.

简化一下,服务器方法的IDL是

HRESULT ProcessRequest([in] BSTR request, [out] BSTR* pResponse);
Run Code Online (Sandbox Code Playgroud)

并且实现如下:

HRESULT MyClass::ProcessRequest(BSTR request, BSTR* pResponse)
{
    USES_CONVERSION;
    char* pszRequest = OLE2A(request);
    char* pszResponse = BuildResponse(pszRequest);
    delete pszRequest;
    *pResponse = A2BSTR(pszResponse);
    delete pszResponse;
    return S_OK;
}
Run Code Online (Sandbox Code Playgroud)

A2BSTR在内部使用SysAllocStringLen()分配BSTR.

在C#客户端中,我只需执行以下操作:

string request = "something";
string response = "";
myserver.ProcessRequest(request, out response);
DoSomething(response);
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为请求字符串被发送到COM服务器并且正确的响应字符串被返回给C#客户端.但是每次往服务器的往返都会泄漏服务器进程中的内存.crt泄漏检测支持显示crt堆上没有重大泄漏,所以我怀疑泄漏是用IMalloc分配的.

我在这里做错了吗?我发现含糊的评论说'所有的参数必须用CoTaskMemAlloc分配,否则互操作编组将不会释放它'但没有细节.

安迪

Kim*_*man 2

安尼尔森已经很好地阐述了这一点,但我想补充几点;

  • CoTaskMemAlloc 不是唯一的 COM 友好分配器——BSTR 被默认编组器识别,并且将使用 SysAllocString 等来释放/重新分配。

  • 避免 USES_CONVERSION (由于堆栈溢出风险 - 请参阅 anelson 的答案),您的完整代码应该是这样的 [1]

(请注意,A2BSTR 可以安全使用,因为它在转换后调用 SysAllocString,并且不使用动态堆栈分配。此外,使用数组删除 (delete[]),因为 BuildResponse 可能会分配一个字符数组)

  • BSTR 分配器有一个缓存,可能会使其看起来好像存在内存泄漏。请参阅http://support.microsoft.com/kb/139071了解一些详细信息,或访问 Google 了解 OANOCACHE。您可以尝试禁用缓存并查看“泄漏”是否消失。

[1]

HRESULT MyClass::ProcessRequest(BSTR request, BSTR* pResponse)
{
    char* pszResponse = BuildResponse(CW2A(request));
    *pResponse = A2BSTR(pszResponse);
    delete[] pszResponse;
    return S_OK;
}
Run Code Online (Sandbox Code Playgroud)