CBStr: a BSTR wrapper-class with string manipulation members

CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

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 gary.olliffe@parallax.co.uk
//
//
#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

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read