Re: Easy way to manipulate BSTR using CString class (?)

Tech Tip: Click here to run a free scan for Windows Errors and optimize PC performance




"Zika Mustikla" <someone@xxxxxxxxxxxxx> wrote in message news:SLTOf.682$oj5.244609@xxxxxxxxxxxxxxxx

http://www.codeproject.com/cpp/easybstr.asp

DISCLAIMER: I am not the author. I just found it.


There is another one :) an improved CComBSTR version, just redefine CComBSTR to CComBSTR2 and all your existing code, continues to work
And this version, does hardly require BSTR caching. It is optimized to reallocate in-place.
For server applications, caching of BSTRs is useless.

/////////////////////////////////////////////////////////////////////////////
// CComBSTR2

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

HRESULT hr = SetLength(nSize);
if (FAILED(hr))
AtlThrow(hr);
ZeroMemory(m_str, nSize * sizeof(WCHAR));

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

}
CComBSTR2(REFGUID guid)
{
OLECHAR szGUID[64];

m_str = ::SysAllocStringLen(szGUID,
::StringFromGUID2(guid, szGUID, 64)
);

if (m_str == NULL)
AtlThrow(E_OUTOFMEMORY);
}

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

CComBSTR2& operator=(LPCOLESTR pSrc)
{
if (pSrc != m_str)
{
if (pSrc != NULL)
{
if (::SysReAllocString(&m_str, pSrc) == FALSE)
AtlThrow(E_OUTOFMEMORY);
}
else
Empty();

}
return *this;
}

~CComBSTR2() throw()
{
::SysFreeString(m_str);
}
unsigned int __stdcall Length() const throw()
{
return SysStringLen(m_str);
}
unsigned int __stdcall ByteLength() const throw()
{
return SysStringByteLen(m_str);
}
operator BSTR() const throw()
{
return m_str;
}
BSTR* __stdcall operator&() throw()
{
return &m_str;
}
BSTR __stdcall Copy() const throw()
{
return m_str == NULL ? NULL :
::SysAllocStringByteLen((char*)m_str, ByteLength());

}
//modified by E.N. pbstr is now in/out!
// you must care for it that it properly gets initialized
STDMETHODIMP CopyTo(BSTR* pbstr) throw()
{
ATLASSERT(pbstr != NULL);
HRESULT hr;
if (pbstr == NULL)
hr = E_POINTER;
else
hr =::SysReAllocStringLen(pbstr, m_str, Length()) == FALSE ? E_OUTOFMEMORY : S_OK;

return hr;
}
// *** returns true if length equals zero characters or when unallocated(null pointer)
bool __stdcall IsEmpty (void) throw()
{
return m_str == NULL || Length() == 0;
}
/* added by may 2005 e.n. needs #include 'wchar.h'*/
HRESULT __stdcall Format(PCWSTR pszFormat, va_list args) throw()
{
size_t len = _vscwprintf( pszFormat, args );

HRESULT hr = SetLength((UINT)len) ;

if(SUCCEEDED(hr))
if (vswprintf( m_str, len + 1, pszFormat, args ) < 0)
hr = E_INVALIDARG;


return hr;
}

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

return hr;
}
HRESULT __stdcall Insert(unsigned int atPosition, PCWSTR value) throw()
{
return Insert(atPosition, CComBSTR(value));
}
HRESULT __stdcall Insert(unsigned int atPosition, const CComBSTR& value) throw()
{
unsigned int toInsert = value.Length();
unsigned int curLen = Length();
HRESULT hr = S_OK;
if (atPosition > curLen || value == NULL)
hr = E_INVALIDARG;
else
hr = SetLength(curLen + toInsert);
if (SUCCEEDED(hr) && curLen != 0 && toInsert != 0)
{
MoveMemory(&m_str[atPosition + toInsert], &m_str[atPosition],
(curLen - atPosition) * sizeof(wchar_t));
CopyMemory(&m_str[atPosition], value, toInsert * sizeof(wchar_t));
}
return hr;
}
void __stdcall Remove(unsigned int startIndex, unsigned int count) throw()
{
unsigned int maxIdx = Length();
if (startIndex < maxIdx)
{
MoveMemory(&m_str[startIndex], &m_str[startIndex + count] ,
(maxIdx - startIndex - 1) * sizeof(wchar_t));
SetLength(maxIdx - count);
}
}
// original string john smith
// merge with west at position 6
// result john westh
// won't extend string length!
void __stdcall MergeString(unsigned int startIndex, BSTR value) throw()
{

unsigned int maxIdx = Length();
if (startIndex > maxIdx || value == NULL) return; // illegal operation
unsigned int mergeLen = SysStringLen(value);
if (mergeLen + startIndex > maxIdx)
mergeLen = maxIdx - startIndex;
MoveMemory(&m_str[startIndex], value, mergeLen * sizeof(wchar_t));
}
BSTR __stdcall Substring(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;
}
HRESULT __stdcall SetByteLength(unsigned int length) throw()
{
return _SetByteLength(&m_str, length);
}
// Cuts the length to specified but does not clear contents
HRESULT __stdcall SetLength(unsigned int length) throw()
{
return _SetLength(&m_str, length);
}
private:
static HRESULT __stdcall _SetByteLength(BSTR *str, unsigned int length) throw()
{
#ifdef SysReAllocStringByteLen
return SysReAllocStringByteLen2(str, NULL, length) == FALSE ? E_OUTOFMEMORY : S_OK;
#endif
}
static HRESULT __stdcall _SetLength(BSTR * str, unsigned int length) throw()
{
return ::SysReAllocStringLen(str, NULL, length) == FALSE ? E_OUTOFMEMORY : S_OK;
}
public:
/// <summary>
/// Replaces a find token with a specified token
/// By E.N.
/// </summary>
/// <param name="find">token to be replace</param>
/// <param name="replace">token that will replace</param>
/// <param name="caseInsensitive">if true, will do a case insensitive replacement</param>
/// <example>
/// CComBSTR2 myReplace(L"the dog jumps over the");
/// myReplace(CComBSTR2(L"the"), CComBSTR2(L"big"));
/// </example>
/// <returns>The example would modify the string to "big dog jumps over big" </returns>
HRESULT __stdcall Replace(BSTR find, BSTR replace, bool caseInsensitive) throw()
{
HRESULT hr = S_OK;
if (m_str == NULL)
hr = E_POINTER;
else
{
//replacement Could be done in-place using intelligent code using
// backward/forward copying and resizing the m_str but not for now...
SAFEARRAY *psa = Split(find, caseInsensitive);
//could Empty() here to safe resources ASAP but if Join would fail
// we end up an uncommited transaction
BSTR bTemp = Join(psa, replace);
if (psa != NULL)
::SafeArrayDestroy(psa);
if (bTemp != NULL)
{ Empty();
m_str = bTemp;
}
else
hr = E_OUTOFMEMORY;

}


//// nSourceLen is in XCHARs
//int nSourceLen = StringTraits::SafeStringLen( pszOld );
//if( nSourceLen == 0 )
// return( 0 );
//// nReplacementLen is in XCHARs
//int nReplacementLen = StringTraits::SafeStringLen( pszNew );

//// loop once to figure out the size of the result string
//int nCount = 0;
//{
// PCXSTR pszStart = GetString();
// PCXSTR pszEnd = pszStart+GetLength();
// while( pszStart < pszEnd )
// {
// PCXSTR pszTarget;
// while( (pszTarget = StringTraits::StringFindString( pszStart, pszOld ) ) != NULL)
// {
// nCount++;
// pszStart = pszTarget+nSourceLen;
// }
// pszStart += StringTraits::SafeStringLen( pszStart )+1;
// }
//}

//// if any changes were made, make them
//if( nCount > 0 )
//{
// // if the buffer is too small, just
// // allocate a new buffer (slow but sure)
// int nOldLength = GetLength();
// int nNewLength = nOldLength+(nReplacementLen-nSourceLen)*nCount;

// PXSTR pszBuffer = GetBuffer( max( nNewLength, nOldLength ) );

// PXSTR pszStart = pszBuffer;
// PXSTR pszEnd = pszStart+nOldLength;

// // loop again to actually do the work
// while( pszStart < pszEnd )
// {
// PXSTR pszTarget;
// while( (pszTarget = StringTraits::StringFindString( pszStart, pszOld ) ) != NULL )
// {
// int nBalance = nOldLength-int(pszTarget-pszBuffer+nSourceLen);
// memmove( pszTarget+nReplacementLen, pszTarget+nSourceLen, nBalance*sizeof( XCHAR ) );

// memcpy( pszTarget, pszNew, nReplacementLen*sizeof( XCHAR ) );
// pszStart = pszTarget+nReplacementLen;
// pszTarget[nReplacementLen+nBalance] = 0;
// nOldLength += (nReplacementLen-nSourceLen);
// }
// pszStart += StringTraits::SafeStringLen( pszStart )+1;
// }
// ATLASSERT( pszBuffer[nNewLength] == 0 );
// ReleaseBufferSetLength( nNewLength );
//}

return hr;
}

/// <summary>
/// Replaces a find token with a specified token
/// <param name="find">token to be replace</param>
/// <param name="replace">token that will replace</param>
/// </summary>
/// <example>
/// CComBSTR2 myReplace(L"the dog jumps over the");
/// myReplace(CComBSTR2(L"the"), CComBSTR2(L"big"));
/// </example>
/// <returns>The example would modify the string to "big dog jumps over big" </returns>
HRESULT __stdcall Replace(const BSTR find, const BSTR replace) throw()
{
return Replace(find, replace, false);
}
/// <summary>
/// Split and copies this instance of CComBSTR2 into a SAFEARRAY* of VTYPE = VT_BSTR
/// </summary>
/// <example>
/// CComSafeArray<BSTR> myArray;
/// CComBSTR2 joined(L"John|Smith");
/// myArray.Attach(joined.Split(CComBSTR2(L"|")))
/// </example>
/// <returns>The example would return a safearray with 2 VT_BSTR elements containing "John" and "Smith"</returns>
SAFEARRAY* __stdcall Split(const BSTR expression, const bool caseInsensitive)
{
SAFEARRAY* retval = NULL;
HRESULT hr = S_OK;
if (m_str == NULL)
AtlThrow(E_POINTER);
else
{
unsigned int exprLen = SysStringLen(expression);
unsigned int mLen = Length();
int x = 0;
//contains the number of found expression tokens
unsigned int found = 0;
//find until no more...
if (expression != NULL)
{
for (;;)
{
x = IndexOf(expression, x, caseInsensitive);
if (x == -1) break;
found++;
x += exprLen;
}
}
SAFEARRAYBOUND rgsa = {found + 1, 0};
retval = ::SafeArrayCreate(VT_BSTR, 1, &rgsa); //::SafeArrayCreateVector(VT_BSTR, 0, found + 1);
if (retval == NULL)
{
hr = E_OUTOFMEMORY;
AtlTrace(L"SafeArrayCreateVector\r\n");
}
else
{
BSTR* paBSTR ;//(BSTR*)retval->pvData;
hr = SafeArrayAccessData(retval, (void**)&paBSTR);
unsigned int prevPos = 0;
for (unsigned int curEl = 0, x=0; curEl < found; curEl++)
{
x = IndexOf(expression, x, caseInsensitive);
if (x >= 0)
{
paBSTR[curEl] = Substring(prevPos, x - prevPos);
if (paBSTR[curEl] == NULL)
{
hr = E_OUTOFMEMORY;
break;
}
x += exprLen;
prevPos = x;
}
}
if (SUCCEEDED(hr))
{
//if ... rest of string
paBSTR[found] = Substring(prevPos);
if (paBSTR[found] == NULL)
{
AtlTrace(L"paBSTR[found] == NULL");
hr = E_OUTOFMEMORY;
}
}
SafeArrayUnaccessData(retval);
}
if (FAILED(hr))
{
AtlTrace(L"general split fail %x", hr);
if (retval != NULL)
::SafeArrayDestroy(retval);
retval = NULL;
AtlThrow(hr);
}
}
return retval;
}
SAFEARRAY* __stdcall Split(const BSTR expression) throw()
{
return Split(expression, false);
}

/// <summary>
/// Added by E.N.
/// Joins a SAFEARRAY to a single BSTR
/// </summary>
/// <example>
/// CComSafeArray<BSTR> myArray;
/// myArray.Add(CComBSTR2(L"John"));
/// myArray.Add(CComBSTR2(L"Smith"));
/// CComBSTR2 joined;
/// joined.Attach(CComBSTR2::Join(myArray.m_psa, CComBSTR2(L"|") ) ); ///
/// </example>
/// <returns>The example would return "John|Smith"</returns>
static BSTR __stdcall Join(SAFEARRAY *psa, const BSTR delimiter) //throw()
{
BSTR retval = NULL;
HRESULT hr = S_OK;
if (psa != NULL && psa != NULL)
{
VARTYPE vt = VT_EMPTY;
unsigned int delLen = ::SysStringLen(delimiter);

hr = ::SafeArrayGetVartype(psa, &vt);
if (vt != VT_BSTR || psa->cDims != 1)
AtlThrow(E_INVALIDARG);
SAFEARRAYBOUND *rgsa = psa->rgsabound;
ULONG elements = rgsa->cElements - rgsa->lLbound;
unsigned int totalLen = 0;
BSTR* paBSTR = (BSTR*) psa->pvData;

ULONG els = elements;
while(els != 0)
{
if (paBSTR[--els] != NULL)
totalLen += ::SysStringLen(paBSTR[els]);
if (els != 0)
totalLen += delLen;
}
hr = _SetLength(&retval, totalLen);
if (FAILED(hr))
AtlThrow(hr);
else
{
totalLen = 0;
els = elements;
ULONG curel = 0;
while (els != 0)
{
els--;
if (paBSTR[curel] != NULL)
{
unsigned int curLen = ::SysStringLen(paBSTR[curel]);
CopyMemory(retval + totalLen, paBSTR[curel], curLen * sizeof(OLECHAR));
totalLen += curLen;
}
curel++;
if (els != 0 && delLen != 0)
{
CopyMemory(retval + totalLen, delimiter, delLen * sizeof(OLECHAR));
totalLen += delLen;
}
}
} //success allocate string

}
return retval;
}
/// <summary>
/// Added by E.N.
/// Returns a new instance of a BSTR which is a Substring starting at the 'startindex' character
/// </summary>
/// <example>
/// CComBSTR2 john(L"John Smith"), subbed;
/// subbed.Attach(john.Substring(5));
/// </example>
/// <returns>The example would return "Smith"</returns>
BSTR __stdcall 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;
}
private:
bool __stdcall local_Test(PCWSTR src, unsigned int startIndex)
{
bool retval = false;
if (src != NULL)
{
unsigned int compLen = lstrlenW(src);
unsigned int thisLen = Length();
if (compLen <= thisLen)
{
DWORD dwCompFlags = 0;
retval = ::CompareStringW(::GetThreadLocale(), dwCompFlags,
&m_str[thisLen - startIndex], compLen, src, compLen) == CSTR_EQUAL;
}
}
return retval;
}
public:

bool __stdcall EndsWith(PCWSTR src) throw()
{

return local_Test(src, lstrlenW(src));
}
bool __stdcall StartsWith(PCWSTR src) throw()
{
return local_Test(src, Length());

}
int __stdcall LastIndexOf(const wchar_t src, const unsigned int startIndex = 0, const bool caseInsensitive = false) throw()
{
wchar_t src2[] = {src, NULL}; //create zero terminated PWSTR
return LastIndexOf(src2, startIndex, caseInsensitive);
}
int __stdcall LastIndexOf(const wchar_t *src, const unsigned int startIndex = 0, const bool caseInsensitive = false, unsigned int count = 0) throw()
{
int result = -1;
if (m_str != NULL && src != NULL)
{
LCID lcid = ::GetThreadLocale();
DWORD dwCmpFlags = caseInsensitive ? NORM_IGNORECASE : 0;

unsigned int compLen = (unsigned int)ocslen(src);
unsigned int maxLen = Length();
unsigned int examinedChars = 0;
if (compLen <= maxLen)
{
for(unsigned int x = maxLen - compLen; x >= startIndex; )
{
bool doCompare = caseInsensitive ? true : m_str[x] == src[0];

if (doCompare)
doCompare= ::CompareStringW(lcid, dwCmpFlags, &m_str[x],
compLen, src, compLen) == CSTR_EQUAL ;
if (doCompare)
{
result = x;
break;
}
if (x-- == 0 || (examinedChars++ == count && count != 0)) break;
}
}
}
return result;
}

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

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

if (m_str != NULL && src != NULL)
{
LCID lcid = ::GetThreadLocale();
DWORD dwCmpFlags = caseInsensitive ? NORM_IGNORECASE : 0;
unsigned int maxLen = Length();
unsigned int compLen = (unsigned int)ocslen(src);
unsigned int examinedChars = 0;
if (compLen <= maxLen && compLen > 0)
{
for(int x = startIndex; (x + compLen <= maxLen) || (examinedChars++ == count && count != 0); x++)
{
bool doCompare = caseInsensitive ? true :
m_str[x] == src[0];

if (doCompare)
doCompare= ::CompareStringW(lcid, dwCmpFlags, &m_str[x],
compLen, src, compLen) == CSTR_EQUAL ;
if (doCompare)
{
result = x;
break;
}
}
}
}
return result;
}

// copy BSTR to VARIANT
HRESULT __stdcall 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 __stdcall Attach(BSTR src) throw()
{
if (m_str != src)
{
::SysReAllocStringLen(&m_str, src, SysStringLen(src));
}
}
BSTR __stdcall Detach() throw()
{
BSTR s = m_str;
m_str = NULL;
return s;
}
void __stdcall Empty() throw()
{
::SysFreeString(m_str);
m_str = NULL;
}
bool __stdcall operator!() const throw()
{
return (m_str == NULL);
}

HRESULT __stdcall Append(const CComBSTR2& bstrSrc) throw()
{
return AppendBSTR(bstrSrc.m_str);
}
/*HRESULT Append(const CComVariant2& pVarSrc) throw()
{
return Append(pVarSrc.pvarVal);
}*/
//Added by E.N.
HRESULT __stdcall Append(const VARIANT& pVar) throw()
{
HRESULT hr = S_OK;
if (pVar.vt != VT_BSTR)
{
VARIANT v = {0};
hr = ::VariantChangeTypeEx(&v,(VARIANT*)&pVar,
::GetThreadLocale(), 0, VT_BSTR);
if (hr == S_OK) hr = AppendBSTR(v.bstrVal);
VariantClear(&v);
}
else
hr = AppendBSTR(pVar.bstrVal);

return hr;
}

HRESULT __stdcall 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 __stdcall AppendBSTR(BSTR p) throw()
{
return Append((LPCOLESTR)p, ::SysStringLen(p));
}
HRESULT __stdcall Append(LPCOLESTR lpsz, int nLen) throw()
{
if (lpsz == NULL || (m_str != NULL && nLen == 0))
return S_OK;
int n1 = Length();
HRESULT hr = SetLength(n1 + nLen);
if ( FAILED(hr))
return hr;
CopyMemory(m_str+n1, lpsz, nLen*sizeof(OLECHAR));
return S_OK;
}
HRESULT __stdcall Append(char ch) throw()
{
OLECHAR chO = ch;

return( Append( &chO, 1 ) );
}
HRESULT __stdcall Append(wchar_t ch) throw()
{
return( Append( &ch, 1 ) );
}
HRESULT __stdcall 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;
CopyMemory(b, m_str, n1);
CopyMemory(((char*)b)+n1, lpsz, nLen);
*((OLECHAR*)(((char*)b)+n1+nLen)) = NULL;
Empty();
m_str = b;
return S_OK;
}
static int __stdcall CountChar(BSTR a, wchar_t theChar) throw()
{
int retval = 0;
if (a != NULL)
{
unsigned int x = ::SysStringLen(a);
while (x != 0)
if (a[--x] == theChar) retval++;
}
return retval;
}
//returns -1 for lesser (<); 0 for equality and 1 for GT (>)
static int __stdcall Compare(BSTR a, BSTR b, bool ignoreCase, bool ignoreDiacritics, bool ignoreSymbols) throw()
{
int retval = 0;
DWORD compareFlags = ignoreCase ? NORM_IGNORECASE : 0;
if (ignoreDiacritics) compareFlags |= NORM_IGNORENONSPACE;
if (ignoreSymbols) compareFlags |= NORM_IGNORESYMBOLS;

if (a == NULL && b == NULL)
retval = 0;
else if (a == NULL)
retval = -1;
else if (b == NULL)
retval = 1;
else
{
switch(::VarBstrCmp(a, b, ::GetThreadLocale(), compareFlags))
{
case VARCMP_LT:
retval = -1;
break;
case VARCMP_EQ:
retval = 0;
break;
case VARCMP_GT:
retval = 1;
break;
}
}
return retval;
}

int __stdcall CompareTo(BSTR otherBstr) throw()
{
return Compare(m_str, otherBstr, false, false, false);
}

int __stdcall CompareTo(BSTR otherBstr, bool ignoreCase) throw()
{
return Compare(m_str, otherBstr, ignoreCase, false, false);
}

int __stdcall CompareTo(BSTR otherBstr, bool ignoreCase, bool ignoreDiacritics) throw()
{
return Compare(m_str, otherBstr, ignoreCase, ignoreDiacritics, false);
}

int __stdcall CompareTo(BSTR otherBstr, bool ignoreCase, bool ignoreDiacritics, bool ignoreSymbols) throw()
{
return Compare(m_str, otherBstr, ignoreCase, ignoreDiacritics, ignoreSymbols);
}

unsigned long __stdcall GetHashCode() throw()
{
//if insufficient, shlwapi::HashData could be used
unsigned long hash=0;
//HASHDATA2 hashdata2 = NULL;
//hash = LHashValOfName(::GetThreadLocale(), m_str);

//TCHAR shlwapi[] = {'S', 'H', 'L', 'W', 'A', 'P', 'I', '.', 'D', 'L', 'L', '\0'};
//HINSTANCE hinst = LoadLibrary(shlwapi);
//char procName[]={'H', 'a', 's', 'h', 'D', 'a', 't', 'a', '\0'}; // procName
//hashdata2 = (HASHDATA2) GetProcAddress(hinst, procName); //
HRESULT hr = S_OK;
//compress unicode before hashing
CComBSTR lpza;
lpza.Attach(ToByteString());
//CW2AEX<> lpza(m_str, CP_UTF8);

//if (hashdata2 != NULL)
hr = HashData((PBYTE)lpza.m_str, lpza.ByteLength(),(LPBYTE) &hash, sizeof(unsigned long));
//FreeLibrary(hinst);
return hash;
}

// added by e.n.
static void __stdcall StringReverse(/*in*/ BSTR s) throw()
{
//CComBSTR2 temp;
//HRESULT hr = temp.AssignBSTR(s); //create a copy
UINT slen = SysStringLen(s), y = 0;

while(y < slen--)
{
WCHAR swp = s[slen];
s[slen] = s[y];
s[y++] = swp;
}

}
void __stdcall Reverse() throw()
{
StringReverse(m_str);
}
GUID __stdcall ToGuid()
{
GUID retval = GUID_NULL;
HRESULT hr = IIDFromString(m_str, &retval);
if (FAILED(hr))
AtlThrow(hr);
return retval;
}

DATE __stdcall ToDate()
{
DATE retval = 0;
HRESULT hr = ::VarDateFromStr(m_str, ::GetThreadLocale(), LOCALE_NOUSEROVERRIDE, &retval);
if (FAILED(hr))
AtlThrow(hr);
return retval;
}
HRESULT __stdcall AssignDate(const DATE date) throw()
{
Empty();
return ::VarBstrFromDate(date, ::GetThreadLocale(), LOCALE_NOUSEROVERRIDE, &m_str);
}

HRESULT __stdcall AssignBSTR(const BSTR bstrSrc) throw()
{
HRESULT hr = S_OK;
#ifndef SysReAllocStringByteLen
if (m_str != bstrSrc)
{
Empty();
if (bstrSrc != NULL)
{
m_str = ::SysAllocStringByteLen((char*)bstrSrc, ::SysStringByteLen(bstrSrc));
if (m_str == NULL)
hr = E_OUTOFMEMORY;
}
else
m_str = NULL;
}
#else
if (m_str != bstrSrc)
{
if (bstrSrc == NULL)
Empty();
else
{
UINT ilen = ::SysStringByteLen(bstrSrc);
if (SysReAllocStringByteLen(&m_str, NULL, ilen) == FALSE)
hr = E_OUTOFMEMORY;
else if (ilen > 0) //fix since SysReAllocStringByteLen measures in lstrlenA
CopyMemory(m_str, bstrSrc, ilen);
}
}
#endif
return hr;

}
//creates a copy to a byteencoded string
// optimal usage, attach to it...
BSTR ToByteString(UINT codePage=CP_UTF8)
{
UINT len = Length();
UINT neededLen = len * 4;
UINT nRet = 0;
BSTR pszA = SysAllocStringByteLen(NULL, neededLen);

int _convert = WideCharToMultiByte(codePage, 0, m_str, len, (PSTR)pszA, neededLen, NULL, NULL);
if (_convert == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
_convert = WideCharToMultiByte(codePage, 0, m_str, len, NULL, 0, NULL, NULL);
_SetByteLength(&pszA, _convert);
_convert = WideCharToMultiByte(codePage, 0, m_str, len, (PSTR)pszA, _convert, NULL, NULL);
}
if (_convert == 0 && GetLastError() > 0)
AtlThrowLastWin32();
_SetByteLength(&pszA, _convert);

return pszA;
}
//creates a copy to a wide-string
// optimal usage, attach to it...
BSTR ToWideString(UINT codePage=CP_UTF8) throw()
{
UINT len = ByteLength();
int _convert = MultiByteToWideChar(codePage, 0, (PSTR) m_str, len, NULL, 0);
BSTR pszW = SysAllocStringLen(NULL, _convert);
int nRet = MultiByteToWideChar(codePage, 0, (PSTR)m_str, len, pszW, _convert);
return pszW;

}

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();
}

BSTR b = ::SysAllocStringByteLen((LPCSTR) (LPWSTR) pszW, nRet * sizeof(OLECHAR));
if (b == NULL)
return E_OUTOFMEMORY;
SysFreeString(m_str);
m_str = b;
#endif
}
return S_OK;
}
HRESULT __stdcall 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();
}

BSTR b = ::SysAllocStringByteLen((LPCSTR) (LPWSTR) pszW, nRet * sizeof(OLECHAR));
if (b == NULL)
return E_OUTOFMEMORY;
SysFreeString(m_str);
m_str = b;
#endif
}
return S_OK;
}

bool __cdecl LoadNString(UINT uID, ...) throw()
{
va_list args;
va_start(args, uID);
bool res = _LoadNString(uID, _AtlBaseModule.GetResourceInstance(), args);
va_end(args);
return res;
}
bool __cdecl LoadNString2(UINT uID, HINSTANCE hInst, ...) throw()
{
va_list args;
va_start(args, hInst);
bool res = _LoadNString(uID, hInst, args);
va_end(args);
return res;
}
private:
bool __cdecl _LoadNString(UINT uID, HINSTANCE hInst, va_list args) throw()
{

bool result = true;

PWSTR myMessage = NULL;
LANGID langid = LANGIDFROMLCID(::GetThreadLocale());
LANGID id= PRIMARYLANGID(langid);
int trycnt = 0;
UINT bufSize =0;
DWORD dwerr;
::SetLastError(ERROR_SUCCESS); //fix
do
{
trycnt++;
bufSize = ::FormatMessageW(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER,
hInst, uID, id, (PWSTR) &myMessage, 0, &args);
id= SUBLANGID(langid);
dwerr = ::GetLastError();
} while (dwerr == ERROR_RESOURCE_LANG_NOT_FOUND && trycnt == 1);

if (dwerr != ERROR_SUCCESS)
{
AtlTrace(L"_LoadNString %d", dwerr);
result = false;
}
else
{
Empty();
if (bufSize > 0) bufSize -= 2;
m_str = ::SysAllocStringLen(myMessage, bufSize);
}
if (myMessage != NULL)
::GlobalFree(myMessage);

return result;
}
public:


bool __stdcall LoadString(HINSTANCE hInst, UINT nID) throw()
{
Empty();
return LoadStringResource(hInst, nID, m_str);
}
bool __stdcall LoadString(UINT nID) throw()
{
Empty();
return LoadStringResource(nID, m_str);
}

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

bool __stdcall operator<(const CComBSTR2& bstrSrc) const throw()
{
return Compare(m_str, bstrSrc.m_str, true, true, true) == -1;
}
bool __stdcall operator<(LPCOLESTR pszSrc) const
{
CComBSTR2 bstr2(pszSrc);
return operator<(bstr2);
}
bool __stdcall operator<(LPOLESTR pszSrc) const throw()
{
return operator<((LPCOLESTR)pszSrc);
}

bool __stdcall operator>(const CComBSTR2& bstrSrc) const throw()
{
return Compare(m_str, bstrSrc.m_str, true, true, true) == -1;
}
bool operator>(LPCOLESTR pszSrc) const
{
CComBSTR2 bstr2(pszSrc);
return operator>(bstr2);
}
bool __stdcall operator>(LPOLESTR pszSrc) const throw()
{
return operator>((LPCOLESTR)pszSrc);
}

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

bool __stdcall operator==(const CComBSTR2& bstrSrc) const throw()
{
return (Compare(m_str, bstrSrc.m_str, true, true, true) == 0);
}
bool __stdcall operator==(LPCOLESTR pszSrc) const throw()
{
CComBSTR2 bstr2(pszSrc);
return operator==(bstr2);
}
bool __stdcall operator==(LPOLESTR pszSrc) const throw()
{
return operator==((LPCOLESTR)pszSrc);
}

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

CComBSTR2(int nSize, LPCSTR sz)
{
if (nSize != 0 && sz == NULL)
{
HRESULT hr = SetLength(nSize);
if (FAILED(hr))
AtlThrow(hr);
}
else
{
m_str = A2WBSTR(sz, nSize);
if (m_str == NULL && nSize != 0)
AtlThrow(E_OUTOFMEMORY);
}
}

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

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


CComBSTR2& __stdcall operator=(ULONG ulong)
{
Empty();
HRESULT hr = ::VarBstrFromUI4(ulong, ::GetThreadLocale(), LOCALE_NOUSEROVERRIDE, &m_str);
if (FAILED(hr)) AtlThrow(hr);
return *this;
}
// Define assignment operator.
//A& A::operator=( const A& );

LONG __stdcall ToLong()
{
LONG retval = 0;
HRESULT hr = ::VarI4FromStr(m_str, ::GetThreadLocale(), LOCALE_NOUSEROVERRIDE, &retval);
if (FAILED(hr))
AtlThrow(hr);
return retval;
}
HRESULT __stdcall AssignWordHex(WORD pVal, bool fixedLen = true) throw()
{
return fixedLen ? Format(L"%04x", pVal) : Format(L"%4x", pVal);
}
HRESULT __stdcall AssignLongHex(LONG pVal, bool fixedLen = true) throw()
{
return fixedLen ? Format(L"%08x", pVal) : Format(L"%8x", pVal);
}
CComBSTR2& __stdcall operator=(LONG pSrc)
{
Empty();
HRESULT hr = ::VarBstrFromI4(pSrc, ::GetThreadLocale(), LOCALE_NOUSEROVERRIDE, &m_str);
if (FAILED(hr)) AtlThrow(hr);
return *this;
}
CComBSTR2& __stdcall operator=(USHORT pSrc)
{
Empty();
HRESULT hr = ::VarBstrFromUI2(pSrc, ::GetThreadLocale(), LOCALE_NOUSEROVERRIDE, &m_str);
if (FAILED(hr)) AtlThrow(hr);
return *this;
}
SHORT __stdcall ToShort()
{
SHORT retval = 0;
HRESULT hr = ::VarI2FromStr(m_str, ::GetThreadLocale(), LOCALE_NOUSEROVERRIDE, &retval);
if (FAILED(hr))
AtlThrow(hr);
return retval;
}
CComBSTR2& __stdcall operator=(SHORT pSrc)
{
Empty();
HRESULT hr = ::VarBstrFromI2(pSrc, ::GetThreadLocale(), LOCALE_NOUSEROVERRIDE, &m_str);
if (FAILED(hr)) AtlThrow(hr);
return *this;
}
BYTE __stdcall ToByte()
{
BYTE retval = 0;
HRESULT hr = ::VarUI1FromStr(m_str, ::GetThreadLocale(), LOCALE_NOUSEROVERRIDE, &retval);
if (FAILED(hr))
AtlThrow(hr);
return retval;
}
CComBSTR2& __stdcall operator=(BYTE pSrc)
{
Empty();
HRESULT hr = ::VarBstrFromUI1(pSrc, ::GetThreadLocale(), LOCALE_NOUSEROVERRIDE, &m_str);
if (FAILED(hr)) AtlThrow(hr);
return *this;
}
#if (_WIN32_WINNT >= 0x0501) || defined(_ATL_SUPPORT_VT_I8)
CComBSTR2& operator =(LONG64 pSrc)
{
Empty();
HRESULT hr = ::VarBstrFromI8(pSrc, ::GetThreadLocale(), LOCALE_NOUSEROVERRIDE, &m_str);
if (FAILED(hr)) AtlThrow(hr);
return *this;
}
LONG64 ToVlong()
{
LONG64 retval = 0;
HRESULT hr = ::VarI8FromStr(m_str, ::GetThreadLocale(), LOCALE_NOUSEROVERRIDE, &retval);
if (FAILED(hr)) AtlThrow(hr);
return retval;
}
#endif
FLOAT __stdcall ToFloat()
{
FLOAT retval = 0;
HRESULT hr = ::VarR4FromStr(m_str, ::GetThreadLocale(), LOCALE_NOUSEROVERRIDE, &retval);
if (FAILED(hr))
AtlThrow(hr);
return retval;
}
CComBSTR2& __stdcall operator=(FLOAT pSrc)
{
Empty();
HRESULT hr = ::VarBstrFromR4(pSrc, ::GetThreadLocale(), LOCALE_NOUSEROVERRIDE, &m_str);
if (FAILED(hr)) AtlThrow(hr);
return *this;
}
DOUBLE __stdcall ToDouble()
{
DOUBLE retval = 0;
HRESULT hr = ::VarR8FromStr(m_str, ::GetThreadLocale(), LOCALE_NOUSEROVERRIDE, &retval);
if (FAILED(hr))
AtlThrow(hr);
return retval;
}
CComBSTR2& __stdcall operator=(DOUBLE pSrc)
{
Empty();
HRESULT hr = ::VarBstrFromR8(pSrc, ::GetThreadLocale(), LOCALE_NOUSEROVERRIDE, &m_str);
if (FAILED(hr)) AtlThrow(hr);
return *this;
}

CComBSTR2& __stdcall operator=(LPCSTR pSrc)
{
Empty();
m_str = A2WBSTR(pSrc);
if (m_str == NULL && pSrc != NULL)
AtlThrow(E_OUTOFMEMORY);
return *this;
}
bool __stdcall operator<(LPCSTR pszSrc) const
{
CComBSTR2 bstr2(pszSrc);
return operator<(bstr2);
}
bool __stdcall operator>(LPCSTR pszSrc) const
{
CComBSTR2 bstr2(pszSrc);
return operator>(bstr2);
}
bool __stdcall operator!=(LPCSTR pszSrc) const
{
return !operator==(pszSrc);
}
bool __stdcall operator==(LPCSTR pszSrc) const
{
CComBSTR2 bstr2(pszSrc);
return operator==(bstr2);
}
HRESULT __stdcall 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 __stdcall 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 __stdcall 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 __stdcall 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 __stdcall BSTRToArray(LPSAFEARRAY *ppArray) throw()
{
return VectorFromBstr(m_str, ppArray);
}

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

.



Relevant Pages

  • 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)
  • For the CComBSTR lovers
    ... does not move the BSTR memory to another location. ... unsigned int ByteLength() const throw ... HRESULT __cdecl Formatthrow{va_list args; ...
    (microsoft.public.vc.atl)
  • Re: For the CComBSTR lovers
    ... unsigned int ByteLength() const throw ... operator BSTR() const throw ... HRESULT __cdecl Formatthrow{va_list args; ...
    (microsoft.public.vc.atl)
  • Re: C++ to C#
    ... } public interface ITestExec{int initializeTestApp; ... interface ITestExec: IUnknown {HRESULT _stdcall initializeTestApp([in] IUnknown* wrapper, ... BSTR checkSum, ...
    (microsoft.public.dotnet.framework.interop)
  • Re: C++ to C#
    ... public int initializeTestApp{ ... BSTR checkSum, ... HRESULT _stdcall pingPhone; ...
    (microsoft.public.dotnet.framework.interop)