the succinct description provided above, in conjunction with the official documentation, should be everything you will ever need to know to deal with bstrs. note that the expected usage pattern is the preventive allocation of an array of olechars, which is later copied into the system string.
basic strings must be allocated and freed manually. but who has the responsibility of doing so when function calls are involved? this is a general com question and so the answer does not apply solely to strings. if the parameter is input-only (idl attribute [in]) the caller is responsible for both the creation and the destruction of the variable. if the parameter is output-only (idl attribute [out]) then the callee is responsible for the allocation of the string, but the caller is expected to free it after use. if the parameter is both input and output (idl attribute [in, out]) then the caller allocates the string and after the method invocation frees the memory. the callee though is allowed to reallocate the string if necessary to do so before returning it to the caller.
obviously these details interest c/c++ developers only, as visual basic will continue to treat strings as usual without any special consideration.
bstr wrappers
both atl and mfc offer particular support for simplified bstr management. atl does it by means of a specialized wrapper class, ccombstr, whose declaration in atlbase.h looks like the following (stripped down as usual for clarity and space constraints):
class ccombstr {public: bstr m_str; ccombstr(); ccombstr(int nsize, lpcolestr sz = null); ccombstr(lpcolestr psrc); ccombstr(const ccombstr& src); ccombstr& operator=(const ccombstr& src); ccombstr& operator=(lpcolestr psrc); ~ccombstr(); unsigned int length() const; operator bstr() const; bstr* operator&(); bstr copy() const; void attach(bstr src); bstr detach(); void empty();#if _msc_ver>1020 bool operator!();#else bool operator!();#endif void append(const ccombstr& bstrsrc); void append(lpcolestr lpsz); void appendbstr(bstr p); void append(lpcolestr lpsz, int nlen); ccombstr& operator+=(const ccombstr& bstrsrc);#ifndef ole2ansi ccombstr(lpcstr psrc); ccombstr(int nsize, lpcstr sz = null); ccombstr& operator=(lpcstr psrc); void append(lpcstr);#endif hresult writetostream(istream* pstream); hresult readfromstream(istream* pstream);}; |
the utilization of the class is very straightforward even for the non-atl experts. basically the features offered are:
- encapsulation of the allocation and deallocation procedures within the constructor and destructor;
- duplication of the contents (through ccombstr::copy());
- possibility to append almost any kind of string to the wrapped bstr exploiting the overloading feature of c++;
- support for readable string comparisons through the customized ! operator;
- basic i/o operations to store the contents of the string to, and retrieve it from, a structured storage stream.
on the other hand, mfc does not provide any direct wrapper class for system strings. all the support is an integral part of the extremely versatile cstring class. as shown in the following code snippet borrowed from the class's prototype in afx.h, there are only a couple of methods specifically generating com strings:
// ole bstr support (use for ole automation) bstr allocsysstring() const; bstr setsysstring(bstr* pbstr) const; |