Marshalling BSTR from C ++ to C # with COM Interoperability

I have a non-process COM server written in C ++ that is called by some C # client code. The method on one of the server interfaces returns a large BSTR to the client, and I suspect this is causing a memory leak. The code works, but I'm looking for help with marshalling BSTRs.

Simplifying the bit, the IDL method for the server

HRESULT ProcessRequest([in] BSTR request, [out] BSTR* pResponse); 

and the implementation is as follows:

 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; } 

A2BSTR internally allocates BSTR using SysAllocStringLen ().

In the C # client, I just do the following:

 string request = "something"; string response = ""; myserver.ProcessRequest(request, out response); DoSomething(response); 

This works, in this request, the lines are sent to the COM server, and the correct response lines are returned to the C # client. But every turn to server memory leaks in the server process. Crt leak detection support does not show significant leaks in the crt heap, so I suspect that the leak was allocated by IMalloc.

Am I doing something wrong here? I found vague comments that "all parameters should be allocated using CoTaskMemAlloc, otherwise the firewall will not release them," but no details.

Andy

+6
c ++ c # interop com atl
source share
3 answers

anelson applied this very well, but I wanted to add a couple of points:

  • CoTaskMemAlloc is not the only COM distributor friendly - BSTRs are recognized by default by the marshaller and will be freed / redistributed using SysAllocString and friends.

  • Avoid USES_CONVERSION (due to risks - see anelson answer), your complete code should be something like this [1]

(note that A2BSTR is safe to use, since it calls SysAllocString after conversion and does not use dynamic stack allocation. Also use array-delete (delete []), since BuildResponse probably allocates an array of characters)

  • The BSTR dispenser has a cache that can make it look like there is a memory leak. See http://support.microsoft.com/kb/139071 or Google for OANOCACHE for more details. You can try disabling the cache and see if the leak disappears.

[one]

 HRESULT MyClass::ProcessRequest(BSTR request, BSTR* pResponse) { char* pszResponse = BuildResponse(CW2A(request)); *pResponse = A2BSTR(pszResponse); delete[] pszResponse; return S_OK; } 
+2
source share

I do not see an obvious problem with your code. Suggest you modify the ProcessRequest method to exclude COM interaction as a leak source:

 HRESULT MyClass::ProcessRequest(BSTR request, BSTR* pResponse) { *psResponse = ::SysAllocStringLen(L"[suitably long string here]"); return S_OK; } 

I suspect this is not a leak, in which case you narrowed the leak into your code.

I would also like to note that OLE2A allocates memory on the stack, so you not only should not delete pszRequest, but should not use OLE2A at all because of the possibility. See this article for safer alternatives.

I also suggest replacing A2BSTR with :: SysAllocString (CA2W (pszResponse))

+3
source share

I think you need to destroy request with ::SysFreeString() . This memory is allocated on the server side.

In addition, OLE2A can allocate memory due to conversion (look). You also do not free him.

-4
source share

All Articles