For the CComBSTR lovers

Tech-Archive recommends: Fix windows errors by optimizing your registry



An improved and optimized version of CComBSTR.



Added:

..IndexOf

..LastIndexOf

..Substring

..Format()

..SetLength

..Replace() // todo...

plus a lot of string BSTR management optimizations.

For instance

CComBSTR myvar;

myvar.Append(L"hi");

myvar.Append(L"there");

does not move the BSTR memory to another location (mostly). This makes the CComBSTR as efficient as a StringBuffer class (found in C#).



/////////////////////////////////////////////////////////////////////////////
// CComBSTR

class CComBSTR
{
public:
BSTR m_str;
CComBSTR() throw()
{
 m_str = NULL;
}
CComBSTR(int nSize)
{
 //if (nSize == 0) //BUG it should be possible to assign a L"" string
 // m_str = NULL;
 m_str = ::SysAllocStringLen(NULL, nSize);
 if (m_str == NULL)
  AtlThrow(E_OUTOFMEMORY);

}
CComBSTR(int nSize, LPCOLESTR sz)
{
 if (nSize == 0)
  m_str = NULL;
 else
 {
  m_str = ::SysAllocStringLen(sz, nSize);
  if (m_str == NULL)
   AtlThrow(E_OUTOFMEMORY);
 }
}
CComBSTR(LPCOLESTR pSrc)
{
 if (pSrc == NULL)
  m_str = NULL;
 else
 {
  m_str = ::SysAllocString(pSrc);
  if (m_str == NULL)
   AtlThrow(E_OUTOFMEMORY);
 }
}
CComBSTR(const CComBSTR& src)
{
 m_str = src.Copy();
 if (!!src && m_str == NULL)
  AtlThrow(E_OUTOFMEMORY);

}
CComBSTR(REFGUID guid)
{
 OLECHAR szGUID[64];
 ::StringFromGUID2(guid, szGUID, 64);
 m_str = ::SysAllocString(szGUID);
 if (m_str == NULL)
  AtlThrow(E_OUTOFMEMORY);
}

CComBSTR& operator=(const CComBSTR& src)
{
 if (m_str != src.m_str)
 {
  if (::SysReAllocStringLen(&m_str, src, src.Length()) == FALSE)
   AtlThrow(E_OUTOFMEMORY);
 }
 return *this;
}

CComBSTR& operator=(LPCOLESTR pSrc)
{
 if (pSrc != m_str)
 {
  if (pSrc != NULL)
  {
   if (::SysReAllocString(&m_str, pSrc) == FALSE)
    AtlThrow(E_OUTOFMEMORY);
  }
  else
  {
   ::SysFreeString(m_str);
   m_str = NULL;
  }
 }
 return *this;
}

~CComBSTR() throw()
{
 ::SysFreeString(m_str);
}
unsigned int Length() const throw()
{
 return (m_str == NULL)? 0 : SysStringLen(m_str);
}
unsigned int ByteLength() const throw()
{
 return (m_str == NULL)? 0 : SysStringByteLen(m_str);
}
operator BSTR() const throw()
{
 return m_str;
}
BSTR* operator&() throw()
{
 return &m_str;
}
BSTR Copy() const throw()
{
 if (m_str == NULL)
  return NULL;
 return ::SysAllocStringByteLen((char*)m_str, ::SysStringByteLen(m_str));
}
HRESULT CopyTo(BSTR* pbstr) throw()
{
 ATLASSERT(pbstr != NULL);
 if (pbstr == NULL)
  return E_POINTER;
 *pbstr = Copy();
 if ((*pbstr == NULL) && (m_str != NULL))
  return E_OUTOFMEMORY;
 return S_OK;
}

/* added by may 2005 e.n. needs #include 'wchar.h'*/
HRESULT __cdecl Format(PCWSTR pszFormat, ...) throw()
{
 va_list args;
 HRESULT hr = S_OK;

 va_start( args, pszFormat );

 int len = _vscwprintf( pszFormat, args );
 if (::SysReAllocStringLen(&m_str, NULL, len) == FALSE)
  hr = E_OUTOFMEMORY;
 else
  vswprintf( m_str, (SIZE_T)Length(), pszFormat, args );
 va_end(args);

 return hr;
}

BSTR Substring(const unsigned int startIndex) throw()
{
 unsigned int maxIdx = Length();
 if (m_str != NULL && startIndex >= 0 && startIndex <= maxIdx)
 {
  return ::SysAllocStringLen(m_str + startIndex, maxIdx - startIndex);
 }
 else
  return NULL;
}

// Cuts the length to specified but does not clear contents
HRESULT SetLength(const unsigned int length) throw()
{
return ::SysReAllocStringLen(&m_str, NULL, length) == FALSE ? E_OUTOFMEMORY : S_OK;
}


BSTR Substring(const unsigned int startIndex, unsigned int length) throw()
{
unsigned int maxIdx = Length();
//if (length < 0) length = 0;
if (startIndex + length > maxIdx)
length = maxIdx - startIndex;
if (m_str != NULL && startIndex > 0 && startIndex <= maxIdx)
{
return ::SysAllocStringLen(m_str + startIndex, length);
}
else
return NULL;
}
int LastIndexOf(const wchar_t *src, const unsigned int startIndex = 0, const bool caseInsensitive = false) throw()
{
int result = -1;
if (m_str != NULL && src != NULL)
{
LCID lcid = ::GetThreadLocale();
DWORD dwCmpFlags = caseInsensitive ? NORM_IGNORECASE : 0;


  unsigned int compLen = (unsigned int)lstrlenW(src);
  unsigned int maxLen = Length();
  if (compLen <= maxLen)
  {
   for(unsigned int x = maxLen - compLen; x >= startIndex; x-- )
   {
    if (::CompareStringW(lcid, dwCmpFlags, m_str + x,
     compLen, src, compLen) == CSTR_EQUAL)
    {
     result = x;
     break;
    }
//    if (--x == 0) break;
   }
  }

 }
 return result;
}

int IndexOf(const wchar_t src, const unsigned int startIndex = 0, const bool caseInsensitive = false) throw()
{
wchar_t src2[] = {src, NULL}; //create zero terminated PWSTR
return IndexOf(src2, startIndex, caseInsensitive);
}


/*
* Addded by E.N.
*/
int IndexOf(const PWSTR src, const unsigned int startIndex = 0, const bool caseInsensitive = false) throw()
{
int result = -1;


 if (m_str != NULL)
 {
  LCID lcid = ::GetThreadLocale();
  DWORD dwCmpFlags = caseInsensitive ? NORM_IGNORECASE : 0;


if (m_str != NULL && src != NULL)
{
unsigned int maxLen = Length();
unsigned int compLen = (unsigned int)lstrlenW(src);
if (compLen <= maxLen)
{
for(unsigned int x = startIndex; x < maxLen - compLen; x++)
{
if (::CompareStringW(lcid, dwCmpFlags, m_str + x, compLen, src, compLen) == CSTR_EQUAL)
{
result = x;
break;
}
}
}


  }
 }
 return result;

}

// copy BSTR to VARIANT
HRESULT CopyTo(VARIANT *pvarDest) throw()
{
 ATLASSERT(pvarDest != NULL);
 HRESULT hRes = E_POINTER;
 if (pvarDest != NULL)
 {
  pvarDest->vt = VT_BSTR;
  pvarDest->bstrVal = Copy();
  if (pvarDest->bstrVal == NULL && m_str != NULL)
   hRes = E_OUTOFMEMORY;
  else
   hRes = S_OK;
 }
 return hRes;
}
void Attach(BSTR src) throw()
{
 if (m_str != src)
 {
  ::SysFreeString(m_str);
  m_str = src;
 }
}
BSTR Detach() throw()
{
 BSTR s = m_str;
 m_str = NULL;
 return s;
}
void Empty() throw()
{
 ::SysFreeString(m_str);
 m_str = NULL;
}
bool operator!() const throw()
{
 return (m_str == NULL);
}
HRESULT Append(const CComBSTR& bstrSrc) throw()
{
 return AppendBSTR(bstrSrc.m_str);
}
HRESULT Append(LPCOLESTR lpsz) throw()
{
 return Append(lpsz, UINT(ocslen(lpsz)));
}
// a BSTR is just a LPCOLESTR so we need a special version to signify
// that we are appending a BSTR
HRESULT AppendBSTR(BSTR p) throw()
{
 return Append((LPCOLESTR)p, ::SysStringLen(p));
}
HRESULT Append(LPCOLESTR lpsz, int nLen) throw()
{
 if (lpsz == NULL || (m_str != NULL && nLen == 0))
  return S_OK;
 int n1 = Length();
 if ( ::SysReAllocStringLen(&m_str, NULL, n1+nLen) == FALSE)
  return E_OUTOFMEMORY;
 memcpy(m_str+n1, lpsz, nLen*sizeof(OLECHAR));
 return S_OK;
}
HRESULT Append(char ch) throw()
{
 OLECHAR chO = ch;

 return( Append( &chO, 1 ) );
}
HRESULT Append(wchar_t ch) throw()
{
 return( Append( &ch, 1 ) );
}
HRESULT AppendBytes(const char* lpsz, int nLen) throw()
{
 if (lpsz == NULL || nLen == 0)
  return S_OK;
 int n1 = ByteLength();
 BSTR b;
 b = ::SysAllocStringByteLen(NULL, n1+nLen);
 if (b == NULL)
  return E_OUTOFMEMORY;
 memcpy(b, m_str, n1);
 memcpy(((char*)b)+n1, lpsz, nLen);
 *((OLECHAR*)(((char*)b)+n1+nLen)) = NULL;
 SysFreeString(m_str);
 m_str = b;
 return S_OK;
}
HRESULT AssignBSTR(const BSTR bstrSrc) throw()
{
 HRESULT hr = S_OK;
 if (m_str != bstrSrc)
 {

if (bstrSrc != NULL)
{
if (::SysReAllocStringLen(&m_str, bstrSrc, ::SysStringLen(bstrSrc)) == FALSE)
hr = E_OUTOFMEMORY;
}
else
m_str = NULL;
}


return hr;
}
HRESULT ToLower() throw()
{
if (m_str != NULL)
{
#ifdef _UNICODE
// Convert in place
CharLowerBuff(m_str, Length());
#else
// Cannot use conversion macros due to possible embedded NULLs
UINT _acp = _AtlGetConversionACP();
int _convert = WideCharToMultiByte(_acp, 0, m_str, Length(), NULL, 0, NULL, NULL);
CTempBuffer<char> pszA;
ATLTRY(pszA.Allocate(_convert));
if (pszA == NULL)
return E_OUTOFMEMORY;


int nRet = WideCharToMultiByte(_acp, 0, m_str, Length(), pszA, _convert, NULL, NULL);
if (nRet == 0)
{
ATLASSERT(0);
return AtlHresultFromLastError();
}


  CharLowerBuff(pszA, nRet);

  _convert = MultiByteToWideChar(_acp, 0, pszA, nRet, NULL, 0);

  CTempBuffer<WCHAR> pszW;
  ATLTRY(pszW.Allocate(_convert));
  if (pszW == NULL)
   return E_OUTOFMEMORY;

  nRet = MultiByteToWideChar(_acp, 0, pszA, nRet, pszW, _convert);
  if (nRet == 0)
  {
   ATLASSERT(0);
   return AtlHresultFromLastError();
  }

if (::SysReAllocStringLen(&m_str, pszW, nRet) == FALSE)
return E_OUTOFMEMORY;
#endif
}
return S_OK;
}
HRESULT ToUpper() throw()
{
if (m_str != NULL)
{
#ifdef _UNICODE
// Convert in place
CharUpperBuff(m_str, Length());
#else
// Cannot use conversion macros due to possible embedded NULLs
UINT _acp = _AtlGetConversionACP();
int _convert = WideCharToMultiByte(_acp, 0, m_str, Length(), NULL, 0, NULL, NULL);
CTempBuffer<char> pszA;
ATLTRY(pszA.Allocate(_convert));
if (pszA == NULL)
return E_OUTOFMEMORY;


int nRet = WideCharToMultiByte(_acp, 0, m_str, Length(), pszA, _convert, NULL, NULL);
if (nRet == 0)
{
ATLASSERT(0);
return AtlHresultFromLastError();
}


  CharUpperBuff(pszA, nRet);

  _convert = MultiByteToWideChar(_acp, 0, pszA, nRet, NULL, 0);

  CTempBuffer<WCHAR> pszW;
  ATLTRY(pszW.Allocate(_convert));
  if (pszW == NULL)
   return E_OUTOFMEMORY;

  nRet = MultiByteToWideChar(_acp, 0, pszA, nRet, pszW, _convert);
  if (nRet == 0)
  {
   ATLASSERT(0);
   return AtlHresultFromLastError();
  }

  if (::SysReAllocStringLen(&m_str, pszW, nRet) == FALSE);
   return E_OUTOFMEMORY;

#endif
 }
 return S_OK;
}
bool LoadString(HINSTANCE hInst, UINT nID) throw()
{
 ::SysFreeString(m_str);
 m_str = NULL;
 return LoadStringResource(hInst, nID, m_str);
}
bool LoadString(UINT nID) throw()
{
 ::SysFreeString(m_str);
 m_str = NULL;
 return LoadStringResource(nID, m_str);
}

CComBSTR& operator+=(const CComBSTR& bstrSrc)
{
 HRESULT hr;
 hr = AppendBSTR(bstrSrc.m_str);
 if (FAILED(hr))
  AtlThrow(hr);
 return *this;
}
CComBSTR& operator+=(LPCOLESTR pszSrc)
{
 HRESULT hr;
 hr = Append(pszSrc);
 if (FAILED(hr))
  AtlThrow(hr);
 return *this;
}

bool operator<(const CComBSTR& bstrSrc) const throw()
{
return VarBstrCmp(m_str, bstrSrc.m_str, ::GetThreadLocale(), 0) == VARCMP_LT;
}
bool operator<(LPCOLESTR pszSrc) const
{
CComBSTR bstr2(pszSrc);
return operator<(bstr2);
}
bool operator<(LPOLESTR pszSrc) const
{
return operator<((LPCOLESTR)pszSrc);
}


bool operator>(const CComBSTR& bstrSrc) const throw()
{
return VarBstrCmp(m_str, bstrSrc.m_str, ::GetThreadLocale(), 0) == VARCMP_GT;
}
bool operator>(LPCOLESTR pszSrc) const
{
CComBSTR bstr2(pszSrc);
return operator>(bstr2);
}
bool operator>(LPOLESTR pszSrc) const
{
return operator>((LPCOLESTR)pszSrc);
}


bool operator!=(const CComBSTR& bstrSrc) const throw()
{
 return !operator==(bstrSrc);
}
bool operator!=(LPCOLESTR pszSrc) const
{
 return !operator==(pszSrc);
}
bool operator!=(int nNull) const throw()
{
 return !operator==(nNull);
}
bool operator!=(LPOLESTR pszSrc) const
{
 return operator!=((LPCOLESTR)pszSrc);
}

bool operator==(const CComBSTR& bstrSrc) const throw()
{
return VarBstrCmp(m_str, bstrSrc.m_str, ::GetThreadLocale(), 0) == VARCMP_EQ;
}
bool operator==(LPCOLESTR pszSrc) const
{
CComBSTR bstr2(pszSrc);
return operator==(bstr2);
}
bool operator==(LPOLESTR pszSrc) const
{
return operator==((LPCOLESTR)pszSrc);
}


bool operator==(int nNull) const throw()
{
 ATLASSERT(nNull == NULL);
 (void)nNull;
 return (m_str == NULL);
}
CComBSTR(LPCSTR pSrc)
{
 if (pSrc != NULL)
 {
  m_str = A2WBSTR(pSrc);
  if (m_str == NULL)
   AtlThrow(E_OUTOFMEMORY);
 }
 else
  m_str = NULL;
}

CComBSTR(int nSize, LPCSTR sz)
{
 if (nSize != 0 && sz == NULL)
 {
  m_str = ::SysAllocStringLen(NULL, nSize);
  if (m_str == NULL)
   AtlThrow(E_OUTOFMEMORY);
  return;
 }

 m_str = A2WBSTR(sz, nSize);
 if (m_str == NULL && nSize != 0)
  AtlThrow(E_OUTOFMEMORY);
}

HRESULT Append(LPCSTR lpsz) throw()
{
 if (lpsz == NULL)
  return S_OK;

 CComBSTR bstrTemp;
 ATLTRY(bstrTemp = lpsz);
 if (bstrTemp.m_str == NULL)
  return E_OUTOFMEMORY;
 return Append(bstrTemp);
}

CComBSTR& operator=(LPCSTR pSrc)
{
 ::SysFreeString(m_str);
 m_str = A2WBSTR(pSrc);
 if (m_str == NULL && pSrc != NULL)
  AtlThrow(E_OUTOFMEMORY);
 return *this;
}
bool operator<(LPCSTR pszSrc) const
{
 CComBSTR bstr2(pszSrc);
 return operator<(bstr2);
}
bool operator>(LPCSTR pszSrc) const
{
 CComBSTR bstr2(pszSrc);
 return operator>(bstr2);
}
bool operator!=(LPCSTR pszSrc) const
{
 return !operator==(pszSrc);
}
bool operator==(LPCSTR pszSrc) const
{
 CComBSTR bstr2(pszSrc);
 return operator==(bstr2);
}
HRESULT WriteToStream(IStream* pStream) throw()
{
 ATLASSERT(pStream != NULL);
 if(pStream == NULL)
  return E_INVALIDARG;

ULONG cb;
ULONG cbStrLen = ULONG(m_str ? SysStringByteLen(m_str)+sizeof(OLECHAR) : 0);
HRESULT hr = pStream->Write((void*) &cbStrLen, sizeof(cbStrLen), &cb);
if (FAILED(hr))
return hr;
return cbStrLen ? pStream->Write((void*) m_str, cbStrLen, &cb) : S_OK;
}
HRESULT ReadFromStream(IStream* pStream) throw()
{
ATLASSERT(pStream != NULL);
if(pStream == NULL)
return E_INVALIDARG;


 ATLASSERT(m_str == NULL); // should be empty
 Empty();

ULONG cbStrLen = 0;
HRESULT hr = pStream->Read((void*) &cbStrLen, sizeof(cbStrLen), NULL);
if ((hr == S_OK) && (cbStrLen != 0))
{
//subtract size for terminating NULL which we wrote out
//since SysAllocStringByteLen overallocates for the NULL
m_str = SysAllocStringByteLen(NULL, cbStrLen-sizeof(OLECHAR));
if (m_str == NULL)
hr = E_OUTOFMEMORY;
else
hr = pStream->Read((void*) m_str, cbStrLen, NULL);
// If SysAllocStringByteLen or IStream::Read failed, reset seek
// pointer to start of BSTR size.
if (hr != S_OK)
{
LARGE_INTEGER nOffset;
nOffset.QuadPart = -(static_cast<LONGLONG>(sizeof(cbStrLen)));
pStream->Seek(nOffset, STREAM_SEEK_CUR, NULL);
}
}
if (hr == S_FALSE)
hr = E_FAIL;
return hr;
}
static bool LoadStringResource(HINSTANCE hInstance, UINT uID, BSTR& bstrText) throw()
{
const ATLSTRINGRESOURCEIMAGE* pImage;


 ATLASSERT(bstrText == NULL);

 pImage = AtlGetStringResourceImage(hInstance, uID);
 if (pImage != NULL)
 {
  bstrText = ::SysAllocStringLen(pImage->achString, pImage->nLength);
 }

 return (bstrText != NULL) ? true : false;
}

static bool LoadStringResource(UINT uID, BSTR& bstrText) throw()
{
 const ATLSTRINGRESOURCEIMAGE* pImage;

 ATLASSERT(bstrText == NULL);

 pImage = AtlGetStringResourceImage(uID);
 if (pImage != NULL)
 {
  bstrText = ::SysAllocStringLen(pImage->achString, pImage->nLength);
 }

 return (bstrText != NULL) ? true : false;
}



// each character in BSTR is copied to each element in SAFEARRAY
HRESULT BSTRToArray(LPSAFEARRAY *ppArray) throw()
{
 return VectorFromBstr(m_str, ppArray);
}

// first character of each element in SAFEARRAY is copied to BSTR
HRESULT ArrayToBSTR(const SAFEARRAY *pSrc) throw()
{
 ::SysFreeString(m_str);
 return BstrFromVector((LPSAFEARRAY)pSrc, &m_str);
}
};


.



Relevant Pages

  • Re: For the CComBSTR lovers
    ... unsigned int ByteLength() const throw ... operator BSTR() const throw ... HRESULT __cdecl Formatthrow{va_list args; ...
    (microsoft.public.vc.atl)
  • take your advantage improved ATL::CComBSTR class
    ... For the guys that want neat COM interop and not convert the CString or std: string classes to a BSTR constantly, this class is an ideal candidate. ... unsigned int ByteLength() const throw ... HRESULT CopyTothrow ... HRESULT Replace(BSTR find, BSTR replace, bool caseInsensitive) throw ...
    (microsoft.public.vc.atl)
  • Re: Easy way to manipulate BSTR using CString class (?)
    ... does hardly require BSTR caching. ... HRESULT hr = SetLength; ... unsigned int __stdcall ByteLength() const throw ...
    (microsoft.public.vc.atl)
  • How to pass an object from C++
    ... STDMETHODIMP CSyntaxObj::InitRules(Handle_DS handlDS, BSTR Provider, BSTR ... interface IParamItem: IUnknown ... [propget, helpstring] ... HRESULT mOrigParam; ...
    (microsoft.public.vc.mfc)
  • Re: Split a _bstr_t
    ... HRESULT hr = SetLength; ... CComBSTR2(LPCOLESTR pSrc) ... operator BSTR() const throw ... /*HRESULT Append(const CComVariant2& pVarSrc) throw ...
    (microsoft.public.vc.atl)