Click to See Complete Forum and Search --> : How to Convert from OLECHAR* to BSTR


Ajit Kumar M R
April 21st, 1999, 01:05 AM
I have a set of Interfaces which have OLECHAR* parameters. I have come to realize that to make automation compatible, we have to use BSTR and i need to do these conversions.
Could you please tell me what are the steps involved to do these conversion. Especially the Memory Allocation and Freeing.

Dave Lorde
April 21st, 1999, 04:07 AM
A BSTR is an LPCOLESTR, a const OLECHAR*.

Look at AtlBase.h for conversions using CComBSTR
Look at ComUtil.h for conversions using _bstr_t
Look at AfxConv.h for AFX conversions between OLECHAR*, BSTR, and LPTSTR.

Dave

mdwilliams
April 21st, 1999, 09:59 AM
A BSTR is NOT an LPCOLESTR!!!

A BSTR is a pointer to a length-prefixed array of OLECHAR's. An OLESTR is simply a null terminated array of OLECHAR's (a wide character string).

Using an OLESTR as a BSTR can cause severe problems when it comes to marshalling since the marshaler can use the length to determine the length of the string.

Use OLE2BSTR ATL conversion macro and make sure to call ::SysFreeString() on the resulting BSTR when you are done with it.

Dave Lorde
April 21st, 1999, 11:09 AM
Beg yer pardon, my mistake for being misleadingly brief. There is the usual confusion between type and usage. By type, one is const WCHAR*, the other is non-const WCHAR*.

[BSTR is typedef'd as an OLECHAR*, which is defined as a char* or WCHAR*.
LPOLECSTR is defined as an LPCSTR, which is typedef'd as a const char* or const WCHAR*].

As you point out, the usage convention of allocating BSTR with SysAllocString means that the OLECHAR buffer it points to is prefixed with its length, but the BSTR type itself is just an OLECHAR*...

I was indirectly quoting Microsoft's comment in the CComBSTR Append implementation in ATLBase.h (line 3995):

HRESULT Append(LPCOLESTR lpsz)
{
return Append(lpsz, ocslen(lpsz));
}
// a BSTR is just a LPCOLESTR so we need a special version to signify
// that we are appending a BSTR
HRESULT AppendBSTR(BSTR p)
{
return Append(p, SysStringLen(p));
}
HRESULT Append(LPCOLESTR lpsz, int nLen)
{
int n1 = Length();
BSTR b;
b = ::SysAllocStringLen(NULL, n1+nLen);
if (b == NULL)
return E_OUTOFMEMORY;
memcpy(b, m_str, n1*sizeof(OLECHAR));
memcpy(b+n1, lpsz, nLen*sizeof(OLECHAR));
b[n1+nLen] = NULL;
SysFreeString(m_str);
m_str = b;
return S_OK;
}

This shows that, given the length (from SysStringLen), you can use a BSTR as an LPCOLESTR.

The normal usage is as you say. I guess it's better not to be burrowing in ATL's internals when answering such questions :-)

Dave

mdwilliams
April 21st, 1999, 11:52 AM
You are correct, BSTR is typedef'd as an OLECHAR*. Just didn't want there to be a confusion. I've seen strange COM crashes before that can be traced back to this problem.

Actually this also brings up an interesting point. Since BSTR are length-prefixed, they can contain enbedded NULL characters. CComBstr has a poor implementation of the Append function in that it doesn't take this into account.

Anyway, just had to give my $.02.

-- Matt

April 22nd, 1999, 08:45 AM
> I've seen strange COM crashes before that can be traced back to this problem.

Yes, you were right to pull me up on it.

> Since BSTR are length-prefixed, they can contain enbedded NULL characters.
> CComBstr has a poor implementation of the Append function in that it doesn't
> take this into account.

True, and the same applies to CString, which can contain NULLs, but most of its
manipulation functions call C runtime methods that expect NULL terminated strings...

> Anyway, just had to give my $.02.

I appreciate it, Matt. It made me stop and refresh my understanding of the whole
sorry COM/OLE/ATL strings business. It's a bit of a mess really.

Dave

P.S. Excuse the anonymous post, but this xxxx system won't accept my user name
and password from another machine!