CBStr: a BSTR wrapper-class with string manipulation members

The MFC CString class, has some really nice string manipulation routines.
However, if you are trying to avoid the MFC for size/deployment issues, and having to do string manipulation
of BSTRs I’m sure that you will be finding the _bstr_t class frustratingly basic.

After doing a great deal of frustrated hair-pulling I finally got around to implementing this class, CBstr.
It is a C++ class derived from the MS VC++ _bstr_t COM support class with the added benefit of
a barrow-load of string manipulation methods. The original idea came after seeing Alex Stockton’s
NoMFC::CString class at www.WorldofATL.com. This class was used
as the template for the public interface.

The class uses the same public “interface” as the NoMFC::CString Class with a couple of minor
differences and as a result has all the functionality of the “real” (MFC) CString class with a few
extra’s. And because it is derived from _bstr_t

Because the class is derived from _bstr_t it is very easy to use instead of that class,
especially where string manipulation of any kind is required. If you are not planning on
using the string-manipulation functionality I would suggest sticking with the _bstr_t class
for reduced class size.

To use the class simply #include the CBstrImpl.h header file supplied in the Zip, and have
this and CBStr.h in your include path.

A demo program (and my test rig) follows and is included in the zip file. This exercises
all of the functionality of of the class, but for more information I would suggest looking
at the documentation of the MFC CString class – it doesn’t seem woth copying it out 😉

This code has been tested with Visual C++ 5.0 Service Pack 3, it has not been tested
with Visual C++ 6.0

Example code

// Main.cpp
//
// Test harness to execise the CBstr class
// derived from _bstr_t and based on the
// NoMFC::CString class from www.worldofatl.com
//
// If anyone can figure out why the ostream::operator<< refuses to
// use the implicit cast to const char* or char* then please email me
// at [email protected]
//
//
#include “CBstrImpl.h”
#include <iostream>

using std::cout;

const TCHAR* Test(const TCHAR* psz);

// This test only works in ANSI (not UNICODE) builds
// due to lack of _T() and stream insertion operator

int main()
{
// Create a proper BSTR
BSTR bstr = ::SysAllocString(L“Hello World”);

// Create two objects of out new class
CBstr newstr(bstr, true); //Take a copy of bstr
CBstr newstr2(bstr, false); //attach to bstr

// test the MakeUpper method
newstr2.MakeUpper();

// Extract the BSTR (this gives a reference
// to the encapulated BSTR, not a copy)
BSTR ptrcopy = newstr2;

// Take a copy of the encapsulated BSTR
BSTR deepcopy = newstr2.copy();

// Test cast to char *
char * ansistr = newstr2;

// Test cast to const char *
const char* ansicstr = newstr2;

// output results
cout << ansistr << “n” << ansicstr;
cout << newstr2;

// Create another string for testing
CBstr str(“twenty”);

// Call a method that takes a const char* parameter
Test(str);

// create another CBstr from the first
CBstr str2(str);

// output results
cout << (const char*)str << “n”;
cout << (const char*)str2 << “n”;

// test the format method
str.Format(“sder %d %s”, 1, “ss”);
cout << (const char*)str << “n”;

// test the length() method
CBstr s(“abcdef”);
cout << s.length() << “n”; // == 6

// test the isempty() method
CBstr s2;
cout << s2.IsEmpty() << “n”; // == true

// test the Empty method
CBstr s3(“abc”);
s3.Empty();
cout << s3.length() << “n”; // == 0

// Test GetAt() method
CBstr s4(“abcdef”);
cout << s4.GetAt(2) << “n”; // == ‘c’

// Test the operator[]
CBstr s5(“abc”);
cout << s5[1] << “n”; // == ‘b’
s5.SetAt(1, ‘X’);
cout << s5[1] << “n”; // == ‘X’

// test assignment operators
CBstr s6, s7; // Empty CBstr objects
s6 = “cat”; // s6 == “cat”
cout << (const char*)s6 << “n”;
s7 = s6; // s6 and s7 each == “cat”
cout << (const char*)s7 << “n”;

// test operator+()
s6 = “the “ + s6; // Or expressions
cout << (const char*)s6 << “n”;

// example for CBstr::operator +
CBstr s8(“abc”);
CBstr s9(“def”);
cout << (const char*)(s8 + s9 ) << “n”; // == “abcdef”
CBstr s10;
s10 = CBstr(“abc”) + “def” ; // == “abcdef”
cout << (const char*)s10 << “n”;

// example for CBstr::operator +=
CBstr s11(“abc”);
cout << (const char*)( s11 += “def”) << “n”; // == “abcdef”

// example for CBstr Comparison Operators
CBstr s12(“abc”);
CBstr s13(“abd”);
if (s12 < s13)
cout << “s12 < 13” << “n”; // == true Operator is overloaded for both.
if (“ABC” < s12)
cout << “ABC < s12” << “n”; // == true CBstr and char*
if (s13 > “abe”)
cout << “s13 > abe” << “n”; // == false
if (s13 == “abd”)
cout << “s13 == abd” << “n”; // == true

// example for CBstr::Compare
CBstr s14( “abc” );
CBstr s15( “abd” );
cout << s14.Compare(s15) << “n”; // == -1 // Compare with another CBstr.
cout << s14.Compare(“abe”) << “n”; // == -1 // Compare with LPTSTR string.

// example for CBstr::CompareNoCase
CBstr s16( “abc” );
CBstr s17( “ABD” );
cout << s16.CompareNoCase( s17 ) << “n”; // == -1 // Compare with a CBstr.
cout << s16.Compare( “ABE” ) << “n”; // == 1 // Compare with LPTSTR string.

// example for CBstr::Mid
CBstr s18(“abcdef”);
cout << (const char*)s18.Mid(2, 3) << “n”; // == _T(“cde”)

// example for CBstr::Left
CBstr s19( _T(“abcdef”) );
cout << (const char*)s19.Left(2) << “n”; // == _T(“ab”)

// example for CBstr::Right
CBstr s20( _T(“abcdef”) );
cout << (const char*)s20.Right(2) << “n”; // == _T(“ef”)

// example for CBstr::SpanIncluding
CBstr s21( “cabbage” );
CBstr s22 = s21.SpanIncluding( “abc” );
cout << (const char*)s22 << “n”; // == “cabba”
s22 = s21.SpanIncluding( “xyz” );
cout << s22.IsEmpty( ) << “n”; // == true

// example for CBstr::MakeUpper
CBstr s23( “abc” );
s23.MakeUpper();
cout << (const char*)s23 << “n”; // == “ABC”

// example for CBstr::MakeLower
CBstr s24( “ABC” );
s24.MakeLower();
cout << (const char*)s24 << “n”; // == “abc”

// example for CBstr::MakeReverse
CBstr s25( “abc” );
s25.MakeReverse();
cout << (const char*)s25 << “n”; // == “cba”

// example for CBstr::Find
CBstr s26( “abcdef” );
cout << s26.Find( ‘c’ ) << “n”; // == 2
cout << s26.Find( “de” ) << “n”; // == 3

// example for CBstr::ReverseFind
CBstr s27( “abcabc” );
cout << s27.ReverseFind( ‘b’ ) << “n”; // == 4

// example for CBstr::FindOneOf
CBstr s28( “abcdef” );
cout << s28.FindOneOf( “xd” ) << “n”; // == 3 // ‘d’ is first match

return 0;
}

Download demo project – 7 KB

More by Author

Must Read