1 // Windows Template Library - WTL version 8.0
2 // Copyright (C) Microsoft Corporation. All rights reserved.
4 // This file is a part of the Windows Template Library.
5 // The use and distribution terms for this software are covered by the
6 // Microsoft Permissive License (Ms-PL) which can be found in the file
7 // Ms-PL.txt at the root of this distribution.
15 #error ATL requires C++ compilation (use a .cpp suffix)
19 #error atlmisc.h requires atlapp.h to be included first
23 #ifdef _ATL_TMP_NO_CSTRING
24 #define _WTL_NO_CSTRING
27 #if defined(_WTL_USE_CSTRING) && defined(_WTL_NO_CSTRING)
28 #error Conflicting options - both _WTL_USE_CSTRING and _WTL_NO_CSTRING are defined
29 #endif // defined(_WTL_USE_CSTRING) && defined(_WTL_NO_CSTRING)
31 #if !defined(_WTL_USE_CSTRING) && !defined(_WTL_NO_CSTRING)
32 #define _WTL_USE_CSTRING
33 #endif // !defined(_WTL_USE_CSTRING) && !defined(_WTL_NO_CSTRING)
35 #ifndef _WTL_NO_CSTRING
36 #if defined(_ATL_USE_CSTRING_FLOAT) && defined(_ATL_MIN_CRT)
37 #error Cannot use CString floating point formatting with _ATL_MIN_CRT defined
38 #endif // defined(_ATL_USE_CSTRING_FLOAT) && defined(_ATL_MIN_CRT)
39 #endif // !_WTL_NO_CSTRING
42 ///////////////////////////////////////////////////////////////////////////////
43 // Classes in this file:
50 // CRecentDocumentListBase<T, t_cchItemLen, t_nFirstID, t_nLastID>
51 // CRecentDocumentList
55 // AtlLoadAccelerators()
63 // AtlLoadBitmapImage()
64 // AtlLoadCursorImage()
66 // AtlLoadSysBitmapImage()
67 // AtlLoadSysCursorImage()
68 // AtlLoadSysIconImage()
74 // AtlGetStockPalette()
82 #ifndef _WTL_NO_WTYPES
84 // forward declarations
89 ///////////////////////////////////////////////////////////////////////////////
90 // CSize - Wrapper for Windows SIZE structure.
92 class CSize
: public SIZE
102 CSize(int initCX
, int initCY
)
110 *(SIZE
*)this = initSize
;
115 *(POINT
*)this = initPt
;
120 cx
= (short)LOWORD(dwSize
);
121 cy
= (short)HIWORD(dwSize
);
125 BOOL
operator ==(SIZE size
) const
127 return (cx
== size
.cx
&& cy
== size
.cy
);
130 BOOL
operator !=(SIZE size
) const
132 return (cx
!= size
.cx
|| cy
!= size
.cy
);
135 void operator +=(SIZE size
)
141 void operator -=(SIZE size
)
147 void SetSize(int CX
, int CY
)
153 // Operators returning CSize values
154 CSize
operator +(SIZE size
) const
156 return CSize(cx
+ size
.cx
, cy
+ size
.cy
);
159 CSize
operator -(SIZE size
) const
161 return CSize(cx
- size
.cx
, cy
- size
.cy
);
164 CSize
operator -() const
166 return CSize(-cx
, -cy
);
169 // Operators returning CPoint values
170 CPoint
operator +(POINT point
) const;
171 CPoint
operator -(POINT point
) const;
173 // Operators returning CRect values
174 CRect
operator +(const RECT
* lpRect
) const;
175 CRect
operator -(const RECT
* lpRect
) const;
179 ///////////////////////////////////////////////////////////////////////////////
180 // CPoint - Wrapper for Windows POINT structure.
182 class CPoint
: public POINT
192 CPoint(int initX
, int initY
)
200 *(POINT
*)this = initPt
;
203 CPoint(SIZE initSize
)
205 *(SIZE
*)this = initSize
;
208 CPoint(DWORD dwPoint
)
210 x
= (short)LOWORD(dwPoint
);
211 y
= (short)HIWORD(dwPoint
);
215 void Offset(int xOffset
, int yOffset
)
221 void Offset(POINT point
)
227 void Offset(SIZE size
)
233 BOOL
operator ==(POINT point
) const
235 return (x
== point
.x
&& y
== point
.y
);
238 BOOL
operator !=(POINT point
) const
240 return (x
!= point
.x
|| y
!= point
.y
);
243 void operator +=(SIZE size
)
249 void operator -=(SIZE size
)
255 void operator +=(POINT point
)
261 void operator -=(POINT point
)
267 void SetPoint(int X
, int Y
)
273 // Operators returning CPoint values
274 CPoint
operator +(SIZE size
) const
276 return CPoint(x
+ size
.cx
, y
+ size
.cy
);
279 CPoint
operator -(SIZE size
) const
281 return CPoint(x
- size
.cx
, y
- size
.cy
);
284 CPoint
operator -() const
286 return CPoint(-x
, -y
);
289 CPoint
operator +(POINT point
) const
291 return CPoint(x
+ point
.x
, y
+ point
.y
);
294 // Operators returning CSize values
295 CSize
operator -(POINT point
) const
297 return CSize(x
- point
.x
, y
- point
.y
);
300 // Operators returning CRect values
301 CRect
operator +(const RECT
* lpRect
) const;
302 CRect
operator -(const RECT
* lpRect
) const;
306 ///////////////////////////////////////////////////////////////////////////////
307 // CRect - Wrapper for Windows RECT structure.
309 class CRect
: public RECT
321 CRect(int l
, int t
, int r
, int b
)
329 CRect(const RECT
& srcRect
)
331 ::CopyRect(this, &srcRect
);
334 CRect(LPCRECT lpSrcRect
)
336 ::CopyRect(this, lpSrcRect
);
339 CRect(POINT point
, SIZE size
)
341 right
= (left
= point
.x
) + size
.cx
;
342 bottom
= (top
= point
.y
) + size
.cy
;
345 CRect(POINT topLeft
, POINT bottomRight
)
349 right
= bottomRight
.x
;
350 bottom
= bottomRight
.y
;
353 // Attributes (in addition to RECT members)
366 return CSize(right
- left
, bottom
- top
);
371 return *((CPoint
*)this);
374 CPoint
& BottomRight()
376 return *((CPoint
*)this + 1);
379 const CPoint
& TopLeft() const
381 return *((CPoint
*)this);
384 const CPoint
& BottomRight() const
386 return *((CPoint
*)this + 1);
389 CPoint
CenterPoint() const
391 return CPoint((left
+ right
) / 2, (top
+ bottom
) / 2);
394 // convert between CRect and LPRECT/LPCRECT (no need for &)
400 operator LPCRECT() const
405 BOOL
IsRectEmpty() const
407 return ::IsRectEmpty(this);
410 BOOL
IsRectNull() const
412 return (left
== 0 && right
== 0 && top
== 0 && bottom
== 0);
415 BOOL
PtInRect(POINT point
) const
417 return ::PtInRect(this, point
);
421 void SetRect(int x1
, int y1
, int x2
, int y2
)
423 ::SetRect(this, x1
, y1
, x2
, y2
);
426 void SetRect(POINT topLeft
, POINT bottomRight
)
428 ::SetRect(this, topLeft
.x
, topLeft
.y
, bottomRight
.x
, bottomRight
.y
);
433 ::SetRectEmpty(this);
436 void CopyRect(LPCRECT lpSrcRect
)
438 ::CopyRect(this, lpSrcRect
);
441 BOOL
EqualRect(LPCRECT lpRect
) const
443 return ::EqualRect(this, lpRect
);
446 void InflateRect(int x
, int y
)
448 ::InflateRect(this, x
, y
);
451 void InflateRect(SIZE size
)
453 ::InflateRect(this, size
.cx
, size
.cy
);
456 void InflateRect(LPCRECT lpRect
)
458 left
-= lpRect
->left
;
460 right
+= lpRect
->right
;
461 bottom
+= lpRect
->bottom
;
464 void InflateRect(int l
, int t
, int r
, int b
)
472 void DeflateRect(int x
, int y
)
474 ::InflateRect(this, -x
, -y
);
477 void DeflateRect(SIZE size
)
479 ::InflateRect(this, -size
.cx
, -size
.cy
);
482 void DeflateRect(LPCRECT lpRect
)
484 left
+= lpRect
->left
;
486 right
-= lpRect
->right
;
487 bottom
-= lpRect
->bottom
;
490 void DeflateRect(int l
, int t
, int r
, int b
)
498 void OffsetRect(int x
, int y
)
500 ::OffsetRect(this, x
, y
);
502 void OffsetRect(SIZE size
)
504 ::OffsetRect(this, size
.cx
, size
.cy
);
507 void OffsetRect(POINT point
)
509 ::OffsetRect(this, point
.x
, point
.y
);
529 // absolute position of rectangle
532 bottom
= Height() + y
;
542 void MoveToXY(int x
, int y
)
548 void MoveToXY(POINT pt
)
554 // operations that fill '*this' with result
555 BOOL
IntersectRect(LPCRECT lpRect1
, LPCRECT lpRect2
)
557 return ::IntersectRect(this, lpRect1
, lpRect2
);
560 BOOL
UnionRect(LPCRECT lpRect1
, LPCRECT lpRect2
)
562 return ::UnionRect(this, lpRect1
, lpRect2
);
565 BOOL
SubtractRect(LPCRECT lpRectSrc1
, LPCRECT lpRectSrc2
)
567 return ::SubtractRect(this, lpRectSrc1
, lpRectSrc2
);
570 // Additional Operations
571 void operator =(const RECT
& srcRect
)
573 ::CopyRect(this, &srcRect
);
576 BOOL
operator ==(const RECT
& rect
) const
578 return ::EqualRect(this, &rect
);
581 BOOL
operator !=(const RECT
& rect
) const
583 return !::EqualRect(this, &rect
);
586 void operator +=(POINT point
)
588 ::OffsetRect(this, point
.x
, point
.y
);
591 void operator +=(SIZE size
)
593 ::OffsetRect(this, size
.cx
, size
.cy
);
596 void operator +=(LPCRECT lpRect
)
601 void operator -=(POINT point
)
603 ::OffsetRect(this, -point
.x
, -point
.y
);
606 void operator -=(SIZE size
)
608 ::OffsetRect(this, -size
.cx
, -size
.cy
);
611 void operator -=(LPCRECT lpRect
)
616 void operator &=(const RECT
& rect
)
618 ::IntersectRect(this, this, &rect
);
621 void operator |=(const RECT
& rect
)
623 ::UnionRect(this, this, &rect
);
626 // Operators returning CRect values
627 CRect
operator +(POINT pt
) const
630 ::OffsetRect(&rect
, pt
.x
, pt
.y
);
634 CRect
operator -(POINT pt
) const
637 ::OffsetRect(&rect
, -pt
.x
, -pt
.y
);
641 CRect
operator +(LPCRECT lpRect
) const
644 rect
.InflateRect(lpRect
);
648 CRect
operator +(SIZE size
) const
651 ::OffsetRect(&rect
, size
.cx
, size
.cy
);
655 CRect
operator -(SIZE size
) const
658 ::OffsetRect(&rect
, -size
.cx
, -size
.cy
);
662 CRect
operator -(LPCRECT lpRect
) const
665 rect
.DeflateRect(lpRect
);
669 CRect
operator &(const RECT
& rect2
) const
672 ::IntersectRect(&rect
, this, &rect2
);
676 CRect
operator |(const RECT
& rect2
) const
679 ::UnionRect(&rect
, this, &rect2
);
683 CRect
MulDiv(int nMultiplier
, int nDivisor
) const
686 ::MulDiv(left
, nMultiplier
, nDivisor
),
687 ::MulDiv(top
, nMultiplier
, nDivisor
),
688 ::MulDiv(right
, nMultiplier
, nDivisor
),
689 ::MulDiv(bottom
, nMultiplier
, nDivisor
));
694 // CSize implementation
696 inline CPoint
CSize::operator +(POINT point
) const
697 { return CPoint(cx
+ point
.x
, cy
+ point
.y
); }
699 inline CPoint
CSize::operator -(POINT point
) const
700 { return CPoint(cx
- point
.x
, cy
- point
.y
); }
702 inline CRect
CSize::operator +(const RECT
* lpRect
) const
703 { return CRect(lpRect
) + *this; }
705 inline CRect
CSize::operator -(const RECT
* lpRect
) const
706 { return CRect(lpRect
) - *this; }
709 // CPoint implementation
711 inline CRect
CPoint::operator +(const RECT
* lpRect
) const
712 { return CRect(lpRect
) + *this; }
714 inline CRect
CPoint::operator -(const RECT
* lpRect
) const
715 { return CRect(lpRect
) - *this; }
717 #endif // !_WTL_NO_WTYPES
720 // WTL::CSize or ATL::CSize scalar operators
722 #if !defined(_WTL_NO_SIZE_SCALAR) && (!defined(_WTL_NO_WTYPES) || defined(__ATLTYPES_H__))
725 inline CSize
operator *(SIZE s
, Num n
)
727 return CSize((int)(s
.cx
* n
), (int)(s
.cy
* n
));
731 inline void operator *=(SIZE
& s
, Num n
)
737 inline CSize
operator /(SIZE s
, Num n
)
739 return CSize((int)(s
.cx
/ n
), (int)(s
.cy
/ n
));
743 inline void operator /=(SIZE
& s
, Num n
)
748 #endif // !defined(_WTL_NO_SIZE_SCALAR) && (!defined(_WTL_NO_WTYPES) || defined(__ATLTYPES_H__))
751 ///////////////////////////////////////////////////////////////////////////////
752 // CString - String class
754 #ifndef _WTL_NO_CSTRING
758 long nRefs
; // reference count
761 // TCHAR data[nAllocLength]
764 { return (TCHAR
*)(this + 1); }
769 // For an empty string, m_pchData will point here
770 // (note: avoids special case of checking for NULL m_pchData)
771 // empty string data (and locked)
772 _declspec(selectany
) int rgInitData
[] = { -1, 0, 0, 0 };
773 _declspec(selectany
) CStringData
* _atltmpDataNil
= (CStringData
*)&rgInitData
;
774 _declspec(selectany
) LPCTSTR _atltmpPchNil
= (LPCTSTR
)(((BYTE
*)&rgInitData
) + sizeof(CStringData
));
786 CString(const CString
& stringSrc
)
788 ATLASSERT(stringSrc
.GetData()->nRefs
!= 0);
789 if (stringSrc
.GetData()->nRefs
>= 0)
791 ATLASSERT(stringSrc
.GetData() != _atltmpDataNil
);
792 m_pchData
= stringSrc
.m_pchData
;
793 InterlockedIncrement(&GetData()->nRefs
);
798 *this = stringSrc
.m_pchData
;
802 CString(TCHAR ch
, int nRepeat
= 1)
804 ATLASSERT(!_istlead(ch
)); // can't create a lead byte string
808 if(AllocBuffer(nRepeat
))
811 for (int i
= 0; i
< nRepeat
; i
++)
814 memset(m_pchData
, ch
, nRepeat
);
820 CString(LPCTSTR lpsz
)
823 if (lpsz
!= NULL
&& HIWORD(lpsz
) == NULL
)
825 UINT nID
= LOWORD((DWORD_PTR
)lpsz
);
826 if (!LoadString(nID
))
827 ATLTRACE2(atlTraceUI
, 0, _T("Warning: implicit LoadString(%u) in CString failed\n"), nID
);
831 int nLen
= SafeStrlen(lpsz
);
834 if(AllocBuffer(nLen
))
835 SecureHelper::memcpy_x(m_pchData
, (nLen
+ 1) * sizeof(TCHAR
), lpsz
, nLen
* sizeof(TCHAR
));
844 #if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800)
845 int nSrcLen
= (lpsz
!= NULL
) ? ATL::lstrlenA(lpsz
) : 0;
847 int nSrcLen
= (lpsz
!= NULL
) ? lstrlenA(lpsz
) : 0;
851 if(AllocBuffer(nSrcLen
))
853 _mbstowcsz(m_pchData
, lpsz
, nSrcLen
+ 1);
859 CString(LPCWSTR lpsz
)
862 int nSrcLen
= (lpsz
!= NULL
) ? (int)wcslen(lpsz
) : 0;
865 if(AllocBuffer(nSrcLen
* 2))
867 _wcstombsz(m_pchData
, lpsz
, (nSrcLen
* 2) + 1);
874 CString(LPCTSTR lpch
, int nLength
)
879 if(AllocBuffer(nLength
))
880 SecureHelper::memcpy_x(m_pchData
, (nLength
+ 1) * sizeof(TCHAR
), lpch
, nLength
* sizeof(TCHAR
));
885 CString(LPCSTR lpsz
, int nLength
)
890 if(AllocBuffer(nLength
))
892 int n
= ::MultiByteToWideChar(CP_ACP
, 0, lpsz
, nLength
, m_pchData
, nLength
+ 1);
893 ReleaseBuffer((n
>= 0) ? n
: -1);
898 CString(LPCWSTR lpsz
, int nLength
)
903 if(((nLength
* 2) > nLength
) && AllocBuffer(nLength
* 2))
905 int n
= ::WideCharToMultiByte(CP_ACP
, 0, lpsz
, nLength
, m_pchData
, (nLength
* 2) + 1, NULL
, NULL
);
906 ReleaseBuffer((n
>= 0) ? n
: -1);
912 CString(const unsigned char* lpsz
)
915 *this = (LPCSTR
)lpsz
;
918 // Attributes & Operations
919 int GetLength() const // as an array of characters
921 return GetData()->nDataLength
;
926 return GetData()->nDataLength
== 0;
929 void Empty() // free up the data
931 if (GetData()->nDataLength
== 0)
934 if (GetData()->nRefs
>= 0)
939 ATLASSERT(GetData()->nDataLength
== 0);
940 ATLASSERT(GetData()->nRefs
< 0 || GetData()->nAllocLength
== 0);
943 TCHAR
GetAt(int nIndex
) const // 0 based
945 ATLASSERT(nIndex
>= 0);
946 ATLASSERT(nIndex
< GetData()->nDataLength
);
947 return m_pchData
[nIndex
];
950 TCHAR
operator [](int nIndex
) const // same as GetAt
953 ATLASSERT(nIndex
>= 0);
954 ATLASSERT(nIndex
< GetData()->nDataLength
);
955 return m_pchData
[nIndex
];
958 void SetAt(int nIndex
, TCHAR ch
)
960 ATLASSERT(nIndex
>= 0);
961 ATLASSERT(nIndex
< GetData()->nDataLength
);
964 m_pchData
[nIndex
] = ch
;
967 operator LPCTSTR() const // as a C string
972 // overloaded assignment
973 CString
& operator =(const CString
& stringSrc
)
975 if (m_pchData
!= stringSrc
.m_pchData
)
977 if ((GetData()->nRefs
< 0 && GetData() != _atltmpDataNil
) || stringSrc
.GetData()->nRefs
< 0)
979 // actual copy necessary since one of the strings is locked
980 AssignCopy(stringSrc
.GetData()->nDataLength
, stringSrc
.m_pchData
);
984 // can just copy references around
986 ATLASSERT(stringSrc
.GetData() != _atltmpDataNil
);
987 m_pchData
= stringSrc
.m_pchData
;
988 InterlockedIncrement(&GetData()->nRefs
);
994 CString
& operator =(TCHAR ch
)
996 ATLASSERT(!_istlead(ch
)); // can't set single lead byte
1002 CString
& operator =(char ch
)
1009 CString
& operator =(LPCTSTR lpsz
)
1011 ATLASSERT(lpsz
== NULL
|| _IsValidString(lpsz
));
1012 AssignCopy(SafeStrlen(lpsz
), lpsz
);
1017 CString
& operator =(LPCSTR lpsz
)
1019 #if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800)
1020 int nSrcLen
= (lpsz
!= NULL
) ? ATL::lstrlenA(lpsz
) : 0;
1022 int nSrcLen
= (lpsz
!= NULL
) ? lstrlenA(lpsz
) : 0;
1024 if(AllocBeforeWrite(nSrcLen
))
1026 _mbstowcsz(m_pchData
, lpsz
, nSrcLen
+ 1);
1032 CString
& operator =(LPCWSTR lpsz
)
1034 int nSrcLen
= (lpsz
!= NULL
) ? (int)wcslen(lpsz
) : 0;
1035 if(AllocBeforeWrite(nSrcLen
* 2))
1037 _wcstombsz(m_pchData
, lpsz
, (nSrcLen
* 2) + 1);
1044 CString
& operator =(const unsigned char* lpsz
)
1046 *this = (LPCSTR
)lpsz
;
1050 // string concatenation
1051 CString
& operator +=(const CString
& string
)
1053 ConcatInPlace(string
.GetData()->nDataLength
, string
.m_pchData
);
1057 CString
& operator +=(TCHAR ch
)
1059 ConcatInPlace(1, &ch
);
1064 CString
& operator +=(char ch
)
1071 CString
& operator +=(LPCTSTR lpsz
)
1073 ATLASSERT(lpsz
== NULL
|| _IsValidString(lpsz
));
1074 ConcatInPlace(SafeStrlen(lpsz
), lpsz
);
1078 friend CString __stdcall
operator +(const CString
& string1
, const CString
& string2
);
1079 friend CString __stdcall
operator +(const CString
& string
, TCHAR ch
);
1080 friend CString __stdcall
operator +(TCHAR ch
, const CString
& string
);
1082 friend CString __stdcall
operator +(const CString
& string
, char ch
);
1083 friend CString __stdcall
operator +(char ch
, const CString
& string
);
1085 friend CString __stdcall
operator +(const CString
& string
, LPCTSTR lpsz
);
1086 friend CString __stdcall
operator +(LPCTSTR lpsz
, const CString
& string
);
1088 // string comparison
1089 int Compare(LPCTSTR lpsz
) const // straight character (MBCS/Unicode aware)
1091 return _cstrcmp(m_pchData
, lpsz
);
1094 int CompareNoCase(LPCTSTR lpsz
) const // ignore case (MBCS/Unicode aware)
1096 return _cstrcmpi(m_pchData
, lpsz
);
1100 // CString::Collate is often slower than Compare but is MBSC/Unicode
1101 // aware as well as locale-sensitive with respect to sort order.
1102 int Collate(LPCTSTR lpsz
) const // NLS aware
1104 return _cstrcoll(m_pchData
, lpsz
);
1107 int CollateNoCase(LPCTSTR lpsz
) const // ignore case
1109 return _cstrcolli(m_pchData
, lpsz
);
1111 #endif // !_WIN32_WCE
1113 // simple sub-string extraction
1114 CString
Mid(int nFirst
, int nCount
) const
1116 // out-of-bounds requests return sensible things
1122 if (nFirst
+ nCount
> GetData()->nDataLength
)
1123 nCount
= GetData()->nDataLength
- nFirst
;
1124 if (nFirst
> GetData()->nDataLength
)
1128 AllocCopy(dest
, nCount
, nFirst
, 0);
1132 CString
Mid(int nFirst
) const
1134 return Mid(nFirst
, GetData()->nDataLength
- nFirst
);
1137 CString
Left(int nCount
) const
1141 else if (nCount
> GetData()->nDataLength
)
1142 nCount
= GetData()->nDataLength
;
1145 AllocCopy(dest
, nCount
, 0, 0);
1149 CString
Right(int nCount
) const
1153 else if (nCount
> GetData()->nDataLength
)
1154 nCount
= GetData()->nDataLength
;
1157 AllocCopy(dest
, nCount
, GetData()->nDataLength
-nCount
, 0);
1161 CString
SpanIncluding(LPCTSTR lpszCharSet
) const // strspn equivalent
1163 ATLASSERT(_IsValidString(lpszCharSet
));
1164 return Left(_cstrspn(m_pchData
, lpszCharSet
));
1167 CString
SpanExcluding(LPCTSTR lpszCharSet
) const // strcspn equivalent
1169 ATLASSERT(_IsValidString(lpszCharSet
));
1170 return Left(_cstrcspn(m_pchData
, lpszCharSet
));
1173 // upper/lower/reverse conversion
1177 CharUpper(m_pchData
);
1183 CharLower(m_pchData
);
1189 _cstrrev(m_pchData
);
1192 // trimming whitespace (either side)
1197 // find beginning of trailing spaces by starting at beginning (DBCS aware)
1198 LPTSTR lpsz
= m_pchData
;
1199 LPTSTR lpszLast
= NULL
;
1200 while (*lpsz
!= _T('\0'))
1202 if (_cstrisspace(*lpsz
))
1204 if (lpszLast
== NULL
)
1211 lpsz
= ::CharNext(lpsz
);
1214 if (lpszLast
!= NULL
)
1216 // truncate at trailing space start
1217 *lpszLast
= _T('\0');
1218 GetData()->nDataLength
= (int)(DWORD_PTR
)(lpszLast
- m_pchData
);
1226 // find first non-space character
1227 LPCTSTR lpsz
= m_pchData
;
1228 while (_cstrisspace(*lpsz
))
1229 lpsz
= ::CharNext(lpsz
);
1231 // fix up data and length
1232 int nDataLength
= GetData()->nDataLength
- (int)(DWORD_PTR
)(lpsz
- m_pchData
);
1233 SecureHelper::memmove_x(m_pchData
, (GetData()->nAllocLength
+ 1) * sizeof(TCHAR
), lpsz
, (nDataLength
+ 1) * sizeof(TCHAR
));
1234 GetData()->nDataLength
= nDataLength
;
1237 // remove continuous occurrences of chTarget starting from right
1238 void TrimRight(TCHAR chTarget
)
1240 // find beginning of trailing matches
1241 // by starting at beginning (DBCS aware)
1244 LPTSTR lpsz
= m_pchData
;
1245 LPTSTR lpszLast
= NULL
;
1247 while (*lpsz
!= _T('\0'))
1249 if (*lpsz
== chTarget
)
1251 if (lpszLast
== NULL
)
1256 lpsz
= ::CharNext(lpsz
);
1259 if (lpszLast
!= NULL
)
1261 // truncate at left-most matching character
1262 *lpszLast
= _T('\0');
1263 GetData()->nDataLength
= (int)(DWORD_PTR
)(lpszLast
- m_pchData
);
1267 // remove continuous occcurrences of characters in passed string, starting from right
1268 void TrimRight(LPCTSTR lpszTargetList
)
1270 // find beginning of trailing matches by starting at beginning (DBCS aware)
1273 LPTSTR lpsz
= m_pchData
;
1274 LPTSTR lpszLast
= NULL
;
1276 while (*lpsz
!= _T('\0'))
1278 TCHAR
* pNext
= ::CharNext(lpsz
);
1279 if(pNext
> lpsz
+ 1)
1281 if (_cstrchr_db(lpszTargetList
, *lpsz
, *(lpsz
+ 1)) != NULL
)
1283 if (lpszLast
== NULL
)
1293 if (_cstrchr(lpszTargetList
, *lpsz
) != NULL
)
1295 if (lpszLast
== NULL
)
1307 if (lpszLast
!= NULL
)
1309 // truncate at left-most matching character
1310 *lpszLast
= _T('\0');
1311 GetData()->nDataLength
= (int)(DWORD_PTR
)(lpszLast
- m_pchData
);
1315 // remove continuous occurrences of chTarget starting from left
1316 void TrimLeft(TCHAR chTarget
)
1318 // find first non-matching character
1321 LPCTSTR lpsz
= m_pchData
;
1323 while (chTarget
== *lpsz
)
1324 lpsz
= ::CharNext(lpsz
);
1326 if (lpsz
!= m_pchData
)
1328 // fix up data and length
1329 int nDataLength
= GetData()->nDataLength
- (int)(DWORD_PTR
)(lpsz
- m_pchData
);
1330 SecureHelper::memmove_x(m_pchData
, (GetData()->nAllocLength
+ 1) * sizeof(TCHAR
), lpsz
, (nDataLength
+ 1) * sizeof(TCHAR
));
1331 GetData()->nDataLength
= nDataLength
;
1335 // remove continuous occcurrences of characters in passed string, starting from left
1336 void TrimLeft(LPCTSTR lpszTargets
)
1338 // if we're not trimming anything, we're not doing any work
1339 if (SafeStrlen(lpszTargets
) == 0)
1343 LPCTSTR lpsz
= m_pchData
;
1345 while (*lpsz
!= _T('\0'))
1347 TCHAR
* pNext
= ::CharNext(lpsz
);
1348 if(pNext
> lpsz
+ 1)
1350 if (_cstrchr_db(lpszTargets
, *lpsz
, *(lpsz
+ 1)) == NULL
)
1355 if (_cstrchr(lpszTargets
, *lpsz
) == NULL
)
1361 if (lpsz
!= m_pchData
)
1363 // fix up data and length
1364 int nDataLength
= GetData()->nDataLength
- (int)(DWORD_PTR
)(lpsz
- m_pchData
);
1365 SecureHelper::memmove_x(m_pchData
, (GetData()->nAllocLength
+ 1) * sizeof(TCHAR
), lpsz
, (nDataLength
+ 1) * sizeof(TCHAR
));
1366 GetData()->nDataLength
= nDataLength
;
1370 // advanced manipulation
1371 // replace occurrences of chOld with chNew
1372 int Replace(TCHAR chOld
, TCHAR chNew
)
1376 // short-circuit the nop case
1379 // otherwise modify each character that matches in the string
1381 LPTSTR psz
= m_pchData
;
1382 LPTSTR pszEnd
= psz
+ GetData()->nDataLength
;
1383 while (psz
< pszEnd
)
1385 // replace instances of the specified character only
1391 psz
= ::CharNext(psz
);
1397 // replace occurrences of substring lpszOld with lpszNew;
1398 // empty lpszNew removes instances of lpszOld
1399 int Replace(LPCTSTR lpszOld
, LPCTSTR lpszNew
)
1401 // can't have empty or NULL lpszOld
1403 int nSourceLen
= SafeStrlen(lpszOld
);
1404 if (nSourceLen
== 0)
1406 int nReplacementLen
= SafeStrlen(lpszNew
);
1408 // loop once to figure out the size of the result string
1410 LPTSTR lpszStart
= m_pchData
;
1411 LPTSTR lpszEnd
= m_pchData
+ GetData()->nDataLength
;
1412 LPTSTR lpszTarget
= NULL
;
1413 while (lpszStart
< lpszEnd
)
1415 while ((lpszTarget
= (TCHAR
*)_cstrstr(lpszStart
, lpszOld
)) != NULL
)
1418 lpszStart
= lpszTarget
+ nSourceLen
;
1420 lpszStart
+= lstrlen(lpszStart
) + 1;
1423 // if any changes were made, make them
1428 // if the buffer is too small, just allocate a new buffer (slow but sure)
1429 int nOldLength
= GetData()->nDataLength
;
1430 int nNewLength
= nOldLength
+ (nReplacementLen
- nSourceLen
) * nCount
;
1431 if (GetData()->nAllocLength
< nNewLength
|| GetData()->nRefs
> 1)
1433 CStringData
* pOldData
= GetData();
1434 LPTSTR pstr
= m_pchData
;
1435 if(!AllocBuffer(nNewLength
))
1437 SecureHelper::memcpy_x(m_pchData
, (nNewLength
+ 1) * sizeof(TCHAR
), pstr
, pOldData
->nDataLength
* sizeof(TCHAR
));
1438 CString::Release(pOldData
);
1440 // else, we just do it in-place
1441 lpszStart
= m_pchData
;
1442 lpszEnd
= m_pchData
+ GetData()->nDataLength
;
1444 // loop again to actually do the work
1445 while (lpszStart
< lpszEnd
)
1447 while ((lpszTarget
= (TCHAR
*)_cstrstr(lpszStart
, lpszOld
)) != NULL
)
1449 int nBalance
= nOldLength
- ((int)(DWORD_PTR
)(lpszTarget
- m_pchData
) + nSourceLen
);
1450 int cchBuffLen
= GetData()->nAllocLength
- (int)(DWORD_PTR
)(lpszTarget
- m_pchData
);
1451 SecureHelper::memmove_x(lpszTarget
+ nReplacementLen
, (cchBuffLen
- nReplacementLen
+ 1) * sizeof(TCHAR
), lpszTarget
+ nSourceLen
, nBalance
* sizeof(TCHAR
));
1452 SecureHelper::memcpy_x(lpszTarget
, (cchBuffLen
+ 1) * sizeof(TCHAR
), lpszNew
, nReplacementLen
* sizeof(TCHAR
));
1453 lpszStart
= lpszTarget
+ nReplacementLen
;
1454 lpszStart
[nBalance
] = _T('\0');
1455 nOldLength
+= (nReplacementLen
- nSourceLen
);
1457 lpszStart
+= lstrlen(lpszStart
) + 1;
1459 ATLASSERT(m_pchData
[nNewLength
] == _T('\0'));
1460 GetData()->nDataLength
= nNewLength
;
1466 // remove occurrences of chRemove
1467 int Remove(TCHAR chRemove
)
1471 LPTSTR pstrSource
= m_pchData
;
1472 LPTSTR pstrDest
= m_pchData
;
1473 LPTSTR pstrEnd
= m_pchData
+ GetData()->nDataLength
;
1475 while (pstrSource
< pstrEnd
)
1477 if (*pstrSource
!= chRemove
)
1479 *pstrDest
= *pstrSource
;
1480 pstrDest
= ::CharNext(pstrDest
);
1482 pstrSource
= ::CharNext(pstrSource
);
1484 *pstrDest
= _T('\0');
1485 int nCount
= (int)(DWORD_PTR
)(pstrSource
- pstrDest
);
1486 GetData()->nDataLength
-= nCount
;
1491 // insert character at zero-based index; concatenates if index is past end of string
1492 int Insert(int nIndex
, TCHAR ch
)
1499 int nNewLength
= GetData()->nDataLength
;
1500 if (nIndex
> nNewLength
)
1501 nIndex
= nNewLength
;
1504 if (GetData()->nAllocLength
< nNewLength
)
1506 CStringData
* pOldData
= GetData();
1507 LPTSTR pstr
= m_pchData
;
1508 if(!AllocBuffer(nNewLength
))
1510 SecureHelper::memcpy_x(m_pchData
, (nNewLength
+ 1) * sizeof(TCHAR
), pstr
, (pOldData
->nDataLength
+ 1) * sizeof(TCHAR
));
1511 CString::Release(pOldData
);
1514 // move existing bytes down
1515 SecureHelper::memmove_x(m_pchData
+ nIndex
+ 1, (GetData()->nAllocLength
- nIndex
) * sizeof(TCHAR
), m_pchData
+ nIndex
, (nNewLength
- nIndex
) * sizeof(TCHAR
));
1516 m_pchData
[nIndex
] = ch
;
1517 GetData()->nDataLength
= nNewLength
;
1522 // insert substring at zero-based index; concatenates if index is past end of string
1523 int Insert(int nIndex
, LPCTSTR pstr
)
1528 int nInsertLength
= SafeStrlen(pstr
);
1529 int nNewLength
= GetData()->nDataLength
;
1530 if (nInsertLength
> 0)
1533 if (nIndex
> nNewLength
)
1534 nIndex
= nNewLength
;
1535 nNewLength
+= nInsertLength
;
1537 if (GetData()->nAllocLength
< nNewLength
)
1539 CStringData
* pOldData
= GetData();
1540 LPTSTR pstr
= m_pchData
;
1541 if(!AllocBuffer(nNewLength
))
1543 SecureHelper::memcpy_x(m_pchData
, (nNewLength
+ 1) * sizeof(TCHAR
), pstr
, (pOldData
->nDataLength
+ 1) * sizeof(TCHAR
));
1544 CString::Release(pOldData
);
1547 // move existing bytes down
1548 SecureHelper::memmove_x(m_pchData
+ nIndex
+ nInsertLength
, (GetData()->nAllocLength
+ 1 - nIndex
- nInsertLength
) * sizeof(TCHAR
), m_pchData
+ nIndex
, (nNewLength
- nIndex
- nInsertLength
+ 1) * sizeof(TCHAR
));
1549 SecureHelper::memcpy_x(m_pchData
+ nIndex
, (GetData()->nAllocLength
+ 1 - nIndex
) * sizeof(TCHAR
), pstr
, nInsertLength
* sizeof(TCHAR
));
1550 GetData()->nDataLength
= nNewLength
;
1556 // delete nCount characters starting at zero-based index
1557 int Delete(int nIndex
, int nCount
= 1)
1561 int nLength
= GetData()->nDataLength
;
1562 if (nCount
> 0 && nIndex
< nLength
)
1564 if((nIndex
+ nCount
) > nLength
)
1565 nCount
= nLength
- nIndex
;
1567 int nBytesToCopy
= nLength
- (nIndex
+ nCount
) + 1;
1569 SecureHelper::memmove_x(m_pchData
+ nIndex
, (GetData()->nAllocLength
+ 1 - nIndex
) * sizeof(TCHAR
), m_pchData
+ nIndex
+ nCount
, nBytesToCopy
* sizeof(TCHAR
));
1571 GetData()->nDataLength
= nLength
;
1577 // searching (return starting index, or -1 if not found)
1578 // look for a single character match
1579 int Find(TCHAR ch
) const // like "C" strchr
1584 int ReverseFind(TCHAR ch
) const
1586 // find last single character
1587 LPCTSTR lpsz
= _cstrrchr(m_pchData
, (_TUCHAR
)ch
);
1589 // return -1 if not found, distance from beginning otherwise
1590 return (lpsz
== NULL
) ? -1 : (int)(lpsz
- m_pchData
);
1593 int Find(TCHAR ch
, int nStart
) const // starting at index
1595 int nLength
= GetData()->nDataLength
;
1596 if (nStart
< 0 || nStart
>= nLength
)
1599 // find first single character
1600 LPCTSTR lpsz
= _cstrchr(m_pchData
+ nStart
, (_TUCHAR
)ch
);
1602 // return -1 if not found and index otherwise
1603 return (lpsz
== NULL
) ? -1 : (int)(lpsz
- m_pchData
);
1606 int FindOneOf(LPCTSTR lpszCharSet
) const
1608 ATLASSERT(_IsValidString(lpszCharSet
));
1609 LPCTSTR lpsz
= _cstrpbrk(m_pchData
, lpszCharSet
);
1610 return (lpsz
== NULL
) ? -1 : (int)(lpsz
- m_pchData
);
1613 // look for a specific sub-string
1614 // find a sub-string (like strstr)
1615 int Find(LPCTSTR lpszSub
) const // like "C" strstr
1617 return Find(lpszSub
, 0);
1620 int Find(LPCTSTR lpszSub
, int nStart
) const // starting at index
1622 ATLASSERT(_IsValidString(lpszSub
));
1624 int nLength
= GetData()->nDataLength
;
1625 if (nStart
< 0 || nStart
> nLength
)
1628 // find first matching substring
1629 LPCTSTR lpsz
= _cstrstr(m_pchData
+ nStart
, lpszSub
);
1631 // return -1 for not found, distance from beginning otherwise
1632 return (lpsz
== NULL
) ? -1 : (int)(lpsz
- m_pchData
);
1635 // Concatentation for non strings
1636 CString
& Append(int n
)
1638 const int cchBuff
= 12;
1639 TCHAR szBuffer
[cchBuff
] = { 0 };
1640 SecureHelper::wsprintf_x(szBuffer
, cchBuff
, _T("%d"), n
);
1641 ConcatInPlace(SafeStrlen(szBuffer
), szBuffer
);
1645 // simple formatting
1646 // formatting (using wsprintf style formatting)
1647 BOOL __cdecl
Format(LPCTSTR lpszFormat
, ...)
1649 ATLASSERT(_IsValidString(lpszFormat
));
1652 va_start(argList
, lpszFormat
);
1653 BOOL bRet
= FormatV(lpszFormat
, argList
);
1658 BOOL __cdecl
Format(UINT nFormatID
, ...)
1661 BOOL bRet
= strFormat
.LoadString(nFormatID
);
1662 ATLASSERT(bRet
!= 0);
1665 va_start(argList
, nFormatID
);
1666 bRet
= FormatV(strFormat
, argList
);
1671 BOOL
FormatV(LPCTSTR lpszFormat
, va_list argList
)
1673 ATLASSERT(_IsValidString(lpszFormat
));
1675 enum _FormatModifiers
1677 FORCE_ANSI
= 0x10000,
1678 FORCE_UNICODE
= 0x20000,
1679 FORCE_INT64
= 0x40000
1682 va_list argListSave
= argList
;
1684 // make a guess at the maximum length of the resulting string
1686 for (LPCTSTR lpsz
= lpszFormat
; *lpsz
!= _T('\0'); lpsz
= ::CharNext(lpsz
))
1688 // handle '%' character, but watch out for '%%'
1689 if (*lpsz
!= _T('%') || *(lpsz
= ::CharNext(lpsz
)) == _T('%'))
1691 nMaxLen
+= (int)(::CharNext(lpsz
) - lpsz
);
1697 // handle '%' character with format
1699 for (; *lpsz
!= _T('\0'); lpsz
= ::CharNext(lpsz
))
1701 // check for valid flags
1702 if (*lpsz
== _T('#'))
1703 nMaxLen
+= 2; // for '0x'
1704 else if (*lpsz
== _T('*'))
1705 nWidth
= va_arg(argList
, int);
1706 else if (*lpsz
== _T('-') || *lpsz
== _T('+') || *lpsz
== _T('0') || *lpsz
== _T(' '))
1708 else // hit non-flag character
1711 // get width and skip it
1714 // width indicated by
1715 nWidth
= _cstrtoi(lpsz
);
1716 for (; *lpsz
!= _T('\0') && _cstrisdigit(*lpsz
); lpsz
= ::CharNext(lpsz
))
1719 ATLASSERT(nWidth
>= 0);
1722 if (*lpsz
== _T('.'))
1724 // skip past '.' separator (width.precision)
1725 lpsz
= ::CharNext(lpsz
);
1727 // get precision and skip it
1728 if (*lpsz
== _T('*'))
1730 nPrecision
= va_arg(argList
, int);
1731 lpsz
= ::CharNext(lpsz
);
1735 nPrecision
= _cstrtoi(lpsz
);
1736 for (; *lpsz
!= _T('\0') && _cstrisdigit(*lpsz
); lpsz
= ::CharNext(lpsz
))
1739 ATLASSERT(nPrecision
>= 0);
1742 // should be on type modifier or specifier
1744 if(lpsz
[0] == _T('I') && lpsz
[1] == _T('6') && lpsz
[2] == _T('4'))
1747 nModifier
= FORCE_INT64
;
1753 // modifiers that affect size
1755 nModifier
= FORCE_ANSI
;
1756 lpsz
= ::CharNext(lpsz
);
1759 nModifier
= FORCE_UNICODE
;
1760 lpsz
= ::CharNext(lpsz
);
1763 // modifiers that do not affect size
1767 lpsz
= ::CharNext(lpsz
);
1772 // now should be on specifier
1773 switch (*lpsz
| nModifier
)
1775 // single characters
1779 va_arg(argList
, TCHAR
);
1781 case _T('c') | FORCE_ANSI
:
1782 case _T('C') | FORCE_ANSI
:
1784 va_arg(argList
, char);
1786 case _T('c') | FORCE_UNICODE
:
1787 case _T('C') | FORCE_UNICODE
:
1789 va_arg(argList
, WCHAR
);
1795 LPCTSTR pstrNextArg
= va_arg(argList
, LPCTSTR
);
1796 if (pstrNextArg
== NULL
)
1798 nItemLen
= 6; // "(null)"
1802 nItemLen
= lstrlen(pstrNextArg
);
1803 nItemLen
= __max(1, nItemLen
);
1811 LPWSTR pstrNextArg
= va_arg(argList
, LPWSTR
);
1812 if (pstrNextArg
== NULL
)
1814 nItemLen
= 6; // "(null)"
1818 nItemLen
= (int)wcslen(pstrNextArg
);
1819 nItemLen
= __max(1, nItemLen
);
1822 LPCSTR pstrNextArg
= va_arg(argList
, LPCSTR
);
1823 if (pstrNextArg
== NULL
)
1825 nItemLen
= 6; // "(null)"
1829 #if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800)
1830 nItemLen
= ATL::lstrlenA(pstrNextArg
);
1832 nItemLen
= lstrlenA(pstrNextArg
);
1834 nItemLen
= __max(1, nItemLen
);
1840 case _T('s') | FORCE_ANSI
:
1841 case _T('S') | FORCE_ANSI
:
1843 LPCSTR pstrNextArg
= va_arg(argList
, LPCSTR
);
1844 if (pstrNextArg
== NULL
)
1846 nItemLen
= 6; // "(null)"
1850 #if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800)
1851 nItemLen
= ATL::lstrlenA(pstrNextArg
);
1853 nItemLen
= lstrlenA(pstrNextArg
);
1855 nItemLen
= __max(1, nItemLen
);
1860 case _T('s') | FORCE_UNICODE
:
1861 case _T('S') | FORCE_UNICODE
:
1863 LPWSTR pstrNextArg
= va_arg(argList
, LPWSTR
);
1864 if (pstrNextArg
== NULL
)
1866 nItemLen
= 6; // "(null)"
1870 nItemLen
= (int)wcslen(pstrNextArg
);
1871 nItemLen
= __max(1, nItemLen
);
1877 // adjust nItemLen for strings
1880 nItemLen
= __max(nItemLen
, nWidth
);
1881 if (nPrecision
!= 0)
1882 nItemLen
= __min(nItemLen
, nPrecision
);
1895 if (nModifier
& FORCE_INT64
)
1896 va_arg(argList
, __int64
);
1898 va_arg(argList
, int);
1900 nItemLen
= __max(nItemLen
, nWidth
+ nPrecision
);
1903 #ifndef _ATL_USE_CSTRING_FLOAT
1909 ATLASSERT(!"Floating point (%%e, %%E, %%f, %%g, and %%G) is not supported by the WTL::CString class.");
1911 ::OutputDebugString(_T("Floating point (%%e, %%f, %%g, and %%G) is not supported by the WTL::CString class."));
1914 #else // CE specific
1916 #endif // _WIN32_WCE
1919 #else // _ATL_USE_CSTRING_FLOAT
1924 va_arg(argList
, double);
1926 nItemLen
= __max(nItemLen
, nWidth
+ nPrecision
);
1930 double f
= va_arg(argList
, double);
1931 // 312 == strlen("-1+(309 zeroes).")
1932 // 309 zeroes == max precision of a double
1933 // 6 == adjustment in case precision is not specified,
1934 // which means that the precision defaults to 6
1935 int cchLen
= __max(nWidth
, 312 + nPrecision
+ 6);
1936 CTempBuffer
<TCHAR
, _WTL_STACK_ALLOC_THRESHOLD
> buff
;
1937 LPTSTR pszTemp
= buff
.Allocate(cchLen
);
1940 SecureHelper::sprintf_x(pszTemp
, cchLen
, _T("%*.*f"), nWidth
, nPrecision
+ 6, f
);
1941 nItemLen
= (int)_tcslen(pszTemp
);
1949 #endif // _ATL_USE_CSTRING_FLOAT
1952 va_arg(argList
, void*);
1954 nItemLen
= __max(nItemLen
, nWidth
+ nPrecision
);
1959 va_arg(argList
, int*);
1963 ATLASSERT(FALSE
); // unknown formatting option
1967 // adjust nMaxLen for output nItemLen
1968 nMaxLen
+= nItemLen
;
1971 if(GetBuffer(nMaxLen
) == NULL
)
1973 #ifndef _ATL_USE_CSTRING_FLOAT
1974 int nRet
= SecureHelper::wvsprintf_x(m_pchData
, GetAllocLength() + 1, lpszFormat
, argListSave
);
1975 #else // _ATL_USE_CSTRING_FLOAT
1976 int nRet
= SecureHelper::vsprintf_x(m_pchData
, GetAllocLength() + 1, lpszFormat
, argListSave
);
1977 #endif // _ATL_USE_CSTRING_FLOAT
1979 ATLASSERT(nRet
<= GetAllocLength());
1982 va_end(argListSave
);
1986 // formatting for localization (uses FormatMessage API)
1987 // formatting (using FormatMessage style formatting)
1988 BOOL __cdecl
FormatMessage(LPCTSTR lpszFormat
, ...)
1990 // format message into temporary buffer lpszTemp
1992 va_start(argList
, lpszFormat
);
1996 if (::FormatMessage(FORMAT_MESSAGE_FROM_STRING
| FORMAT_MESSAGE_ALLOCATE_BUFFER
,
1997 lpszFormat
, 0, 0, (LPTSTR
)&lpszTemp
, 0, &argList
) == 0 || lpszTemp
== NULL
)
2000 // assign lpszTemp into the resulting string and free the temporary
2002 LocalFree(lpszTemp
);
2007 BOOL __cdecl
FormatMessage(UINT nFormatID
, ...)
2009 // get format string from string table
2011 BOOL bRetTmp
= strFormat
.LoadString(nFormatID
);
2013 ATLASSERT(bRetTmp
!= 0);
2015 // format message into temporary buffer lpszTemp
2017 va_start(argList
, nFormatID
);
2021 if (::FormatMessage(FORMAT_MESSAGE_FROM_STRING
| FORMAT_MESSAGE_ALLOCATE_BUFFER
,
2022 strFormat
, 0, 0, (LPTSTR
)&lpszTemp
, 0, &argList
) == 0 || lpszTemp
== NULL
)
2025 // assign lpszTemp into the resulting string and free lpszTemp
2027 LocalFree(lpszTemp
);
2033 BOOL
LoadString(UINT nID
) // load from string resource (255 chars max.)
2036 const int CHAR_FUDGE
= 1; // one TCHAR unused is good enough
2038 const int CHAR_FUDGE
= 2; // two BYTES unused for case of DBC last char
2041 // try fixed buffer first (to avoid wasting space in the heap)
2043 int nCount
= sizeof(szTemp
) / sizeof(szTemp
[0]);
2044 int nLen
= _LoadString(nID
, szTemp
, nCount
);
2045 if (nCount
- nLen
> CHAR_FUDGE
)
2051 // try buffer size of 512, then larger size until entire string is retrieved
2056 LPTSTR lpstr
= GetBuffer(nSize
- 1);
2062 nLen
= _LoadString(nID
, lpstr
, nSize
);
2063 } while (nSize
- nLen
<= CHAR_FUDGE
);
2070 // ANSI <-> OEM support (convert string in place)
2074 ::AnsiToOem(m_pchData
, m_pchData
);
2080 ::OemToAnsi(m_pchData
, m_pchData
);
2085 // OLE BSTR support (use for OLE automation)
2086 BSTR
AllocSysString() const
2088 #if defined(_UNICODE) || defined(OLE2ANSI)
2089 BSTR bstr
= ::SysAllocStringLen(m_pchData
, GetData()->nDataLength
);
2091 int nLen
= MultiByteToWideChar(CP_ACP
, 0, m_pchData
,
2092 GetData()->nDataLength
, NULL
, NULL
);
2093 BSTR bstr
= ::SysAllocStringLen(NULL
, nLen
);
2095 MultiByteToWideChar(CP_ACP
, 0, m_pchData
, GetData()->nDataLength
, bstr
, nLen
);
2100 BSTR
SetSysString(BSTR
* pbstr
) const
2102 #if defined(_UNICODE) || defined(OLE2ANSI)
2103 ::SysReAllocStringLen(pbstr
, m_pchData
, GetData()->nDataLength
);
2105 int nLen
= MultiByteToWideChar(CP_ACP
, 0, m_pchData
,
2106 GetData()->nDataLength
, NULL
, NULL
);
2107 if(::SysReAllocStringLen(pbstr
, NULL
, nLen
))
2108 MultiByteToWideChar(CP_ACP
, 0, m_pchData
, GetData()->nDataLength
, *pbstr
, nLen
);
2110 ATLASSERT(*pbstr
!= NULL
);
2113 #endif // !_ATL_NO_COM
2115 // Access to string implementation buffer as "C" character array
2116 LPTSTR
GetBuffer(int nMinBufLength
)
2118 ATLASSERT(nMinBufLength
>= 0);
2120 if (GetData()->nRefs
> 1 || nMinBufLength
> GetData()->nAllocLength
)
2122 // we have to grow the buffer
2123 CStringData
* pOldData
= GetData();
2124 int nOldLen
= GetData()->nDataLength
; // AllocBuffer will tromp it
2125 if (nMinBufLength
< nOldLen
)
2126 nMinBufLength
= nOldLen
;
2128 if(!AllocBuffer(nMinBufLength
))
2131 SecureHelper::memcpy_x(m_pchData
, (nMinBufLength
+ 1) * sizeof(TCHAR
), pOldData
->data(), (nOldLen
+ 1) * sizeof(TCHAR
));
2132 GetData()->nDataLength
= nOldLen
;
2133 CString::Release(pOldData
);
2135 ATLASSERT(GetData()->nRefs
<= 1);
2137 // return a pointer to the character storage for this string
2138 ATLASSERT(m_pchData
!= NULL
);
2142 void ReleaseBuffer(int nNewLength
= -1)
2144 CopyBeforeWrite(); // just in case GetBuffer was not called
2146 if (nNewLength
== -1)
2147 nNewLength
= lstrlen(m_pchData
); // zero terminated
2149 ATLASSERT(nNewLength
<= GetData()->nAllocLength
);
2150 GetData()->nDataLength
= nNewLength
;
2151 m_pchData
[nNewLength
] = _T('\0');
2154 LPTSTR
GetBufferSetLength(int nNewLength
)
2156 ATLASSERT(nNewLength
>= 0);
2158 if(GetBuffer(nNewLength
) == NULL
)
2161 GetData()->nDataLength
= nNewLength
;
2162 m_pchData
[nNewLength
] = _T('\0');
2168 ATLASSERT(GetData()->nDataLength
<= GetData()->nAllocLength
);
2169 if (GetData()->nDataLength
!= GetData()->nAllocLength
)
2171 CStringData
* pOldData
= GetData();
2172 if(AllocBuffer(GetData()->nDataLength
))
2174 SecureHelper::memcpy_x(m_pchData
, (GetData()->nAllocLength
+ 1) * sizeof(TCHAR
), pOldData
->data(), pOldData
->nDataLength
* sizeof(TCHAR
));
2175 ATLASSERT(m_pchData
[GetData()->nDataLength
] == _T('\0'));
2176 CString::Release(pOldData
);
2179 ATLASSERT(GetData() != NULL
);
2182 // Use LockBuffer/UnlockBuffer to turn refcounting off
2185 LPTSTR lpsz
= GetBuffer(0);
2187 GetData()->nRefs
= -1;
2193 ATLASSERT(GetData()->nRefs
== -1);
2194 if (GetData() != _atltmpDataNil
)
2195 GetData()->nRefs
= 1;
2200 ~CString() // free any attached data
2202 if (GetData() != _atltmpDataNil
)
2204 if (InterlockedDecrement(&GetData()->nRefs
) <= 0)
2205 delete[] (BYTE
*)GetData();
2209 int GetAllocLength() const
2211 return GetData()->nAllocLength
;
2214 static BOOL __stdcall
_IsValidString(LPCTSTR lpsz
, int /*nLength*/ = -1)
2216 return (lpsz
!= NULL
) ? TRUE
: FALSE
;
2220 LPTSTR m_pchData
; // pointer to ref counted string data
2222 // implementation helpers
2223 CStringData
* GetData() const
2225 ATLASSERT(m_pchData
!= NULL
);
2226 return ((CStringData
*)m_pchData
) - 1;
2231 m_pchData
= _GetEmptyString().m_pchData
;
2234 BOOL
AllocCopy(CString
& dest
, int nCopyLen
, int nCopyIndex
, int nExtraLen
) const
2236 // will clone the data attached to this string
2237 // allocating 'nExtraLen' characters
2238 // Places results in uninitialized string 'dest'
2239 // Will copy the part or all of original data to start of new string
2242 int nNewLen
= nCopyLen
+ nExtraLen
;
2248 else if(nNewLen
>= nCopyLen
)
2250 if(dest
.AllocBuffer(nNewLen
))
2252 SecureHelper::memcpy_x(dest
.m_pchData
, (nNewLen
+ 1) * sizeof(TCHAR
), m_pchData
+ nCopyIndex
, nCopyLen
* sizeof(TCHAR
));
2260 // always allocate one extra character for '\0' termination
2261 // assumes [optimistically] that data length will equal allocation length
2262 BOOL
AllocBuffer(int nLen
)
2264 ATLASSERT(nLen
>= 0);
2265 ATLASSERT(nLen
<= INT_MAX
- 1); // max size (enough room for 1 extra)
2273 CStringData
* pData
= NULL
;
2274 ATLTRY(pData
= (CStringData
*)new BYTE
[sizeof(CStringData
) + (nLen
+ 1) * sizeof(TCHAR
)]);
2279 pData
->data()[nLen
] = _T('\0');
2280 pData
->nDataLength
= nLen
;
2281 pData
->nAllocLength
= nLen
;
2282 m_pchData
= pData
->data();
2288 // Assignment operators
2289 // All assign a new value to the string
2290 // (a) first see if the buffer is big enough
2291 // (b) if enough room, copy on top of old buffer, set size and type
2292 // (c) otherwise free old string data, and create a new one
2294 // All routines return the new string (but as a 'const CString&' so that
2295 // assigning it again will cause a copy, eg: s1 = s2 = "hi there".
2297 void AssignCopy(int nSrcLen
, LPCTSTR lpszSrcData
)
2299 if(AllocBeforeWrite(nSrcLen
))
2301 SecureHelper::memcpy_x(m_pchData
, (nSrcLen
+ 1) * sizeof(TCHAR
), lpszSrcData
, nSrcLen
* sizeof(TCHAR
));
2302 GetData()->nDataLength
= nSrcLen
;
2303 m_pchData
[nSrcLen
] = _T('\0');
2308 // NOTE: "operator +" is done as friend functions for simplicity
2309 // There are three variants:
2310 // CString + CString
2311 // and for ? = TCHAR, LPCTSTR
2314 BOOL
ConcatCopy(int nSrc1Len
, LPCTSTR lpszSrc1Data
, int nSrc2Len
, LPCTSTR lpszSrc2Data
)
2316 // -- master concatenation routine
2317 // Concatenate two sources
2318 // -- assume that 'this' is a new CString object
2321 int nNewLen
= nSrc1Len
+ nSrc2Len
;
2322 if(nNewLen
< nSrc1Len
|| nNewLen
< nSrc2Len
)
2326 else if(nNewLen
!= 0)
2328 bRet
= AllocBuffer(nNewLen
);
2331 SecureHelper::memcpy_x(m_pchData
, (nNewLen
+ 1) * sizeof(TCHAR
), lpszSrc1Data
, nSrc1Len
* sizeof(TCHAR
));
2332 SecureHelper::memcpy_x(m_pchData
+ nSrc1Len
, (nNewLen
+ 1 - nSrc1Len
) * sizeof(TCHAR
), lpszSrc2Data
, nSrc2Len
* sizeof(TCHAR
));
2338 void ConcatInPlace(int nSrcLen
, LPCTSTR lpszSrcData
)
2340 // -- the main routine for += operators
2342 // concatenating an empty string is a no-op!
2346 // if the buffer is too small, or we have a width mis-match, just
2347 // allocate a new buffer (slow but sure)
2348 if (GetData()->nRefs
> 1 || GetData()->nDataLength
+ nSrcLen
> GetData()->nAllocLength
)
2350 // we have to grow the buffer, use the ConcatCopy routine
2351 CStringData
* pOldData
= GetData();
2352 if (ConcatCopy(GetData()->nDataLength
, m_pchData
, nSrcLen
, lpszSrcData
))
2354 ATLASSERT(pOldData
!= NULL
);
2355 CString::Release(pOldData
);
2360 // fast concatenation when buffer big enough
2361 SecureHelper::memcpy_x(m_pchData
+ GetData()->nDataLength
, (GetData()->nAllocLength
+ 1) * sizeof(TCHAR
), lpszSrcData
, nSrcLen
* sizeof(TCHAR
));
2362 GetData()->nDataLength
+= nSrcLen
;
2363 ATLASSERT(GetData()->nDataLength
<= GetData()->nAllocLength
);
2364 m_pchData
[GetData()->nDataLength
] = _T('\0');
2368 void CopyBeforeWrite()
2370 if (GetData()->nRefs
> 1)
2372 CStringData
* pData
= GetData();
2374 if(AllocBuffer(pData
->nDataLength
))
2375 SecureHelper::memcpy_x(m_pchData
, (GetData()->nAllocLength
+ 1) * sizeof(TCHAR
), pData
->data(), (pData
->nDataLength
+ 1) * sizeof(TCHAR
));
2377 ATLASSERT(GetData()->nRefs
<= 1);
2380 BOOL
AllocBeforeWrite(int nLen
)
2383 if (GetData()->nRefs
> 1 || nLen
> GetData()->nAllocLength
)
2386 bRet
= AllocBuffer(nLen
);
2388 ATLASSERT(GetData()->nRefs
<= 1);
2394 if (GetData() != _atltmpDataNil
)
2396 ATLASSERT(GetData()->nRefs
!= 0);
2397 if (InterlockedDecrement(&GetData()->nRefs
) <= 0)
2398 delete[] (BYTE
*)GetData();
2403 static void PASCAL
Release(CStringData
* pData
)
2405 if (pData
!= _atltmpDataNil
)
2407 ATLASSERT(pData
->nRefs
!= 0);
2408 if (InterlockedDecrement(&pData
->nRefs
) <= 0)
2409 delete[] (BYTE
*)pData
;
2413 static int PASCAL
SafeStrlen(LPCTSTR lpsz
)
2415 return (lpsz
== NULL
) ? 0 : lstrlen(lpsz
);
2418 static int __stdcall
_LoadString(UINT nID
, LPTSTR lpszBuf
, UINT nMaxBuf
)
2421 // LoadString without annoying warning from the Debug kernel if the
2422 // segment containing the string is not present
2423 if (::FindResource(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE((nID
>> 4) + 1), RT_STRING
) == NULL
)
2425 lpszBuf
[0] = _T('\0');
2426 return 0; // not found
2430 int nLen
= ::LoadString(ModuleHelper::GetResourceInstance(), nID
, lpszBuf
, nMaxBuf
);
2432 lpszBuf
[0] = _T('\0');
2437 static const CString
& __stdcall
_GetEmptyString()
2439 return *(CString
*)&_atltmpPchNil
;
2442 // CString conversion helpers
2443 static int __cdecl
_wcstombsz(char* mbstr
, const wchar_t* wcstr
, size_t count
)
2445 if (count
== 0 && mbstr
!= NULL
)
2448 int result
= ::WideCharToMultiByte(CP_ACP
, 0, wcstr
, -1, mbstr
, (int)count
, NULL
, NULL
);
2449 ATLASSERT(mbstr
== NULL
|| result
<= (int)count
);
2451 mbstr
[result
- 1] = 0;
2455 static int __cdecl
_mbstowcsz(wchar_t* wcstr
, const char* mbstr
, size_t count
)
2457 if (count
== 0 && wcstr
!= NULL
)
2460 int result
= ::MultiByteToWideChar(CP_ACP
, 0, mbstr
, -1, wcstr
, (int)count
);
2461 ATLASSERT(wcstr
== NULL
|| result
<= (int)count
);
2463 wcstr
[result
- 1] = 0;
2467 // Helpers to avoid CRT startup code
2469 static const TCHAR
* _cstrchr(const TCHAR
* p
, TCHAR ch
)
2471 // strchr for '\0' should succeed
2478 return (*p
== ch
) ? p
: NULL
;
2481 static const TCHAR
* _cstrrchr(const TCHAR
* p
, TCHAR ch
)
2483 const TCHAR
* lpsz
= NULL
;
2493 static TCHAR
* _cstrrev(TCHAR
* pStr
)
2495 // optimize NULL, zero-length, and single-char case
2496 if ((pStr
== NULL
) || (pStr
[0] == _T('\0')) || (pStr
[1] == _T('\0')))
2503 TCHAR
* pNext
= ::CharNext(p
);
2506 char p1
= *(char*)p
;
2507 *(char*)p
= *(char*)(p
+ 1);
2508 *(char*)(p
+ 1) = p1
;
2527 static const TCHAR
* _cstrstr(const TCHAR
* pStr
, const TCHAR
* pCharSet
)
2529 int nLen
= lstrlen(pCharSet
);
2531 return (TCHAR
*)pStr
;
2533 const TCHAR
* pRet
= NULL
;
2534 const TCHAR
* pCur
= pStr
;
2535 while((pCur
= _cstrchr(pCur
, *pCharSet
)) != NULL
)
2537 if(memcmp(pCur
, pCharSet
, nLen
* sizeof(TCHAR
)) == 0)
2542 pCur
= ::CharNext(pCur
);
2547 static int _cstrspn(const TCHAR
* pStr
, const TCHAR
* pCharSet
)
2550 const TCHAR
* p
= pStr
;
2553 const TCHAR
* pNext
= ::CharNext(p
);
2556 if(_cstrchr_db(pCharSet
, *p
, *(p
+ 1)) == NULL
)
2562 if(_cstrchr(pCharSet
, *p
) == NULL
)
2571 static int _cstrcspn(const TCHAR
* pStr
, const TCHAR
* pCharSet
)
2574 TCHAR
* p
= (TCHAR
*)pStr
;
2577 TCHAR
* pNext
= ::CharNext(p
);
2580 if(_cstrchr_db(pCharSet
, *p
, *(p
+ 1)) != NULL
)
2586 if(_cstrchr(pCharSet
, *p
) != NULL
)
2595 static const TCHAR
* _cstrpbrk(const TCHAR
* p
, const TCHAR
* lpszCharSet
)
2597 int n
= _cstrcspn(p
, lpszCharSet
);
2598 return (p
[n
] != 0) ? &p
[n
] : NULL
;
2601 static int _cstrisdigit(TCHAR ch
)
2604 GetStringTypeEx(GetThreadLocale(), CT_CTYPE1
, &ch
, 1, &type
);
2605 return (type
& C1_DIGIT
) == C1_DIGIT
;
2608 static int _cstrisspace(TCHAR ch
)
2611 GetStringTypeEx(GetThreadLocale(), CT_CTYPE1
, &ch
, 1, &type
);
2612 return (type
& C1_SPACE
) == C1_SPACE
;
2615 static int _cstrcmp(const TCHAR
* pstrOne
, const TCHAR
* pstrOther
)
2617 return lstrcmp(pstrOne
, pstrOther
);
2620 static int _cstrcmpi(const TCHAR
* pstrOne
, const TCHAR
* pstrOther
)
2622 return lstrcmpi(pstrOne
, pstrOther
);
2625 static int _cstrcoll(const TCHAR
* pstrOne
, const TCHAR
* pstrOther
)
2627 int nRet
= CompareString(GetThreadLocale(), 0, pstrOne
, -1, pstrOther
, -1);
2628 ATLASSERT(nRet
!= 0);
2629 return nRet
- 2; // convert to strcmp convention
2632 static int _cstrcolli(const TCHAR
* pstrOne
, const TCHAR
* pstrOther
)
2634 int nRet
= CompareString(GetThreadLocale(), NORM_IGNORECASE
, pstrOne
, -1, pstrOther
, -1);
2635 ATLASSERT(nRet
!= 0);
2636 return nRet
- 2; // convert to strcmp convention
2639 static int _cstrtoi(const TCHAR
* nptr
)
2641 int c
; // current char
2642 int total
; // current total
2643 int sign
; // if '-', then negative, otherwise positive
2645 while (_cstrisspace(*nptr
))
2648 c
= (int)(_TUCHAR
)*nptr
++;
2649 sign
= c
; // save sign indication
2650 if (c
== _T('-') || c
== _T('+'))
2651 c
= (int)(_TUCHAR
)*nptr
++; // skip sign
2655 while (_cstrisdigit((TCHAR
)c
))
2657 total
= 10 * total
+ (c
- '0'); // accumulate digit
2658 c
= (int)(_TUCHAR
)*nptr
++; // get next char
2664 return total
; // return result, negated if necessary
2666 #else // !_ATL_MIN_CRT
2667 static const TCHAR
* _cstrchr(const TCHAR
* p
, TCHAR ch
)
2669 return _tcschr(p
, ch
);
2672 static const TCHAR
* _cstrrchr(const TCHAR
* p
, TCHAR ch
)
2674 return _tcsrchr(p
, ch
);
2677 static TCHAR
* _cstrrev(TCHAR
* pStr
)
2679 return _tcsrev(pStr
);
2682 static const TCHAR
* _cstrstr(const TCHAR
* pStr
, const TCHAR
* pCharSet
)
2684 return _tcsstr(pStr
, pCharSet
);
2687 static int _cstrspn(const TCHAR
* pStr
, const TCHAR
* pCharSet
)
2689 return (int)_tcsspn(pStr
, pCharSet
);
2692 static int _cstrcspn(const TCHAR
* pStr
, const TCHAR
* pCharSet
)
2694 return (int)_tcscspn(pStr
, pCharSet
);
2697 static const TCHAR
* _cstrpbrk(const TCHAR
* p
, const TCHAR
* lpszCharSet
)
2699 return _tcspbrk(p
, lpszCharSet
);
2702 static int _cstrisdigit(TCHAR ch
)
2704 return _istdigit(ch
);
2707 static int _cstrisspace(TCHAR ch
)
2709 return _istspace((_TUCHAR
)ch
);
2712 static int _cstrcmp(const TCHAR
* pstrOne
, const TCHAR
* pstrOther
)
2714 return _tcscmp(pstrOne
, pstrOther
);
2717 static int _cstrcmpi(const TCHAR
* pstrOne
, const TCHAR
* pstrOther
)
2719 return _tcsicmp(pstrOne
, pstrOther
);
2723 static int _cstrcoll(const TCHAR
* pstrOne
, const TCHAR
* pstrOther
)
2725 return _tcscoll(pstrOne
, pstrOther
);
2728 static int _cstrcolli(const TCHAR
* pstrOne
, const TCHAR
* pstrOther
)
2730 return _tcsicoll(pstrOne
, pstrOther
);
2732 #endif // !_WIN32_WCE
2734 static int _cstrtoi(const TCHAR
* nptr
)
2738 #endif // !_ATL_MIN_CRT
2740 static const TCHAR
* _cstrchr_db(const TCHAR
* p
, TCHAR ch1
, TCHAR ch2
)
2742 const TCHAR
* lpsz
= NULL
;
2745 if (*p
== ch1
&& *(p
+ 1) == ch2
)
2759 inline bool __stdcall
operator ==(const CString
& s1
, const CString
& s2
)
2760 { return s1
.Compare(s2
) == 0; }
2762 inline bool __stdcall
operator ==(const CString
& s1
, LPCTSTR s2
)
2763 { return s1
.Compare(s2
) == 0; }
2765 inline bool __stdcall
operator ==(LPCTSTR s1
, const CString
& s2
)
2766 { return s2
.Compare(s1
) == 0; }
2768 inline bool __stdcall
operator !=(const CString
& s1
, const CString
& s2
)
2769 { return s1
.Compare(s2
) != 0; }
2771 inline bool __stdcall
operator !=(const CString
& s1
, LPCTSTR s2
)
2772 { return s1
.Compare(s2
) != 0; }
2774 inline bool __stdcall
operator !=(LPCTSTR s1
, const CString
& s2
)
2775 { return s2
.Compare(s1
) != 0; }
2777 inline bool __stdcall
operator <(const CString
& s1
, const CString
& s2
)
2778 { return s1
.Compare(s2
) < 0; }
2780 inline bool __stdcall
operator <(const CString
& s1
, LPCTSTR s2
)
2781 { return s1
.Compare(s2
) < 0; }
2783 inline bool __stdcall
operator <(LPCTSTR s1
, const CString
& s2
)
2784 { return s2
.Compare(s1
) > 0; }
2786 inline bool __stdcall
operator >(const CString
& s1
, const CString
& s2
)
2787 { return s1
.Compare(s2
) > 0; }
2789 inline bool __stdcall
operator >(const CString
& s1
, LPCTSTR s2
)
2790 { return s1
.Compare(s2
) > 0; }
2792 inline bool __stdcall
operator >(LPCTSTR s1
, const CString
& s2
)
2793 { return s2
.Compare(s1
) < 0; }
2795 inline bool __stdcall
operator <=(const CString
& s1
, const CString
& s2
)
2796 { return s1
.Compare(s2
) <= 0; }
2798 inline bool __stdcall
operator <=(const CString
& s1
, LPCTSTR s2
)
2799 { return s1
.Compare(s2
) <= 0; }
2801 inline bool __stdcall
operator <=(LPCTSTR s1
, const CString
& s2
)
2802 { return s2
.Compare(s1
) >= 0; }
2804 inline bool __stdcall
operator >=(const CString
& s1
, const CString
& s2
)
2805 { return s1
.Compare(s2
) >= 0; }
2807 inline bool __stdcall
operator >=(const CString
& s1
, LPCTSTR s2
)
2808 { return s1
.Compare(s2
) >= 0; }
2810 inline bool __stdcall
operator >=(LPCTSTR s1
, const CString
& s2
)
2811 { return s2
.Compare(s1
) <= 0; }
2814 // CString "operator +" functions
2816 inline CString __stdcall
operator +(const CString
& string1
, const CString
& string2
)
2819 s
.ConcatCopy(string1
.GetData()->nDataLength
, string1
.m_pchData
, string2
.GetData()->nDataLength
, string2
.m_pchData
);
2823 inline CString __stdcall
operator +(const CString
& string
, TCHAR ch
)
2826 s
.ConcatCopy(string
.GetData()->nDataLength
, string
.m_pchData
, 1, &ch
);
2830 inline CString __stdcall
operator +(TCHAR ch
, const CString
& string
)
2833 s
.ConcatCopy(1, &ch
, string
.GetData()->nDataLength
, string
.m_pchData
);
2838 inline CString __stdcall
operator +(const CString
& string
, char ch
)
2840 return string
+ (TCHAR
)ch
;
2843 inline CString __stdcall
operator +(char ch
, const CString
& string
)
2845 return (TCHAR
)ch
+ string
;
2849 inline CString __stdcall
operator +(const CString
& string
, LPCTSTR lpsz
)
2851 ATLASSERT(lpsz
== NULL
|| CString::_IsValidString(lpsz
));
2853 s
.ConcatCopy(string
.GetData()->nDataLength
, string
.m_pchData
, CString::SafeStrlen(lpsz
), lpsz
);
2857 inline CString __stdcall
operator +(LPCTSTR lpsz
, const CString
& string
)
2859 ATLASSERT(lpsz
== NULL
|| CString::_IsValidString(lpsz
));
2861 s
.ConcatCopy(CString::SafeStrlen(lpsz
), lpsz
, string
.GetData()->nDataLength
, string
.m_pchData
);
2865 #endif // !_WTL_NO_CSTRING
2868 ///////////////////////////////////////////////////////////////////////////////
2869 // CRecentDocumentList - MRU List Support
2873 #ifndef _WTL_MRUEMPTY_TEXT
2874 #define _WTL_MRUEMPTY_TEXT _T("(empty)")
2877 // forward declaration
2878 inline bool AtlCompactPath(LPTSTR lpstrOut
, LPCTSTR lpstrIn
, int cchLen
);
2880 template <class T
, int t_cchItemLen
= MAX_PATH
, int t_nFirstID
= ID_FILE_MRU_FIRST
, int t_nLastID
= ID_FILE_MRU_LAST
>
2881 class CRecentDocumentListBase
2887 TCHAR szDocName
[t_cchItemLen
];
2888 bool operator ==(const _DocEntry
& de
) const
2889 { return (lstrcmpi(szDocName
, de
.szDocName
) == 0); }
2894 m_nMaxEntries_Min
= 2,
2895 m_nMaxEntries_Max
= t_nLastID
- t_nFirstID
+ 1,
2896 m_cchMaxItemLen_Min
= 6,
2897 m_cchMaxItemLen_Max
= t_cchItemLen
,
2898 m_cchItemNameLen
= 11
2902 ATL::CSimpleArray
<_DocEntry
> m_arrDocs
;
2903 int m_nMaxEntries
; // default is 4
2906 TCHAR m_szNoEntries
[t_cchItemLen
];
2908 int m_cchMaxItemLen
;
2911 CRecentDocumentListBase() : m_hMenu(NULL
), m_nMaxEntries(4), m_cchMaxItemLen(-1)
2913 // These ASSERTs verify values of the template arguments
2914 ATLASSERT(t_cchItemLen
> m_cchMaxItemLen_Min
);
2915 ATLASSERT(m_nMaxEntries_Max
> m_nMaxEntries_Min
);
2919 HMENU
GetMenuHandle() const
2924 void SetMenuHandle(HMENU hMenu
)
2926 ATLASSERT(hMenu
== NULL
|| ::IsMenu(hMenu
));
2928 if(m_hMenu
== NULL
|| (::GetMenuString(m_hMenu
, t_nFirstID
, m_szNoEntries
, t_cchItemLen
, MF_BYCOMMAND
) == 0))
2930 T
* pT
= static_cast<T
*>(this);
2931 pT
; // avoid level 4 warning
2932 SecureHelper::strncpy_x(m_szNoEntries
, _countof(m_szNoEntries
), pT
->GetMRUEmptyText(), _TRUNCATE
);
2936 int GetMaxEntries() const
2938 return m_nMaxEntries
;
2941 void SetMaxEntries(int nMaxEntries
)
2943 ATLASSERT(nMaxEntries
>= m_nMaxEntries_Min
&& nMaxEntries
<= m_nMaxEntries_Max
);
2944 if(nMaxEntries
< m_nMaxEntries_Min
)
2945 nMaxEntries
= m_nMaxEntries_Min
;
2946 else if(nMaxEntries
> m_nMaxEntries_Max
)
2947 nMaxEntries
= m_nMaxEntries_Max
;
2948 m_nMaxEntries
= nMaxEntries
;
2951 int GetMaxItemLength() const
2953 return m_cchMaxItemLen
;
2956 void SetMaxItemLength(int cchMaxLen
)
2958 ATLASSERT((cchMaxLen
>= m_cchMaxItemLen_Min
&& cchMaxLen
<= m_cchMaxItemLen_Max
) || cchMaxLen
== -1);
2961 if(cchMaxLen
< m_cchMaxItemLen_Min
)
2962 cchMaxLen
= m_cchMaxItemLen_Min
;
2963 else if(cchMaxLen
> m_cchMaxItemLen_Max
)
2964 cchMaxLen
= m_cchMaxItemLen_Max
;
2966 m_cchMaxItemLen
= cchMaxLen
;
2967 T
* pT
= static_cast<T
*>(this);
2972 BOOL
AddToList(LPCTSTR lpstrDocName
)
2975 errno_t nRet
= SecureHelper::strncpy_x(de
.szDocName
, _countof(de
.szDocName
), lpstrDocName
, _TRUNCATE
);
2976 if(nRet
!= 0 && nRet
!= STRUNCATE
)
2979 for(int i
= 0; i
< m_arrDocs
.GetSize(); i
++)
2981 if(lstrcmpi(m_arrDocs
[i
].szDocName
, lpstrDocName
) == 0)
2983 m_arrDocs
.RemoveAt(i
);
2988 if(m_arrDocs
.GetSize() == m_nMaxEntries
)
2989 m_arrDocs
.RemoveAt(0);
2991 BOOL bRet
= m_arrDocs
.Add(de
);
2994 T
* pT
= static_cast<T
*>(this);
2995 bRet
= pT
->UpdateMenu();
3000 // This function is deprecated because it is not safe.
3001 // Use the version below that accepts the buffer length.
3002 #if (_MSC_VER >= 1300)
3003 __declspec(deprecated
)
3005 BOOL
GetFromList(int /*nItemID*/, LPTSTR
/*lpstrDocName*/)
3011 BOOL
GetFromList(int nItemID
, LPTSTR lpstrDocName
, int cchLength
)
3013 int nIndex
= m_arrDocs
.GetSize() - (nItemID
- t_nFirstID
) - 1;
3014 if(nIndex
< 0 || nIndex
>= m_arrDocs
.GetSize())
3016 if(lstrlen(m_arrDocs
[nIndex
].szDocName
) >= cchLength
)
3018 SecureHelper::strcpy_x(lpstrDocName
, cchLength
, m_arrDocs
[nIndex
].szDocName
);
3023 #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
3024 BOOL
GetFromList(int nItemID
, _CSTRING_NS::CString
& strDocName
)
3026 int nIndex
= m_arrDocs
.GetSize() - (nItemID
- t_nFirstID
) - 1;
3027 if(nIndex
< 0 || nIndex
>= m_arrDocs
.GetSize())
3029 strDocName
= m_arrDocs
[nIndex
].szDocName
;
3032 #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
3034 BOOL
RemoveFromList(int nItemID
)
3036 int nIndex
= m_arrDocs
.GetSize() - (nItemID
- t_nFirstID
) - 1;
3037 BOOL bRet
= m_arrDocs
.RemoveAt(nIndex
);
3040 T
* pT
= static_cast<T
*>(this);
3041 bRet
= pT
->UpdateMenu();
3046 BOOL
MoveToTop(int nItemID
)
3048 int nIndex
= m_arrDocs
.GetSize() - (nItemID
- t_nFirstID
) - 1;
3049 if(nIndex
< 0 || nIndex
>= m_arrDocs
.GetSize())
3052 de
= m_arrDocs
[nIndex
];
3053 m_arrDocs
.RemoveAt(nIndex
);
3054 BOOL bRet
= m_arrDocs
.Add(de
);
3057 T
* pT
= static_cast<T
*>(this);
3058 bRet
= pT
->UpdateMenu();
3063 BOOL
ReadFromRegistry(LPCTSTR lpstrRegKey
)
3065 T
* pT
= static_cast<T
*>(this);
3066 ATL::CRegKey rkParent
;
3069 LONG lRet
= rkParent
.Open(HKEY_CURRENT_USER
, lpstrRegKey
);
3070 if(lRet
!= ERROR_SUCCESS
)
3072 lRet
= rk
.Open(rkParent
, pT
->GetRegKeyName());
3073 if(lRet
!= ERROR_SUCCESS
)
3077 #if (_ATL_VER >= 0x0700)
3078 lRet
= rk
.QueryDWORDValue(pT
->GetRegCountName(), dwRet
);
3080 lRet
= rk
.QueryValue(dwRet
, pT
->GetRegCountName());
3082 if(lRet
!= ERROR_SUCCESS
)
3084 SetMaxEntries(dwRet
);
3086 m_arrDocs
.RemoveAll();
3088 TCHAR szRetString
[t_cchItemLen
] = { 0 };
3091 for(int nItem
= m_nMaxEntries
; nItem
> 0; nItem
--)
3093 TCHAR szBuff
[m_cchItemNameLen
] = { 0 };
3094 SecureHelper::wsprintf_x(szBuff
, m_cchItemNameLen
, pT
->GetRegItemName(), nItem
);
3095 #if (_ATL_VER >= 0x0700)
3096 ULONG ulCount
= t_cchItemLen
;
3097 lRet
= rk
.QueryStringValue(szBuff
, szRetString
, &ulCount
);
3099 DWORD dwCount
= t_cchItemLen
* sizeof(TCHAR
);
3100 lRet
= rk
.QueryValue(szRetString
, szBuff
, &dwCount
);
3102 if(lRet
== ERROR_SUCCESS
)
3104 SecureHelper::strcpy_x(de
.szDocName
, _countof(de
.szDocName
), szRetString
);
3112 return pT
->UpdateMenu();
3115 BOOL
WriteToRegistry(LPCTSTR lpstrRegKey
)
3117 T
* pT
= static_cast<T
*>(this);
3118 pT
; // avoid level 4 warning
3119 ATL::CRegKey rkParent
;
3122 LONG lRet
= rkParent
.Create(HKEY_CURRENT_USER
, lpstrRegKey
);
3123 if(lRet
!= ERROR_SUCCESS
)
3125 lRet
= rk
.Create(rkParent
, pT
->GetRegKeyName());
3126 if(lRet
!= ERROR_SUCCESS
)
3129 #if (_ATL_VER >= 0x0700)
3130 lRet
= rk
.SetDWORDValue(pT
->GetRegCountName(), m_nMaxEntries
);
3132 lRet
= rk
.SetValue(m_nMaxEntries
, pT
->GetRegCountName());
3134 ATLASSERT(lRet
== ERROR_SUCCESS
);
3138 for(nItem
= m_arrDocs
.GetSize(); nItem
> 0; nItem
--)
3140 TCHAR szBuff
[m_cchItemNameLen
] = { 0 };
3141 SecureHelper::wsprintf_x(szBuff
, m_cchItemNameLen
, pT
->GetRegItemName(), nItem
);
3142 TCHAR szDocName
[t_cchItemLen
] = { 0 };
3143 GetFromList(t_nFirstID
+ nItem
- 1, szDocName
, t_cchItemLen
);
3144 #if (_ATL_VER >= 0x0700)
3145 lRet
= rk
.SetStringValue(szBuff
, szDocName
);
3147 lRet
= rk
.SetValue(szDocName
, szBuff
);
3149 ATLASSERT(lRet
== ERROR_SUCCESS
);
3152 // delete unused keys
3153 for(nItem
= m_arrDocs
.GetSize() + 1; nItem
< m_nMaxEntries_Max
; nItem
++)
3155 TCHAR szBuff
[m_cchItemNameLen
] = { 0 };
3156 SecureHelper::wsprintf_x(szBuff
, m_cchItemNameLen
, pT
->GetRegItemName(), nItem
);
3157 rk
.DeleteValue(szBuff
);
3171 ATLASSERT(::IsMenu(m_hMenu
));
3173 int nItems
= ::GetMenuItemCount(m_hMenu
);
3175 for(nInsertPoint
= 0; nInsertPoint
< nItems
; nInsertPoint
++)
3179 ::GetMenuItemInfo(m_hMenu
, nInsertPoint
, TRUE
, &mi
);
3180 if (mi
.wID
== t_nFirstID
)
3183 ATLASSERT(nInsertPoint
< nItems
&& "You need a menu item with an ID = t_nFirstID");
3186 for(nItem
= t_nFirstID
; nItem
< t_nFirstID
+ m_nMaxEntries
; nItem
++)
3188 // keep the first one as an insertion point
3189 if (nItem
!= t_nFirstID
)
3190 ::DeleteMenu(m_hMenu
, nItem
, MF_BYCOMMAND
);
3193 TCHAR szItemText
[t_cchItemLen
+ 6] = { 0 }; // add space for &, 2 digits, and a space
3194 int nSize
= m_arrDocs
.GetSize();
3198 for(nItem
= 0; nItem
< nSize
; nItem
++)
3200 if(m_cchMaxItemLen
== -1)
3202 SecureHelper::wsprintf_x(szItemText
, t_cchItemLen
+ 6, _T("&%i %s"), nItem
+ 1, m_arrDocs
[nSize
- 1 - nItem
].szDocName
);
3206 TCHAR szBuff
[t_cchItemLen
] = { 0 };
3207 T
* pT
= static_cast<T
*>(this);
3208 pT
; // avoid level 4 warning
3209 bool bRet
= pT
->CompactDocumentName(szBuff
, m_arrDocs
[nSize
- 1 - nItem
].szDocName
, m_cchMaxItemLen
);
3210 bRet
; // avoid level 4 warning
3212 SecureHelper::wsprintf_x(szItemText
, t_cchItemLen
+ 6, _T("&%i %s"), nItem
+ 1, szBuff
);
3214 ::InsertMenu(m_hMenu
, nInsertPoint
+ nItem
, MF_BYPOSITION
| MF_STRING
, t_nFirstID
+ nItem
, szItemText
);
3219 ::InsertMenu(m_hMenu
, nInsertPoint
, MF_BYPOSITION
| MF_STRING
, t_nFirstID
, m_szNoEntries
);
3220 ::EnableMenuItem(m_hMenu
, t_nFirstID
, MF_GRAYED
);
3223 ::DeleteMenu(m_hMenu
, nInsertPoint
+ nItem
, MF_BYPOSITION
);
3229 // override to provide a different method of compacting document names
3230 static bool CompactDocumentName(LPTSTR lpstrOut
, LPCTSTR lpstrIn
, int cchLen
)
3232 return AtlCompactPath(lpstrOut
, lpstrIn
, cchLen
);
3235 static LPCTSTR
GetRegKeyName()
3237 return _T("Recent Document List");
3240 static LPCTSTR
GetRegCountName()
3242 return _T("DocumentCount");
3245 static LPCTSTR
GetRegItemName()
3247 // Note: This string is a format string used with wsprintf().
3248 // Resulting formatted string must be m_cchItemNameLen or less
3249 // characters long, including the terminating null character.
3250 return _T("Document%i");
3253 static LPCTSTR
GetMRUEmptyText()
3255 return _WTL_MRUEMPTY_TEXT
;
3259 class CRecentDocumentList
: public CRecentDocumentListBase
<CRecentDocumentList
>
3265 #endif // _WIN32_WCE
3268 ///////////////////////////////////////////////////////////////////////////////
3269 // CFindFile - file search helper class
3275 WIN32_FIND_DATA m_fd
;
3276 TCHAR m_lpszRoot
[MAX_PATH
];
3277 TCHAR m_chDirSeparator
;
3281 // Constructor/destructor
3282 CFindFile() : m_hFind(NULL
), m_chDirSeparator(_T('\\')), m_bFound(FALSE
)
3291 ULONGLONG
GetFileSize() const
3293 ATLASSERT(m_hFind
!= NULL
);
3295 ULARGE_INTEGER nFileSize
= { 0 };
3299 nFileSize
.LowPart
= m_fd
.nFileSizeLow
;
3300 nFileSize
.HighPart
= m_fd
.nFileSizeHigh
;
3304 nFileSize
.QuadPart
= 0;
3307 return nFileSize
.QuadPart
;
3310 BOOL
GetFileName(LPTSTR lpstrFileName
, int cchLength
) const
3312 ATLASSERT(m_hFind
!= NULL
);
3313 if(lstrlen(m_fd
.cFileName
) >= cchLength
)
3317 SecureHelper::strcpy_x(lpstrFileName
, cchLength
, m_fd
.cFileName
);
3322 BOOL
GetFilePath(LPTSTR lpstrFilePath
, int cchLength
) const
3324 ATLASSERT(m_hFind
!= NULL
);
3326 int nLen
= lstrlen(m_lpszRoot
);
3328 ATLASSERT(nLen
> 0);
3332 bool bAddSep
= (m_lpszRoot
[nLen
- 1] != _T('\\') && m_lpszRoot
[nLen
- 1] !=_T('/'));
3333 #else // CE specific
3334 // allow diskless devices (nLen == 0)
3335 bool bAddSep
= ((nLen
== 0) || (m_lpszRoot
[nLen
- 1] != _T('\\') && m_lpszRoot
[nLen
- 1] !=_T('/')));
3336 #endif // _WIN32_WCE
3338 if((lstrlen(m_lpszRoot
) + (bAddSep
? 1 : 0)) >= cchLength
)
3341 SecureHelper::strcpy_x(lpstrFilePath
, cchLength
, m_lpszRoot
);
3345 TCHAR szSeparator
[2] = { m_chDirSeparator
, 0 };
3346 SecureHelper::strcat_x(lpstrFilePath
, cchLength
, szSeparator
);
3349 SecureHelper::strcat_x(lpstrFilePath
, cchLength
, m_fd
.cFileName
);
3355 BOOL
GetFileTitle(LPTSTR lpstrFileTitle
, int cchLength
) const
3357 ATLASSERT(m_hFind
!= NULL
);
3359 TCHAR szBuff
[MAX_PATH
] = { 0 };
3360 if(!GetFileName(szBuff
, MAX_PATH
))
3363 if(lstrlen(szBuff
) >= cchLength
|| cchLength
< 1)
3366 // find the last dot
3367 LPTSTR pstrDot
= (LPTSTR
)_cstrrchr(szBuff
, _T('.'));
3371 SecureHelper::strcpy_x(lpstrFileTitle
, cchLength
, szBuff
);
3375 #endif // !_WIN32_WCE
3377 BOOL
GetFileURL(LPTSTR lpstrFileURL
, int cchLength
) const
3379 ATLASSERT(m_hFind
!= NULL
);
3381 TCHAR szBuff
[MAX_PATH
] = { 0 };
3382 if(!GetFilePath(szBuff
, MAX_PATH
))
3384 LPCTSTR lpstrFileURLPrefix
= _T("file://");
3385 if(lstrlen(szBuff
) + lstrlen(lpstrFileURLPrefix
) >= cchLength
)
3387 SecureHelper::strcpy_x(lpstrFileURL
, cchLength
, lpstrFileURLPrefix
);
3388 SecureHelper::strcat_x(lpstrFileURL
, cchLength
, szBuff
);
3393 BOOL
GetRoot(LPTSTR lpstrRoot
, int cchLength
) const
3395 ATLASSERT(m_hFind
!= NULL
);
3396 if(lstrlen(m_lpszRoot
) >= cchLength
)
3399 SecureHelper::strcpy_x(lpstrRoot
, cchLength
, m_lpszRoot
);
3404 #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
3405 _CSTRING_NS::CString
GetFileName() const
3407 ATLASSERT(m_hFind
!= NULL
);
3409 _CSTRING_NS::CString ret
;
3412 ret
= m_fd
.cFileName
;
3416 _CSTRING_NS::CString
GetFilePath() const
3418 ATLASSERT(m_hFind
!= NULL
);
3420 _CSTRING_NS::CString strResult
= m_lpszRoot
;
3421 int nLen
= strResult
.GetLength();
3423 ATLASSERT(nLen
> 0);
3427 if((strResult
[nLen
- 1] != _T('\\')) && (strResult
[nLen
- 1] != _T('/')))
3428 #else // CE specific
3429 // allow diskless devices (nLen == 0)
3430 if((nLen
== 0) || ((strResult
[nLen
- 1] != _T('\\')) && (strResult
[nLen
- 1] != _T('/'))))
3431 #endif // _WIN32_WCE
3432 strResult
+= m_chDirSeparator
;
3433 strResult
+= GetFileName();
3438 _CSTRING_NS::CString
GetFileTitle() const
3440 ATLASSERT(m_hFind
!= NULL
);
3442 _CSTRING_NS::CString strResult
;
3443 GetFileTitle(strResult
.GetBuffer(MAX_PATH
), MAX_PATH
);
3444 strResult
.ReleaseBuffer();
3448 #endif // !_WIN32_WCE
3450 _CSTRING_NS::CString
GetFileURL() const
3452 ATLASSERT(m_hFind
!= NULL
);
3454 _CSTRING_NS::CString
strResult("file://");
3455 strResult
+= GetFilePath();
3459 _CSTRING_NS::CString
GetRoot() const
3461 ATLASSERT(m_hFind
!= NULL
);
3463 _CSTRING_NS::CString str
= m_lpszRoot
;
3466 #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
3468 BOOL
GetLastWriteTime(FILETIME
* pTimeStamp
) const
3470 ATLASSERT(m_hFind
!= NULL
);
3471 ATLASSERT(pTimeStamp
!= NULL
);
3473 if(m_bFound
&& pTimeStamp
!= NULL
)
3475 *pTimeStamp
= m_fd
.ftLastWriteTime
;
3482 BOOL
GetLastAccessTime(FILETIME
* pTimeStamp
) const
3484 ATLASSERT(m_hFind
!= NULL
);
3485 ATLASSERT(pTimeStamp
!= NULL
);
3487 if(m_bFound
&& pTimeStamp
!= NULL
)
3489 *pTimeStamp
= m_fd
.ftLastAccessTime
;
3496 BOOL
GetCreationTime(FILETIME
* pTimeStamp
) const
3498 ATLASSERT(m_hFind
!= NULL
);
3500 if(m_bFound
&& pTimeStamp
!= NULL
)
3502 *pTimeStamp
= m_fd
.ftCreationTime
;
3509 BOOL
MatchesMask(DWORD dwMask
) const
3511 ATLASSERT(m_hFind
!= NULL
);
3514 return ((m_fd
.dwFileAttributes
& dwMask
) != 0);
3521 ATLASSERT(m_hFind
!= NULL
);
3523 // return TRUE if the file name is "." or ".." and
3524 // the file is a directory
3526 BOOL bResult
= FALSE
;
3527 if(m_bFound
&& IsDirectory())
3529 if(m_fd
.cFileName
[0] == _T('.') && (m_fd
.cFileName
[1] == _T('\0') || (m_fd
.cFileName
[1] == _T('.') && m_fd
.cFileName
[2] == _T('\0'))))
3536 BOOL
IsReadOnly() const
3538 return MatchesMask(FILE_ATTRIBUTE_READONLY
);
3541 BOOL
IsDirectory() const
3543 return MatchesMask(FILE_ATTRIBUTE_DIRECTORY
);
3546 BOOL
IsCompressed() const
3548 return MatchesMask(FILE_ATTRIBUTE_COMPRESSED
);
3551 BOOL
IsSystem() const
3553 return MatchesMask(FILE_ATTRIBUTE_SYSTEM
);
3556 BOOL
IsHidden() const
3558 return MatchesMask(FILE_ATTRIBUTE_HIDDEN
);
3561 BOOL
IsTemporary() const
3563 return MatchesMask(FILE_ATTRIBUTE_TEMPORARY
);
3566 BOOL
IsNormal() const
3568 return MatchesMask(FILE_ATTRIBUTE_NORMAL
);
3571 BOOL
IsArchived() const
3573 return MatchesMask(FILE_ATTRIBUTE_ARCHIVE
);
3577 BOOL
FindFile(LPCTSTR pstrName
= NULL
)
3581 if(pstrName
== NULL
)
3583 pstrName
= _T("*.*");
3585 else if(lstrlen(pstrName
) >= MAX_PATH
)
3591 SecureHelper::strcpy_x(m_fd
.cFileName
, _countof(m_fd
.cFileName
), pstrName
);
3593 m_hFind
= ::FindFirstFile(pstrName
, &m_fd
);
3595 if(m_hFind
== INVALID_HANDLE_VALUE
)
3599 bool bFullPath
= (::GetFullPathName(pstrName
, MAX_PATH
, m_lpszRoot
, NULL
) != 0);
3600 #else // CE specific
3601 errno_t nRet
= SecureHelper::strncpy_x(m_lpszRoot
, _countof(m_lpszRoot
), pstrName
, _TRUNCATE
);
3602 bool bFullPath
= (nRet
== 0 || nRet
== STRUNCATE
);
3603 #endif // _WIN32_WCE
3605 // passed name isn't a valid path but was found by the API
3606 ATLASSERT(bFullPath
);
3610 ::SetLastError(ERROR_INVALID_NAME
);
3615 // find the last forward or backward whack
3616 LPTSTR pstrBack
= (LPTSTR
)_cstrrchr(m_lpszRoot
, _T('\\'));
3617 LPTSTR pstrFront
= (LPTSTR
)_cstrrchr(m_lpszRoot
, _T('/'));
3619 if(pstrFront
!= NULL
|| pstrBack
!= NULL
)
3621 if(pstrFront
== NULL
)
3622 pstrFront
= m_lpszRoot
;
3623 if(pstrBack
== NULL
)
3624 pstrBack
= m_lpszRoot
;
3626 // from the start to the last whack is the root
3628 if(pstrFront
>= pstrBack
)
3629 *pstrFront
= _T('\0');
3631 *pstrBack
= _T('\0');
3642 ATLASSERT(m_hFind
!= NULL
);
3650 m_bFound
= ::FindNextFile(m_hFind
, &m_fd
);
3659 if(m_hFind
!= NULL
&& m_hFind
!= INVALID_HANDLE_VALUE
)
3661 ::FindClose(m_hFind
);
3667 static const TCHAR
* _cstrrchr(const TCHAR
* p
, TCHAR ch
)
3670 const TCHAR
* lpsz
= NULL
;
3678 #else // !_ATL_MIN_CRT
3679 return _tcsrchr(p
, ch
);
3680 #endif // !_ATL_MIN_CRT
3685 ///////////////////////////////////////////////////////////////////////////////
3686 // Global functions for loading resources
3688 inline HACCEL
AtlLoadAccelerators(ATL::_U_STRINGorID table
)
3690 return ::LoadAccelerators(ModuleHelper::GetResourceInstance(), table
.m_lpstr
);
3693 inline HMENU
AtlLoadMenu(ATL::_U_STRINGorID menu
)
3695 return ::LoadMenu(ModuleHelper::GetResourceInstance(), menu
.m_lpstr
);
3698 inline HBITMAP
AtlLoadBitmap(ATL::_U_STRINGorID bitmap
)
3700 return ::LoadBitmap(ModuleHelper::GetResourceInstance(), bitmap
.m_lpstr
);
3704 inline HBITMAP
AtlLoadSysBitmap(ATL::_U_STRINGorID bitmap
)
3707 WORD wID
= (WORD
)bitmap
.m_lpstr
;
3708 ATLASSERT(wID
>= 32734 && wID
<= 32767);
3710 return ::LoadBitmap(NULL
, bitmap
.m_lpstr
);
3712 #endif // OEMRESOURCE
3714 inline HCURSOR
AtlLoadCursor(ATL::_U_STRINGorID cursor
)
3716 return ::LoadCursor(ModuleHelper::GetResourceInstance(), cursor
.m_lpstr
);
3719 inline HCURSOR
AtlLoadSysCursor(LPCTSTR lpCursorName
)
3721 #if (WINVER >= 0x0500)
3722 ATLASSERT(lpCursorName
== IDC_ARROW
|| lpCursorName
== IDC_IBEAM
|| lpCursorName
== IDC_WAIT
||
3723 lpCursorName
== IDC_CROSS
|| lpCursorName
== IDC_UPARROW
|| lpCursorName
== IDC_SIZE
||
3724 lpCursorName
== IDC_ICON
|| lpCursorName
== IDC_SIZENWSE
|| lpCursorName
== IDC_SIZENESW
||
3725 lpCursorName
== IDC_SIZEWE
|| lpCursorName
== IDC_SIZENS
|| lpCursorName
== IDC_SIZEALL
||
3726 lpCursorName
== IDC_NO
|| lpCursorName
== IDC_APPSTARTING
|| lpCursorName
== IDC_HELP
||
3727 lpCursorName
== IDC_HAND
);
3728 #else // !(WINVER >= 0x0500)
3729 ATLASSERT(lpCursorName
== IDC_ARROW
|| lpCursorName
== IDC_IBEAM
|| lpCursorName
== IDC_WAIT
||
3730 lpCursorName
== IDC_CROSS
|| lpCursorName
== IDC_UPARROW
|| lpCursorName
== IDC_SIZE
||
3731 lpCursorName
== IDC_ICON
|| lpCursorName
== IDC_SIZENWSE
|| lpCursorName
== IDC_SIZENESW
||
3732 lpCursorName
== IDC_SIZEWE
|| lpCursorName
== IDC_SIZENS
|| lpCursorName
== IDC_SIZEALL
||
3733 lpCursorName
== IDC_NO
|| lpCursorName
== IDC_APPSTARTING
|| lpCursorName
== IDC_HELP
);
3734 #endif // !(WINVER >= 0x0500)
3735 return ::LoadCursor(NULL
, lpCursorName
);
3738 inline HICON
AtlLoadIcon(ATL::_U_STRINGorID icon
)
3740 return ::LoadIcon(ModuleHelper::GetResourceInstance(), icon
.m_lpstr
);
3744 inline HICON
AtlLoadSysIcon(LPCTSTR lpIconName
)
3746 #if (WINVER >= 0x0600)
3747 ATLASSERT(lpIconName
== IDI_APPLICATION
|| lpIconName
== IDI_ASTERISK
|| lpIconName
== IDI_EXCLAMATION
||
3748 lpIconName
== IDI_HAND
|| lpIconName
== IDI_QUESTION
|| lpIconName
== IDI_WINLOGO
||
3749 lpIconName
== IDI_SHIELD
);
3750 #else // !(WINVER >= 0x0600)
3751 ATLASSERT(lpIconName
== IDI_APPLICATION
|| lpIconName
== IDI_ASTERISK
|| lpIconName
== IDI_EXCLAMATION
||
3752 lpIconName
== IDI_HAND
|| lpIconName
== IDI_QUESTION
|| lpIconName
== IDI_WINLOGO
);
3753 #endif // !(WINVER >= 0x0600)
3754 return ::LoadIcon(NULL
, lpIconName
);
3756 #endif // !_WIN32_WCE
3758 inline HBITMAP
AtlLoadBitmapImage(ATL::_U_STRINGorID bitmap
, UINT fuLoad
= LR_DEFAULTCOLOR
)
3760 return (HBITMAP
)::LoadImage(ModuleHelper::GetResourceInstance(), bitmap
.m_lpstr
, IMAGE_BITMAP
, 0, 0, fuLoad
);
3763 inline HCURSOR
AtlLoadCursorImage(ATL::_U_STRINGorID cursor
, UINT fuLoad
= LR_DEFAULTCOLOR
| LR_DEFAULTSIZE
, int cxDesired
= 0, int cyDesired
= 0)
3765 return (HCURSOR
)::LoadImage(ModuleHelper::GetResourceInstance(), cursor
.m_lpstr
, IMAGE_CURSOR
, cxDesired
, cyDesired
, fuLoad
);
3768 inline HICON
AtlLoadIconImage(ATL::_U_STRINGorID icon
, UINT fuLoad
= LR_DEFAULTCOLOR
| LR_DEFAULTSIZE
, int cxDesired
= 0, int cyDesired
= 0)
3770 return (HICON
)::LoadImage(ModuleHelper::GetResourceInstance(), icon
.m_lpstr
, IMAGE_ICON
, cxDesired
, cyDesired
, fuLoad
);
3774 inline HBITMAP
AtlLoadSysBitmapImage(WORD wBitmapID
, UINT fuLoad
= LR_DEFAULTCOLOR
)
3776 ATLASSERT(wBitmapID
>= 32734 && wBitmapID
<= 32767);
3777 ATLASSERT((fuLoad
& LR_LOADFROMFILE
) == 0); // this one doesn't load from a file
3778 return (HBITMAP
)::LoadImage(NULL
, MAKEINTRESOURCE(wBitmapID
), IMAGE_BITMAP
, 0, 0, fuLoad
);
3780 #endif // OEMRESOURCE
3782 inline HCURSOR
AtlLoadSysCursorImage(ATL::_U_STRINGorID cursor
, UINT fuLoad
= LR_DEFAULTCOLOR
| LR_DEFAULTSIZE
, int cxDesired
= 0, int cyDesired
= 0)
3785 WORD wID
= (WORD
)cursor
.m_lpstr
;
3786 ATLASSERT((wID
>= 32512 && wID
<= 32516) || (wID
>= 32640 && wID
<= 32648) || (wID
== 32650) || (wID
== 32651));
3787 ATLASSERT((fuLoad
& LR_LOADFROMFILE
) == 0); // this one doesn't load from a file
3789 return (HCURSOR
)::LoadImage(NULL
, cursor
.m_lpstr
, IMAGE_CURSOR
, cxDesired
, cyDesired
, fuLoad
);
3792 inline HICON
AtlLoadSysIconImage(ATL::_U_STRINGorID icon
, UINT fuLoad
= LR_DEFAULTCOLOR
| LR_DEFAULTSIZE
, int cxDesired
= 0, int cyDesired
= 0)
3795 WORD wID
= (WORD
)icon
.m_lpstr
;
3796 ATLASSERT(wID
>= 32512 && wID
<= 32517);
3797 ATLASSERT((fuLoad
& LR_LOADFROMFILE
) == 0); // this one doesn't load from a file
3799 return (HICON
)::LoadImage(NULL
, icon
.m_lpstr
, IMAGE_ICON
, cxDesired
, cyDesired
, fuLoad
);
3802 #if (_ATL_VER < 0x0700)
3803 inline int AtlLoadString(UINT uID
, LPTSTR lpBuffer
, int nBufferMax
)
3805 return ::LoadString(_Module
.GetResourceInstance(), uID
, lpBuffer
, nBufferMax
);
3807 #endif // (_ATL_VER < 0x0700)
3809 #ifdef _WIN32_WCE // CE only direct access to the resource
3810 inline LPCTSTR
AtlLoadString(UINT uID
)
3812 LPCTSTR s
= (LPCTSTR
)::LoadString(ModuleHelper::GetResourceInstance(), uID
, NULL
, 0);
3813 #ifdef DEBUG // Check for null-termination
3815 // Note: RC -n <file.rc> compiles null-terminated resource strings
3816 ATLASSERT(s
[*((WORD
*)s
-1) - 1] == L
'\0');
3820 #endif // _WIN32_WCE
3822 inline bool AtlLoadString(UINT uID
, BSTR
& bstrText
)
3825 ATLASSERT(bstrText
== NULL
);
3827 LPTSTR lpstrText
= NULL
;
3829 for(int nLen
= 256; ; nLen
*= 2)
3831 ATLTRY(lpstrText
= new TCHAR
[nLen
]);
3832 if(lpstrText
== NULL
)
3834 nRes
= ::LoadString(ModuleHelper::GetResourceInstance(), uID
, lpstrText
, nLen
);
3837 delete [] lpstrText
;
3841 if(lpstrText
!= NULL
)
3844 bstrText
= ::SysAllocString(T2OLE(lpstrText
));
3845 delete [] lpstrText
;
3848 return (bstrText
!= NULL
) ? true : false;
3852 ///////////////////////////////////////////////////////////////////////////////
3853 // Global functions for stock GDI objects
3855 inline HPEN
AtlGetStockPen(int nPen
)
3857 #if (_WIN32_WINNT >= 0x0500) && !defined(_WIN32_WCE)
3858 ATLASSERT(nPen
== WHITE_PEN
|| nPen
== BLACK_PEN
|| nPen
== NULL_PEN
|| nPen
== DC_PEN
);
3860 ATLASSERT(nPen
== WHITE_PEN
|| nPen
== BLACK_PEN
|| nPen
== NULL_PEN
);
3862 return (HPEN
)::GetStockObject(nPen
);
3865 inline HBRUSH
AtlGetStockBrush(int nBrush
)
3867 #if (_WIN32_WINNT >= 0x0500) && !defined(_WIN32_WCE)
3868 ATLASSERT((nBrush
>= WHITE_BRUSH
&& nBrush
<= HOLLOW_BRUSH
) || nBrush
== DC_BRUSH
);
3870 ATLASSERT(nBrush
>= WHITE_BRUSH
&& nBrush
<= HOLLOW_BRUSH
);
3872 return (HBRUSH
)::GetStockObject(nBrush
);
3875 inline HFONT
AtlGetStockFont(int nFont
)
3878 ATLASSERT((nFont
>= OEM_FIXED_FONT
&& nFont
<= SYSTEM_FIXED_FONT
) || nFont
== DEFAULT_GUI_FONT
);
3879 #else // CE specific
3880 ATLASSERT(nFont
== SYSTEM_FONT
);
3881 #endif // _WIN32_WCE
3882 return (HFONT
)::GetStockObject(nFont
);
3885 inline HPALETTE
AtlGetStockPalette(int nPalette
)
3887 ATLASSERT(nPalette
== DEFAULT_PALETTE
); // the only one supported
3888 return (HPALETTE
)::GetStockObject(nPalette
);
3892 ///////////////////////////////////////////////////////////////////////////////
3893 // Global function for compacting a path by replacing parts with ellipsis
3895 // helper for multi-byte character sets
3896 inline bool _IsDBCSTrailByte(LPCTSTR lpstr
, int nChar
)
3902 if(!::IsDBCSLeadByte(lpstr
[i
- 1]))
3905 return ((nChar
> 0) && (((nChar
- i
) & 1) != 0));
3912 inline bool AtlCompactPath(LPTSTR lpstrOut
, LPCTSTR lpstrIn
, int cchLen
)
3914 ATLASSERT(lpstrOut
!= NULL
);
3915 ATLASSERT(lpstrIn
!= NULL
);
3916 ATLASSERT(cchLen
> 0);
3918 LPCTSTR szEllipsis
= _T("...");
3919 const int cchEndEllipsis
= 3;
3920 const int cchMidEllipsis
= 4;
3922 if(lstrlen(lpstrIn
) < cchLen
)
3924 SecureHelper::strcpy_x(lpstrOut
, cchLen
, lpstrIn
);
3930 // check if the separator is a slash or a backslash
3931 TCHAR chSlash
= _T('\\');
3932 for(LPTSTR lpstr
= (LPTSTR
)lpstrIn
; *lpstr
!= 0; lpstr
= ::CharNext(lpstr
))
3934 if((*lpstr
== _T('/')) || (*lpstr
== _T('\\')))
3938 // find the filename portion of the path
3939 LPCTSTR lpstrFileName
= lpstrIn
;
3940 for(LPCTSTR pPath
= lpstrIn
; *pPath
; pPath
= ::CharNext(pPath
))
3942 if((pPath
[0] == _T('\\') || pPath
[0] == _T(':') || pPath
[0] == _T('/'))
3943 && pPath
[1] && pPath
[1] != _T('\\') && pPath
[1] != _T('/'))
3944 lpstrFileName
= pPath
+ 1;
3946 int cchFileName
= lstrlen(lpstrFileName
);
3948 // handle just the filename without a path
3949 if(lpstrFileName
== lpstrIn
&& cchLen
> cchEndEllipsis
)
3951 bool bRet
= (SecureHelper::strncpy_x(lpstrOut
, cchLen
, lpstrIn
, cchLen
- cchEndEllipsis
- 1) == 0);
3955 if(_IsDBCSTrailByte(lpstrIn
, cchLen
- cchEndEllipsis
))
3956 lpstrOut
[cchLen
- cchEndEllipsis
- 1] = 0;
3958 SecureHelper::strcat_x(lpstrOut
, cchLen
, szEllipsis
);
3963 // handle just ellipsis
3964 if((cchLen
< (cchMidEllipsis
+ cchEndEllipsis
)))
3966 for(int i
= 0; i
< cchLen
- 1; i
++)
3967 lpstrOut
[i
] = ((i
+ 1) == cchMidEllipsis
) ? chSlash
: _T('.');
3968 lpstrOut
[cchLen
- 1] = 0;
3972 // calc how much we have to copy
3973 int cchToCopy
= cchLen
- (cchMidEllipsis
+ cchFileName
) - 1;
3979 if(cchToCopy
> 0 && _IsDBCSTrailByte(lpstrIn
, cchToCopy
))
3983 bool bRet
= (SecureHelper::strncpy_x(lpstrOut
, cchLen
, lpstrIn
, cchToCopy
) == 0);
3988 SecureHelper::strcat_x(lpstrOut
, cchLen
, szEllipsis
);
3991 TCHAR szSlash
[2] = { chSlash
, 0 };
3992 SecureHelper::strcat_x(lpstrOut
, cchLen
, szSlash
);
3996 // add filename (and ellipsis, if needed)
3997 if(cchLen
> (cchMidEllipsis
+ cchFileName
))
3999 SecureHelper::strcat_x(lpstrOut
, cchLen
, lpstrFileName
);
4003 cchToCopy
= cchLen
- cchMidEllipsis
- cchEndEllipsis
- 1;
4005 if(cchToCopy
> 0 && _IsDBCSTrailByte(lpstrFileName
, cchToCopy
))
4008 bRet
= (SecureHelper::strncpy_x(&lpstrOut
[cchMidEllipsis
], cchLen
- cchMidEllipsis
, lpstrFileName
, cchToCopy
) == 0);
4010 SecureHelper::strcat_x(lpstrOut
, cchLen
, szEllipsis
);
4018 #endif // __ATLMISC_H__