OK - i didn´t know or at least i didn´t understand that!
so, when getting passed a CBstr (or an OLE wide string) like this
Code: [Select]
FUNCTION somefunc(b as CBstr) AS LONG
DIM b1 as CBstr = b
...
b1 is not a copy of b (as i would expect) but is in fact b itself, because only the OLE handle has been copied and not the data. This means when b1 goes out of scope, b is destroyed as well.
No. In this case, b1 will be a copy. As both b and b1 are CBSTRings, this is the constructor that will be called:
PRIVATE CONSTRUCTOR CBStr (BYREF cbs AS CBStr)
m_bstr = SysAllocString(cbs)
END CONSTRUCTOR
Otherwise, both b and b1 will try to free the same memory!
CBSTR will aso make a copy if the parameter is a CWSTR, an ANSI string, a literal or a WSTRING, but will attach it if the passed parameter is a BSTR (although the parameter has been declared as a WSTRING because FB does not natively support BSTRings).
if this is for special cases only, wouldn´t it have been better to have a special "attach" operator for exactly these special cases, instead of making it a standard behavior, which opens unexpected traps.
The constructor has an optional fAttach parameter:
CONSTRUCTOR CBStr (BYREF bstrHandle AS AFX_BSTR = NULL, BYVAL fAttach AS LONG = TRUE)
When calling a COM function that returns a BSTR, you can do
DIM cbs AS CBSTR = <some function> ' fAttach defaults to TRUE
or
DIM cbs AS CBSTR = (<some function>, FALSE)
but how are you going to pass this parameter when using the FB intrinsic string functions?
how does PowerBASIC handle this situation?
PowerBasic natively supports BSTRings and knows when it has to allocate an free them. If FB had also native support for BSTRings there will be no problems, but as it only supports WSTRINGs, its intrinsic functions are prepared to free the termporary WSTRINGs that they generate, but they have no idea of what to do with BSTRings.
I think, your approach was to have a separate OLE wide string type ONLY for COM, not only because it must be an OLE string, but also for implementing automatic freeing of the passed string handle. That is, when using CBstr with COM you don´t have to care about when to free passed strings and when not to - your CBstr does it automatically for you. Is this correct ?
Yes, and also for efficiency. If the return type is a CBSTR, I can simply return a BSTR, that will be attached. Otherwise, I will have to create a temporary CBSTR, copy the contents of the BSTR to it, free the BSTR and return the temporary CBSTR, whose contents will be copied again.
The reason i defined USTRING as CBstr (and not as CWstr, which of course is possible) is, that i hoped to have a "one for all" wide string type. A type which basically works everywhere, without having to makes decisions where to use this and where to use that. When it´s about heavy string manipulation and i want more speed i can always implement CWstr for this - that´s the idea behind it.
I know, but I have warned you that they are not interchangeable. BSTRings are managed by te Windows COM library, not FreeBasic. The first string class that I tried to write was CBSTR and I did lose countless hours trying to solve all the problems. Finally, I decided to write CWSTR for general use and relegate CBSTR for COM use.
Of course, you can try to write your "interchangeable" BSTR class. If you still have some hair in your head, you will lose it.