views:

398

answers:

3

I have a "const char* str" with a very long string. I need to pass it from a cpp client to a .Net COM method which expects BSTR type. Currently I use:

CComBSTR bstr = str;

This has the following issues:

  • Sometimes this line fails with out of memory message
  • When I pass the bstr to the COM class it takes a lot of memory (much more than the string size) so it can fail with out of memory

Questions:

  • Am I converting to CComBSTR wisely? e.g. is there a way to use the heap or something
  • Is it better to use BSTR instead?

Any other suggestion is also welcomed...

A: 

A CComBSTR is a wrapper around a BSTR which in turn is counted Unicode string with special termination.

You would thus expect it to be about twice the size of the corresponding char* form (for character sets that mainly use single-byte characters).

Using a CComBSTR is a good idea in general, since the destructor will free the memory associated with the BSTR for you.

Steve Gilham
The problem is more with passing the value to the COM object, are there any more implicit duplications to the BSTR done there?
Yaron Naveh
+1  A: 

Is it an In-Process COM server do you have the code for it or is it a 3rd party? because you can pass the actual char* pointer to the COM server and not pay the price of allocate+copy+free. You will need to add a new method/property that will be available only to C++ clients.


Instead of passing BSTR you can wrap your char* in a Stream interface, the .NET server should get a Stream instead of a string.

On the C++ side implement a COM class that support the IStream COM interface, this class is a read only stream which wraps the char*, you can pass this class as UCOMIStream interface to the .NET server.
On the .NET side use the UCOMIStream methods to read the string, be careful not to read the entire stream in one pass.

Shay Erlichmen
how can I do this? the signature shows me that I need to pass BSTR.
Yaron Naveh
I've modified my answer to clearly my idea.
Shay Erlichmen
the server is in .Net and client in cpp
Yaron Naveh
can you add the information to question?
Shay Erlichmen
I have added it
Yaron Naveh
how would the Stream interface look like, it is also a COM interface so which types will it use in the signature?
Yaron Naveh
+1  A: 

If a method is expecting a BSTR passing a BSTR is the only correct way.

To convert char* to a BSTR you use MultiByteToWideChar() Win32 API function for conversion and SysAllocStringLen() for memory allocation. You can't get around that - you need SysAllocStringLen() for memory allocation because otherwise the COM server will fail if it calls SysStringLen().

When you use CComBSTR and assign a char* to it the same sequence is run - ATL is available as headers and you can enjoy reading it to see how it works. So in fact CComBSTR does exactly the minimal set of necessary actions.

When you pass a BSTR to a COM server CComBSTR::operator BSTR() const is called that simply returns a pointer to the wrapped BSTR - the BSTR body is not copied. Anything that happens next is up to the COM server or the interop being used - they decide for themselves whether they want to copy the BSTR body or just read it directly.

Your only bet for resolving the memory outages is to change the COM interface so that it accepts some reader and requests the data in chunks through that reader.

sharptooth