// FILE: tstring.h // AUTHOR: Davepl // REMARKS: // // // This header file declares the tstring class. This string class is // derived from the Standard C++ Libarary string classes (one of them) // and adds to them the MFC CString conveniences of // // - UNICODE support and // - implicit casts to PCTSTR // - loading from resource files // - formatting (via Format()) function. // - writing to/reading from COM IStream interfaces // - Functional objects for use in STL algorithms // // This header also declares our own version of the MFC/ATL UNICODE-MBCS // conversion macros. Our version looks exactly like the originals in order // facilitate portability. // // (c) 1999 Dave Plummer. Portions of this code derived from source // produced by Joe O'Leary with the following license: // > This code is free. Use it anywhere you want. Rewrite // > it, restructure it, whatever you want. #ifndef _STDSTRING_H_ #define _STDSTRING_H_ // Turn off browser references #ifdef _MSC_VER #pragma component(browser, off, references, "tstring") #endif // Avoid legacy code mess up -- if _UNICODE is defined, then UNICODE must be as well #if defined (_UNICODE) && !defined (UNICODE) #define UNICODE #endif #include #include #ifndef STRICT #define STRICT #endif #include // In non-MFC builds, ASSERT and VERIFY probably won't be defined, so // check to see if they are defined and, if not, define them ourself. #ifndef ASSERT #include // probably already included but do it just in case #define ASSERT(f) _ASSERTE((f)) #endif #ifndef VERIFY #ifdef _DEBUG #define VERIFY(x) ASSERT((x)) #else #define VERIFY(x) x #endif #endif #ifndef TRACE #define TRACE #endif #include // needed for tstring_lessnocase, et al // If this is a recent enough version of VC include comdef.h, we can write many tstring // functions to deal with COM types and compiler support classes like _bstr_t #if defined (_MSC_VER) && (_MSC_VER >= 1100) #include #define STDSTRING_INC_COMDEF // signal that we #included MS comdef.h file #endif #ifndef PCTSTR_DEFINED typedef const TCHAR* PCTSTR; #define PCTSTR_DEFINED #endif #ifndef PCOLESTR #define PCOLESTR LPCOLESTR #endif #ifndef POLESTR #define POLESTR LPOLESTR #endif // UNICODE/MBCS conversion macros. These are made to work just like the MFC/ATL ones. We // will not define them if // _NO_STDCONVERSION - the developer explicitly turned them off // USES_CONVERSION - this is an ATL/MFC build and they are already defined #ifndef _NO_STDCONVERSION #if defined (USES_CONVERSION) #define _NO_STDCONVERSION // Let StdString.cpp know it should not compile functions #else // In MFC builds we can just use the MFC UNICODE conversion macros. // In NON-MFC builds will have to define them ourselves #include #ifdef _MFC_VER #include #define _NO_STDCONVERSION // Let StdString.cpp know it should not compile functions #else // Define our conversion macros to look exactly like the originals // using this stuff both with and without MFC/ATL. Avert your eyes, // its not pretty #ifndef _DEBUG #define USES_CONVERSION int _convert; _convert #else #define USES_CONVERSION int _convert = 0 #endif PWSTR StdA2WHelper(PWSTR pw, PCSTR pa, int nChars); PSTR StdW2AHelper(PSTR pa, PCWSTR pw, int nChars); #define A2W(pa) (\ ((PCSTR)(pa) == NULL) ? NULL : (\ _convert = (strlen((pa))+1),\ StdA2WHelper((LPWSTR) alloca(_convert*2), (pa), _convert))) #define W2A(pw) (\ ((PCWSTR)(pw) == NULL) ? NULL : (\ _convert = (wcslen((pw))+1)*2,\ StdW2AHelper((PSTR) alloca(_convert), (pw), _convert))) #define A2CW(pa) ((PCWSTR)A2W((pa))) #define W2CA(pw) ((PCSTR)W2A((pw))) #ifdef _UNICODE #define T2A W2A #define A2T A2W inline PWSTR T2W(PTSTR p) { return p; } inline PTSTR W2T(PWSTR p) { return p; } #define T2CA W2CA #define A2CT A2CW inline PCWSTR T2CW(PCTSTR p) { return p; } inline PCTSTR W2CT(PCWSTR p) { return p; } #else #define T2W A2W #define W2T W2A inline PSTR T2A(PTSTR p) { return p; } inline PTSTR A2T(PSTR p) { return p; } #define T2CW A2CW #define W2CT W2CA inline PCSTR T2CA(PCTSTR p) { return p; } inline PCTSTR A2CT(PCSTR p) { return p; } #endif // #ifdef _UNICODE #if defined(_UNICODE) // in these cases the default (TCHAR) is the same as OLECHAR inline size_t ocslen(PCOLESTR x) { return wcslen(x); } inline OLECHAR* ocscpy(POLESTR dest, PCOLESTR src) { return wcscpy(dest, src); } inline PCOLESTR T2COLE(PCTSTR p) { return p; } inline PCTSTR OLE2CT(PCOLESTR p) { return p; } inline POLESTR T2OLE(PTSTR p) { return p; } inline PTSTR OLE2T(POLESTR p) { return p; } #elif defined(OLE2ANSI) // in these cases the default (TCHAR) is the same as OLECHAR inline size_t ocslen(PCOLESTR x) { return strlen(x); } inline OLECHAR* ocscpy(POLESTR dest, LPCOLESTR src) { return strcpy(dest, src); } inline PCOLESTR T2COLE(PCTSTR p) { return p; } inline PCTSTR OLE2CT(PCOLESTR p) { return p; } inline POLESTR T2OLE(PTSTR p) { return p; } inline PTSTR OLE2T(POLESTR p) { return p; } #else inline size_t ocslen(PCOLESTR x) { return wcslen(x); } inline OLECHAR* ocscpy(POLESTR dest, PCOLESTR src) {return (POLESTR) memcpy(dest, src, (wcslen(src)+1)*sizeof(WCHAR));} //CharNextW doesn't work on Win95 so we use this #define T2COLE(pa) A2CW((pa)) #define T2OLE(pa) A2W((pa)) #define OLE2CT(po) W2CA((po)) #define OLE2T(po) W2A((po)) #endif #ifdef OLE2ANSI inline POLESTR A2OLE(PSTR p) { return p;} inline PSTR OLE2A(POLESTR p) { return p;} #define W2OLE W2A #define OLE2W A2W inline PCOLESTR A2COLE(PCSTR p) { return p;} inline PCSTR OLE2CA(PCOLESTR p) { return p;} #define W2COLE W2CA #define OLE2CW A2CW #else inline POLESTR W2OLE(PWSTR p) { return p; } inline PWSTR OLE2W(POLESTR p) { return p; } #define A2OLE A2W #define OLE2A W2A inline PCOLESTR W2COLE(PCWSTR p) { return p; } inline PCWSTR OLE2CW(PCOLESTR p) { return p; } #define A2COLE A2CW #define OLE2CA W2CA #endif inline BSTR OLE2BSTR(PCOLESTR p) {return ::SysAllocString(p);} #if defined(_UNICODE) // in these cases the default (TCHAR) is the same as OLECHAR inline BSTR T2BSTR(PCTSTR p) {return ::SysAllocString(p);} inline BSTR A2BSTR(PCSTR p) {USES_CONVERSION; return ::SysAllocString(A2COLE(p));} inline BSTR W2BSTR(PCWSTR p) {return ::SysAllocString(p);} #elif defined(OLE2ANSI) // in these cases the default (TCHAR) is the same as OLECHAR inline BSTR T2BSTR(PCTSTR p) {return ::SysAllocString(p);} inline BSTR A2BSTR(PCSTR p) {return ::SysAllocString(p);} inline BSTR W2BSTR(PCWSTR p) {USES_CONVERSION; return ::SysAllocString(W2COLE(p));} #else inline BSTR T2BSTR(PCTSTR p) {USES_CONVERSION; return ::SysAllocString(T2COLE(p));} inline BSTR A2BSTR(PCSTR p) {USES_CONVERSION; return ::SysAllocString(A2COLE(p));} inline BSTR W2BSTR(PCWSTR p) {return ::SysAllocString(p);} #endif #endif // #ifdef _MFC_VER #endif // #ifndef USES_CONVERSION #endif // #ifndef _NO_STDCONVERSION // Define our own macros for "other" type to TCHAR type conversion // i.e. in a UNICODE build "other" would be char. In a non-UNICODE // build, "other" would be wchar_t These macros make the declaration // of the tstring class a lot cleaner #ifdef _UNICODE #define O2T A2T // "other" type string to generic text type string #define O2CT A2CT // constant "other" type string to generic text type string #define T2O T2A // generic text type string to "other" type string. #define T2CO T2CA // generic text type string to constant "other type string. #else #define O2T W2T #define O2CT W2CT #define T2O T2W #define T2CO T2CW #endif // Define some short names for types that we will refer to in our definition of // the tstring class. #ifdef _UNICODE #define TOTHER char // the "other" char type (opposite of TCHAR) #define POSTR PSTR // the "other" string type (opposite of PTSTR) #define PCOSTR PCSTR // the "other" const string type (oppsite of PCTSTR) const PCOSTR szONull = ""; // an empty string of the "other" type. #else #define TOTHER wchar_t #define POSTR PWSTR #define PCOSTR PCWSTR const PCOSTR szONull = L""; #endif const PCTSTR szTNull = _T(""); // an empty string of the TCHAR type typedef std::basic_string STRBASE; // our base class typedef std::basic_string STROTHER; // opposite of our base // Define TSTRING -- this is a basic_string built around the TCHAR type, kind of like MFC CString // It is also our base class. #ifndef _TSTRING_DEFINED_ #define _TSTRING_DEFINED_ typedef std::basic_string TSTRING; #endif // tstring class // // This class is a simplified version of the Standard C++ Library string or basic string class. It // is derived from basic_string and adds some MFC CString-like functionality class tstring : public STRBASE { public: typedef std::allocator MYALLOC; // constructors tstring(); tstring(const tstring& str); tstring(const STRBASE& str); tstring(const STROTHER& str); tstring(PCTSTR pT); tstring(PCOSTR pO); tstring(const_iterator first, const_iterator last); tstring(size_type nSize, value_type ch, const allocator_type& al=std::allocator()); tstring(UINT nId); #ifdef STDSTRING_INC_COMDEF tstring(const _bstr_t& bstr); // takes the _bstr_t MS compiler COM support class #endif // assignment operators tstring& operator=(const tstring& str); // copy constructor tstring& operator=(const STRBASE& str); // takes a base std string type (string or wstring) tstring& operator=(const STROTHER& str); // takes the other std string type (string or wstring) tstring& operator=(PCTSTR pT); // takes const TCHAR pointer tstring& operator=(PCOSTR pO); // takes const pointer to "other" type (opposite of PCTSTR) tstring& operator=(TCHAR); // takes single character of TCHAR type tstring& operator=(TOTHER); // takes single character of the "other" type #ifdef STDSTRING_INC_COMDEF tstring& operator=(const _bstr_t& bstr); // takes the _bstr_t MS compiler COM support class #endif // These overloads are also needed to fix the MSVC assignment bug (only for our STL - See KB: Q172398) tstring& assign(const tstring& str, tstring::size_type nStart, tstring::size_type nChars); tstring& assign(PCTSTR pT, tstring::size_type nChars); tstring& assign(tstring::size_type nChars, tstring::value_type val); tstring& assign(const tstring& str); tstring& assign(PCTSTR pT); tstring& assign(tstring::const_iterator iterFirst, tstring::const_iterator iterLast); // comparison (equality) bool operator==(const tstring& str) const; bool operator==(const STRBASE& str) const; bool operator==(const STROTHER& str) const; bool operator==(PCTSTR pT) const; bool operator==(PCOSTR pO) const; bool operator==(TCHAR t) const; bool operator==(TOTHER t) const; // Note the default here is case INsensitive bool Equals(PCTSTR pT, bool bUseCase=false) const; // comparison operators (inequality) bool operator!=(const tstring& str) const; bool operator!=(const STRBASE& str) const; bool operator!=(const STROTHER& str) const; bool operator!=(PCTSTR pT) const; bool operator!=(PCOSTR pO) const; bool operator!=(TCHAR t) const; bool operator!=(TOTHER t) const; // comparison operator (less than) bool operator<(const tstring& str) const; bool operator<(PCTSTR str) const; // concatenation. const tstring& operator+=(const tstring& str); const tstring& operator+=(const STRBASE& str); const tstring& operator+=(const STROTHER& str); const tstring& operator+=(PCTSTR pT); const tstring& operator+=(PCOSTR pO); const tstring& operator+=(TCHAR t); const tstring& operator+=(TOTHER t); #ifdef STDSTRING_INC_COMDEF const tstring& operator+=(const _bstr_t& bstr); #endif // addition operators -- global friend functions. friend tstring operator+(const tstring& str1, const tstring& str2); friend tstring operator+(const tstring& str, TCHAR ch); friend tstring operator+(TCHAR ch, const tstring& str); friend tstring operator+(const tstring& str, TOTHER ch); friend tstring operator+(TOTHER ch, const tstring& str); friend tstring operator+(const tstring& str, PCTSTR sz); friend tstring operator+(PCTSTR sz, const tstring& str); friend tstring operator+(const tstring& str, PCOSTR sz); friend tstring operator+(PCOSTR sz, const tstring& str); #ifdef STDSTRING_INC_COMDEF friend tstring operator+(const _bstr_t& bstr, const tstring& str); friend tstring operator+(const tstring& str, const _bstr_t& bstr); #endif // Conversion to "other" type of string (i.e. to string if we're a wstring, to wstring if we're a string) STROTHER Other() const { USES_CONVERSION; return T2CO(c_str()); }; // General utility stuff LPTSTR GetBuffer(int n = -1) { if ( (-1 != n) && (n > (int)length()) ) resize(n); return (LPTSTR) data(); } void ReleaseBuffer( int n = -1 ) { if (-1 == n) n = _tcslen( data() ); resize(n); } operator CComBSTR() const { PCTSTR pFoo = *this; return CComBSTR( pFoo ); } operator PCTSTR() const; // implicit cast to const TCHAR* bool Load(UINT nId); // load using resource id tstring& Format(PCTSTR szFormat, ...); // format using literal string tstring& Format(UINT nId, ...); // format using resource string identifier tstring& FormatV(PCTSTR szFormat, va_list argList); // format using a va_list instead of ... tstring& TrimRight(); // chop off all whitespace characters on right tstring& TrimLeft(); // chop off all whitespace characters on left tstring& ToUpper(); // make uppercase tstring& ToLower(); // make lowercase bool IsEmpty() const { return empty(); }; TCHAR& operator[](int nIdx); const TCHAR& operator[](int nIdx) const; #ifdef STDSTRING_INC_COMDEF HRESULT StreamSave(IStream* pStream) const; // write to an IStream HRESULT StreamLoad(IStream* pStream); // read from an IStream; ULONG StreamSize() const; // how many bytes needed to write to an IStream? #endif // These static functions simplify copying one C-style string to another, either one or two byte. static void CopyString(PCTSTR p_szSource, PTSTR p_szDest, int p_nMaxChars=0); static void CopyString(PCOSTR p_szSource, POSTR p_szDest, int p_nMaxChars=0); static void CopyString(PCSTR p_szSource, PWSTR p_szDest, int p_nMaxChars=0); static void CopyString(PCWSTR p_szSource, PSTR, int p_nMaxChars=0); // If this is NOT an MFC build, provide a SetResourceHandle function so that those who call // the versions of Load(), Format(), or the constructor that take resource IDs can provide // an alternate HINST of a DLL to search. This is not exactly the list of link libraries // that MFC provides but it's better than nothing. static void SetResourceHandle(HINSTANCE hNew); static HINSTANCE GetResourceHandle(); protected: #if !defined(_MFC_VER) static HINSTANCE hInstResource; // implementation of Get/SetResourceHandle in non-MFC builds #endif }; #define _TRES(pctstr) (LOWORD((pctstr))) // shorthand conversion from PCTSTR to string resource ID // tstring inline constructors inline tstring::tstring() {} inline tstring::tstring(const STRBASE& str) { *this = str; }; //inline tstring::tstring(PCTSTR pT) { *this = (pT == NULL ? szTNull : pT); }; inline tstring::tstring(PCOSTR pO) { *this = (pO == NULL ? szONull : pO); }; inline tstring::tstring(const tstring& str) { *this = str; }; inline tstring::tstring(const STROTHER& str) { *this = str; }; inline tstring::tstring(const_iterator first, const_iterator last) : STRBASE(first, last) {}; inline tstring::tstring(size_type nSize, value_type ch, const allocator_type& al) : STRBASE(nSize, ch, al) { } #ifdef STDSTRING_INC_COMDEF inline tstring::tstring(const _bstr_t& bstr) { *this = static_cast(bstr); } #endif // tstring inline assignment operators -- the erase() function // call fixes the MSVC assignment bug (see knowledge base article Q172398). inline tstring& tstring::operator=(const tstring& str) { if ( str.data() != data() ) { erase(); STRBASE::assign(str.data());} return *this; }; inline tstring& tstring::operator=(const STRBASE& str) { if ( str.data() != data() ) { erase(); STRBASE::assign(str.data());} return *this; }; inline tstring& tstring::operator=(const STROTHER& str) { erase(); USES_CONVERSION; STRBASE::assign(O2CT(str.data())); return *this; }; inline tstring& tstring::operator=(PCTSTR pT) { if ( pT != data() ) { erase(); if ( pT != NULL ) STRBASE::assign(pT); } return *this; }; inline tstring& tstring::operator=(PCOSTR pO) { erase(); if ( pO != NULL ) { USES_CONVERSION; STRBASE::assign(O2CT(pO)); } return *this; }; inline tstring& tstring::operator=(TOTHER t) { erase(); USES_CONVERSION; STRBASE::assign(O2CT(&t)); return *this; }; inline tstring& tstring::operator=(TCHAR t) { erase(); STRBASE::assign(1,t); return *this; }; #ifdef STDSTRING_INC_COMDEF inline tstring& tstring::operator=(const _bstr_t& bstr) { return operator=(static_cast(bstr)); } #endif // These overloads are also needed to fix the MSVC assignment bug (KB: Q172398) // *** Thanks to Pete The Plumber for catching this one *** inline tstring& tstring::assign(const tstring& str, tstring::size_type nStart, tstring::size_type nChars) { if( str.data() != data() ) erase(); STRBASE::assign(str, nStart, nChars); return *this; } inline tstring& tstring::assign(PCTSTR pT, tstring::size_type nChars) { if( pT != data() ) erase(); STRBASE::assign(pT, nChars); return *this; } inline tstring& tstring::assign(tstring::size_type nChars, tstring::value_type val) { erase(); STRBASE::assign(nChars, val); return *this; } inline tstring& tstring::assign(const tstring& str) { return assign(str, 0, npos); } inline tstring& tstring::assign(PCTSTR pT) { return assign(pT, tstring::traits_type::length(pT)); } inline tstring& tstring::assign(tstring::const_iterator iterFirst, tstring::const_iterator iterLast) { replace(begin(), end(), iterFirst, iterLast); return *this; } // tstring inline comparison (equality) inline bool tstring::operator==(const tstring& str) const { return compare(str.c_str()) == 0; }; inline bool tstring::operator==(const STRBASE& str) const { return compare(str.data()) == 0; }; inline bool tstring::operator==(const STROTHER& str) const { USES_CONVERSION; return compare(O2CT(str.data())) == 0; }; inline bool tstring::operator==(PCTSTR pT) const { return compare(pT) == 0; }; inline bool tstring::operator==(PCOSTR pO) const { USES_CONVERSION; return compare(O2CT(pO)) == 0; }; inline bool tstring::operator==(TCHAR t) const { return operator==(STRBASE(1,t)); }; inline bool tstring::operator==(TOTHER t) const { USES_CONVERSION; return operator==(tstring(O2CT(&t))); }; inline bool tstring::Equals(PCTSTR pT, bool bUseCase/*=false*/) const // defaults to case insensitive { return bUseCase ? compare(pT) == 0 : _tcsicmp(tstring(*this), pT) == 0; } // get copy, THEN compare (thread safe) //inline bool tstring::WildcardEquals(PCTSTR pT, bool bUseCase/*=false*/) const // defaults to case insensitive //{ tstring me(*this), mask(pT); if( !bUseCase ) { me.ToUpper(); mask.ToUpper(); } return Wildstrcmp(me, mask); } // get copy, THEN compare (thread safe) // tstring inline comparison operators (inequality) inline bool tstring::operator!=(const tstring& str) const { return compare(str.c_str()) != 0; }; inline bool tstring::operator!=(const STRBASE& str) const { return compare(str.data()) != 0; }; inline bool tstring::operator!=(const STROTHER& str) const { USES_CONVERSION; return compare(O2CT(str.data())) != 0; }; inline bool tstring::operator!=(PCTSTR pT) const { return compare(pT) != 0; }; inline bool tstring::operator!=(PCOSTR pO) const { USES_CONVERSION; return compare(O2CT(pO)) != 0; }; inline bool tstring::operator!=(TCHAR t) const { return operator!=(STRBASE(1,t)); }; inline bool tstring::operator!=(TOTHER t) const { USES_CONVERSION; return operator!=(tstring(O2CT(&t))); }; // tstring comparison operator (less than) inline bool tstring::operator<(const tstring& str) const { return compare(str) < 0; }; inline bool tstring::operator<(PCTSTR str) const { return compare(str) < 0; }; // tstring inline concatenation. inline const tstring& tstring::operator+=(const tstring& str) { append(str); return *this; }; inline const tstring& tstring::operator+=(const STRBASE& str) { append(str); return *this; }; inline const tstring& tstring::operator+=(const STROTHER& str) { USES_CONVERSION; *this += O2CT(str.c_str()); return *this; }; inline const tstring& tstring::operator+=(PCTSTR pT) { if ( pT != NULL ) append(pT); return *this; }; inline const tstring& tstring::operator+=(PCOSTR pO) { USES_CONVERSION; if ( pO != NULL ) append(O2CT(pO)); return *this; }; inline const tstring& tstring::operator+=(TCHAR t) { append(1, t); return *this; }; inline const tstring& tstring::operator+=(TOTHER t) { USES_CONVERSION; append(O2CT(&t)); return *this; }; #ifdef STDSTRING_INC_COMDEF inline const tstring& tstring::operator+=(const _bstr_t& bstr) { return operator+=(static_cast(bstr)); } #endif // tstring friend addition functions defined as inline inline tstring operator+(const tstring& str1, const tstring& str2) { tstring strRet(str1); return strRet.append(str2); } inline tstring operator+(const tstring& str, TCHAR ch) { tstring strRet(str); return strRet.append(1, ch); } inline tstring operator+(TCHAR ch, const tstring& str) { tstring strRet(1, ch); return strRet.append(str); } inline tstring operator+(const tstring& str, TOTHER ch) { return str + STROTHER(1, ch).data(); } inline tstring operator+(TOTHER ch, const tstring& str) { tstring strRet; strRet = ch; return strRet.append(str); } inline tstring operator+(const tstring& str, PCTSTR sz) { tstring strRet(str); return sz == NULL ? strRet : strRet.append(sz); } inline tstring operator+(PCTSTR sz, const tstring& str) { tstring strRet(sz); return strRet.append(str); } inline tstring operator+(const tstring& str, PCOSTR sz) { tstring strRet(str); return strRet.append(tstring(sz)); } inline tstring operator+(PCOSTR sz, const tstring& str) { tstring strRet(sz); return strRet.append(str); } #ifdef STDSTRING_INC_COMDEF inline tstring operator+(const _bstr_t& bstr, const tstring& str) { return tstring(static_cast(bstr)) + str; } inline tstring operator+(const tstring& str, const _bstr_t& bstr) { return str + static_cast(bstr); } #endif inline TCHAR& tstring::operator[](int nIdx) { return STRBASE::operator[](nIdx); } inline const TCHAR& tstring::operator[](int nIdx) const { return STRBASE::operator[](nIdx); } inline tstring::operator PCTSTR() const { return c_str(); }; // implicit cast to const TCHAR* // In MFC builds, define some global serialization operators #ifdef _MFC_VER CArchive& AFXAPI operator>>(CArchive& ar, tstring& string); CArchive& AFXAPI operator<<(CArchive& ar, const tstring& string); inline void tstring::SetResourceHandle(HINSTANCE hNew) { AfxSetResourceHandle(hNew); } inline HINSTANCE tstring::GetResourceHandle() { return AfxGetResourceHandle(); }; #else // Because we're a template with no C file, we can't simply have a glocal static // HINSTANCE. Instead, we have a class-static function which in turn has a static // HINSTANCE. Since only that class-static function has access to the HINSTANCE, // it has the ability to set or retrieve its static HINSTANCE. // // In short, the HInstanceSingleton is static to the class, and its _hInstance // variable is static to the HInstanceSingleton function, so the _hInstance variable // is static to the class. inline const HINSTANCE & HInstanceSingleton(HINSTANCE hNew = NULL, bool bSet = false) { static HINSTANCE _hInstance = ::GetModuleHandle(NULL); if (bSet) _hInstance = hNew; return _hInstance; } inline void tstring::SetResourceHandle(HINSTANCE hNew) { HInstanceSingleton(hNew, true); } inline HINSTANCE tstring::GetResourceHandle() { return HInstanceSingleton(); }; #endif // Some code still refers to old names of this class -- Account for this. #define CSTLString tstring #define CW32String tstring // WUSysMessage -- return the system string corresponding to a system error or HRESULT value. tstring WUSysMessage(DWORD dwError, DWORD p_dwLangId=MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT)); // WUFormat -- creates and formats a tstring with one line of code instead of the two it normally takes tstring WUFormat(PCTSTR szFormat, ...); tstring WUFormat(UINT nId, ...); // Functional Comparators // // These structs are derived from the std::binary_function template. They give us functional // classes (which may be used in Standard C++ Library collections and algorithms) that perform // case-insensitive comparisons of tstring objects. This is useful for maps in which the key // may be the proper string but in the wrong case. #define tstring_lessnocase _SSLNC // define shorter name to avoid compiler warning 4786 #define tstring_comparenocase _SSENC // define shorter name to avoid compiler warning 4786 struct tstring_lessnocase : std::binary_function { bool operator()(const tstring& strFirst, const tstring& strSecond) const { return _tcsicmp(strFirst, strSecond) < 0; } }; struct tstring_comparenocase : std::binary_function { bool operator()(const tstring& strFirst, const tstring& strSecond) const { return _tcsicmp(strFirst, strSecond) == 0; } }; #endif // #ifndef _STDSTRING_H_