CBSTR StringBuilder Class

Started by Paul Squires, July 09, 2016, 11:45:45 PM

Previous topic - Next topic

José Roca

Now that I think about it, CBStrBld is not an adequate name because it is not a BSTR. I choose that name because it was planned as an auxiliary class to CBSTR, but now it has become a new data type.

What about CWStr or CWString?

Which name do you prefer?

José Roca

Quote from: Jose Roca on July 11, 2016, 09:52:05 AM
Quote from: TechSupport on July 11, 2016, 08:37:35 AM
Thanks Jose! Excellent job. Thanks for making the class even more useful!

I have been using the CBSTR class in some new editor code and the there have only been a couple of places where the compiler complained. For example, the Dir() function needs the double asterisk to deference. I believe you have also identified Left() and Right(). Nonetheless, I use CBSTR for situations where I need a dynamic Unicode string, otherwise I simply use wstrings.


I have added to it almost all the functionality of CBSTR. We can consider CBStrBld as a dynamic WSTRING. What it lacks is the ability to pass it to a COM method or function that has a BYREF BSTR parameter. With CBSTR we can use @cbs, that passes the adress of the underlying BSTR stored in the CBSTR class, but we can't do it with CBStrBld because the underlying type is not a BSTR, although we probably could use it with methods or functions that have a byref WSTRING parameter.

Therefore, we have now two new data types, a BSTR and a dynamic WSTRING.


Another difference is that CBSTR can work with strings with embedded nulls and this new data type not.

James Fuller

Jose,
  I vote for CWStr.
Would the rule of thumb be for non-COM we use CWStr and for COM CBStr?

James

José Roca

Not all COM interfaces use BSTRs. Most low-level ones use WSTRINGS, with the particularity that must be freed with CoTaskMemFree, in general. I would use CWSTR when speed is needed, such in the string functions, and CBSTR in the other cases, because as BSTRs carry with them its length, they can be used as a buffer for images and other binary files. Also when you pass them to a function you don't need to specify its length or how many characters have to be copied, and you don't have the risk of buffer overruns.



James Fuller

Jose,
  You mention the compiler balks on left,right for CBStr's and we must use **cbs.
Can you not overload them as you did LEN ?

James

José Roca

They're not overdoloadable. However, you can use MID, that works, or **.

José Roca

#21
Quote from: James Fuller on July 11, 2016, 11:01:03 AM
Jose,
  I vote for CWStr.

James


Well, we have two votes. I think I will use it. It is short and it matches with its CBSTR counterpart.

I also have added the @ operator, so now we can do things like


DIM sb AS CWSTR = 260
GetWindowText(pWindow.hWindow, @sb, 260)
MessageBox 0, sb, "", MB_OK


This is a big advantage over WSTRINGs, that must be dimensioned at compile time and its size can't be changed at runtime. Wow! Dynamic null terminated unicode strings.

James Fuller

Quote from: Jose Roca on July 11, 2016, 11:30:01 AM
They're not overdoloadable. However, you can use MID, that works, or **.
Yes I say that.
How about cLeft and cRight macros that use MID? I just don't like ** :)

James

José Roca

#23
And I don't like macros, but you can write as many as you wish.

If I write a macro called cLeft, I will have to pray that nobody will use it as a variable name, or as another macro... Macros are a can of worms.

You can also request a change in the compiler. Doesn't make much sense that MID works and LEFT and RIGHT not.

José Roca

#24
Done. Name officially changed to WSTR (or WStr, for VB lovers).

I also have implemented the @ operator, so WSTRs can be passed as parameters to functions that expect a WSTRING by reference (or a pointer to a unicode null terminated string, for C lovers).

José Roca

#25
I have added another constructor.

Now WSTR and CBSTR collaborate even better and are very handy to write wrappers that return unicode strings. For example:


' ========================================================================================
' Gets the text of a window.
' Note: GetWindowText cannot retrieve the text of a control in another application.
' ========================================================================================
FUNCTION AfxGetWindowText (BYVAL hwnd AS HWND) AS CBSTR
   DIM nLen AS LONG = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0)
   DIM wszText AS CWSTR = SPACE(nLen + 1)
   SendMessageW(hwnd, WM_GETTEXT, nLen + 1, cast(LPARAM, *wszText))
   FUNCTION = wszText.Str
END FUNCTION
' ========================================================================================


That can be called as


DIM wszText AS CBSTR = AfxGetWindowText(hwnd)
AfxMsg wszText


and, with the new constructor, even as


DIM wszText AS CWSTR = AfxGetWindowText(hwnd)
AfxMsg wszText


CWSTR can also be used as the return type of the function, but in both cases you have to return FUNCTION = wszText.Str and not FUNCTION = wszText, or it will GPF.

James Fuller

Jose,
  Check your comments in CBStr.inc especially for the CWStr. A number of references to BSTR when I think you mean CWSTR?

James

José Roca

For example? I don't see anything wrong.

James Fuller

I guess I just don't understand the functionality:

' ========================================================================================
' One * returns the value of the BSTR pointer.
' Two ** returns the adress of the start of the string data.
' Needed because LEFT and RIGHT (cws) fail with an ambiguous call error.
' We have to use **cws (notice the double indirection) with these functions.
' ========================================================================================
OPERATOR * (BYREF cws AS CWstr) AS WSTRING PTR
   OPERATOR = cast(WSTRING PTR, cws.m_pBuffer)
END OPERATOR
' ========================================================================================

' ========================================================================================
' Assigns new text to the BSTR
' ========================================================================================
OPERATOR CWstr.Let (BYREF wszStr AS CONST WSTRING)
   this.Clear
   this.Add(wszStr)
END OPERATOR
'

José Roca

You're correct. These are recent additions that I copied/adapted from CBSTR. I have modified them and a couple of others.