Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(635)

Side by Side Diff: third_party/wtl/include/atlmisc.h

Issue 703753005: More Windows build fixes. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: remove generated files Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/wtl/include/atlgdi.h ('k') | third_party/wtl/include/atlprint.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Windows Template Library - WTL version 8.0
2 // Copyright (C) Microsoft Corporation. All rights reserved.
3 //
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.
8
9 #ifndef __ATLMISC_H__
10 #define __ATLMISC_H__
11
12 #pragma once
13
14 #ifndef __cplusplus
15 #error ATL requires C++ compilation (use a .cpp suffix)
16 #endif
17
18 #ifndef __ATLAPP_H__
19 #error atlmisc.h requires atlapp.h to be included first
20 #endif
21
22
23 #ifdef _ATL_TMP_NO_CSTRING
24 #define _WTL_NO_CSTRING
25 #endif
26
27 #if defined(_WTL_USE_CSTRING) && defined(_WTL_NO_CSTRING)
28 #error Conflicting options - both _WTL_USE_CSTRING and _WTL_NO_CSTRING a re defined
29 #endif // defined(_WTL_USE_CSTRING) && defined(_WTL_NO_CSTRING)
30
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)
34
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 de fined
38 #endif // defined(_ATL_USE_CSTRING_FLOAT) && defined(_ATL_MIN_CRT)
39 #endif // !_WTL_NO_CSTRING
40
41
42 ///////////////////////////////////////////////////////////////////////////////
43 // Classes in this file:
44 //
45 // CSize
46 // CPoint
47 // CRect
48 // CString
49 //
50 // CRecentDocumentListBase<T, t_cchItemLen, t_nFirstID, t_nLastID>
51 // CRecentDocumentList
52 // CFindFile
53 //
54 // Global functions:
55 // AtlLoadAccelerators()
56 // AtlLoadMenu()
57 // AtlLoadBitmap()
58 // AtlLoadSysBitmap()
59 // AtlLoadCursor()
60 // AtlLoadSysCursor()
61 // AtlLoadIcon()
62 // AtlLoadSysIcon()
63 // AtlLoadBitmapImage()
64 // AtlLoadCursorImage()
65 // AtlLoadIconImage()
66 // AtlLoadSysBitmapImage()
67 // AtlLoadSysCursorImage()
68 // AtlLoadSysIconImage()
69 // AtlLoadString()
70 //
71 // AtlGetStockPen()
72 // AtlGetStockBrush()
73 // AtlGetStockFont()
74 // AtlGetStockPalette()
75 //
76 // AtlCompactPath()
77
78
79 namespace WTL
80 {
81
82 #ifndef _WTL_NO_WTYPES
83
84 // forward declarations
85 class CSize;
86 class CPoint;
87 class CRect;
88
89 ///////////////////////////////////////////////////////////////////////////////
90 // CSize - Wrapper for Windows SIZE structure.
91
92 class CSize : public SIZE
93 {
94 public:
95 // Constructors
96 CSize()
97 {
98 cx = 0;
99 cy = 0;
100 }
101
102 CSize(int initCX, int initCY)
103 {
104 cx = initCX;
105 cy = initCY;
106 }
107
108 CSize(SIZE initSize)
109 {
110 *(SIZE*)this = initSize;
111 }
112
113 CSize(POINT initPt)
114 {
115 *(POINT*)this = initPt;
116 }
117
118 CSize(DWORD dwSize)
119 {
120 cx = (short)LOWORD(dwSize);
121 cy = (short)HIWORD(dwSize);
122 }
123
124 // Operations
125 BOOL operator ==(SIZE size) const
126 {
127 return (cx == size.cx && cy == size.cy);
128 }
129
130 BOOL operator !=(SIZE size) const
131 {
132 return (cx != size.cx || cy != size.cy);
133 }
134
135 void operator +=(SIZE size)
136 {
137 cx += size.cx;
138 cy += size.cy;
139 }
140
141 void operator -=(SIZE size)
142 {
143 cx -= size.cx;
144 cy -= size.cy;
145 }
146
147 void SetSize(int CX, int CY)
148 {
149 cx = CX;
150 cy = CY;
151 }
152
153 // Operators returning CSize values
154 CSize operator +(SIZE size) const
155 {
156 return CSize(cx + size.cx, cy + size.cy);
157 }
158
159 CSize operator -(SIZE size) const
160 {
161 return CSize(cx - size.cx, cy - size.cy);
162 }
163
164 CSize operator -() const
165 {
166 return CSize(-cx, -cy);
167 }
168
169 // Operators returning CPoint values
170 CPoint operator +(POINT point) const;
171 CPoint operator -(POINT point) const;
172
173 // Operators returning CRect values
174 CRect operator +(const RECT* lpRect) const;
175 CRect operator -(const RECT* lpRect) const;
176 };
177
178
179 ///////////////////////////////////////////////////////////////////////////////
180 // CPoint - Wrapper for Windows POINT structure.
181
182 class CPoint : public POINT
183 {
184 public:
185 // Constructors
186 CPoint()
187 {
188 x = 0;
189 y = 0;
190 }
191
192 CPoint(int initX, int initY)
193 {
194 x = initX;
195 y = initY;
196 }
197
198 CPoint(POINT initPt)
199 {
200 *(POINT*)this = initPt;
201 }
202
203 CPoint(SIZE initSize)
204 {
205 *(SIZE*)this = initSize;
206 }
207
208 CPoint(DWORD dwPoint)
209 {
210 x = (short)LOWORD(dwPoint);
211 y = (short)HIWORD(dwPoint);
212 }
213
214 // Operations
215 void Offset(int xOffset, int yOffset)
216 {
217 x += xOffset;
218 y += yOffset;
219 }
220
221 void Offset(POINT point)
222 {
223 x += point.x;
224 y += point.y;
225 }
226
227 void Offset(SIZE size)
228 {
229 x += size.cx;
230 y += size.cy;
231 }
232
233 BOOL operator ==(POINT point) const
234 {
235 return (x == point.x && y == point.y);
236 }
237
238 BOOL operator !=(POINT point) const
239 {
240 return (x != point.x || y != point.y);
241 }
242
243 void operator +=(SIZE size)
244 {
245 x += size.cx;
246 y += size.cy;
247 }
248
249 void operator -=(SIZE size)
250 {
251 x -= size.cx;
252 y -= size.cy;
253 }
254
255 void operator +=(POINT point)
256 {
257 x += point.x;
258 y += point.y;
259 }
260
261 void operator -=(POINT point)
262 {
263 x -= point.x;
264 y -= point.y;
265 }
266
267 void SetPoint(int X, int Y)
268 {
269 x = X;
270 y = Y;
271 }
272
273 // Operators returning CPoint values
274 CPoint operator +(SIZE size) const
275 {
276 return CPoint(x + size.cx, y + size.cy);
277 }
278
279 CPoint operator -(SIZE size) const
280 {
281 return CPoint(x - size.cx, y - size.cy);
282 }
283
284 CPoint operator -() const
285 {
286 return CPoint(-x, -y);
287 }
288
289 CPoint operator +(POINT point) const
290 {
291 return CPoint(x + point.x, y + point.y);
292 }
293
294 // Operators returning CSize values
295 CSize operator -(POINT point) const
296 {
297 return CSize(x - point.x, y - point.y);
298 }
299
300 // Operators returning CRect values
301 CRect operator +(const RECT* lpRect) const;
302 CRect operator -(const RECT* lpRect) const;
303 };
304
305
306 ///////////////////////////////////////////////////////////////////////////////
307 // CRect - Wrapper for Windows RECT structure.
308
309 class CRect : public RECT
310 {
311 public:
312 // Constructors
313 CRect()
314 {
315 left = 0;
316 top = 0;
317 right = 0;
318 bottom = 0;
319 }
320
321 CRect(int l, int t, int r, int b)
322 {
323 left = l;
324 top = t;
325 right = r;
326 bottom = b;
327 }
328
329 CRect(const RECT& srcRect)
330 {
331 ::CopyRect(this, &srcRect);
332 }
333
334 CRect(LPCRECT lpSrcRect)
335 {
336 ::CopyRect(this, lpSrcRect);
337 }
338
339 CRect(POINT point, SIZE size)
340 {
341 right = (left = point.x) + size.cx;
342 bottom = (top = point.y) + size.cy;
343 }
344
345 CRect(POINT topLeft, POINT bottomRight)
346 {
347 left = topLeft.x;
348 top = topLeft.y;
349 right = bottomRight.x;
350 bottom = bottomRight.y;
351 }
352
353 // Attributes (in addition to RECT members)
354 int Width() const
355 {
356 return right - left;
357 }
358
359 int Height() const
360 {
361 return bottom - top;
362 }
363
364 CSize Size() const
365 {
366 return CSize(right - left, bottom - top);
367 }
368
369 CPoint& TopLeft()
370 {
371 return *((CPoint*)this);
372 }
373
374 CPoint& BottomRight()
375 {
376 return *((CPoint*)this + 1);
377 }
378
379 const CPoint& TopLeft() const
380 {
381 return *((CPoint*)this);
382 }
383
384 const CPoint& BottomRight() const
385 {
386 return *((CPoint*)this + 1);
387 }
388
389 CPoint CenterPoint() const
390 {
391 return CPoint((left + right) / 2, (top + bottom) / 2);
392 }
393
394 // convert between CRect and LPRECT/LPCRECT (no need for &)
395 operator LPRECT()
396 {
397 return this;
398 }
399
400 operator LPCRECT() const
401 {
402 return this;
403 }
404
405 BOOL IsRectEmpty() const
406 {
407 return ::IsRectEmpty(this);
408 }
409
410 BOOL IsRectNull() const
411 {
412 return (left == 0 && right == 0 && top == 0 && bottom == 0);
413 }
414
415 BOOL PtInRect(POINT point) const
416 {
417 return ::PtInRect(this, point);
418 }
419
420 // Operations
421 void SetRect(int x1, int y1, int x2, int y2)
422 {
423 ::SetRect(this, x1, y1, x2, y2);
424 }
425
426 void SetRect(POINT topLeft, POINT bottomRight)
427 {
428 ::SetRect(this, topLeft.x, topLeft.y, bottomRight.x, bottomRight .y);
429 }
430
431 void SetRectEmpty()
432 {
433 ::SetRectEmpty(this);
434 }
435
436 void CopyRect(LPCRECT lpSrcRect)
437 {
438 ::CopyRect(this, lpSrcRect);
439 }
440
441 BOOL EqualRect(LPCRECT lpRect) const
442 {
443 return ::EqualRect(this, lpRect);
444 }
445
446 void InflateRect(int x, int y)
447 {
448 ::InflateRect(this, x, y);
449 }
450
451 void InflateRect(SIZE size)
452 {
453 ::InflateRect(this, size.cx, size.cy);
454 }
455
456 void InflateRect(LPCRECT lpRect)
457 {
458 left -= lpRect->left;
459 top -= lpRect->top;
460 right += lpRect->right;
461 bottom += lpRect->bottom;
462 }
463
464 void InflateRect(int l, int t, int r, int b)
465 {
466 left -= l;
467 top -= t;
468 right += r;
469 bottom += b;
470 }
471
472 void DeflateRect(int x, int y)
473 {
474 ::InflateRect(this, -x, -y);
475 }
476
477 void DeflateRect(SIZE size)
478 {
479 ::InflateRect(this, -size.cx, -size.cy);
480 }
481
482 void DeflateRect(LPCRECT lpRect)
483 {
484 left += lpRect->left;
485 top += lpRect->top;
486 right -= lpRect->right;
487 bottom -= lpRect->bottom;
488 }
489
490 void DeflateRect(int l, int t, int r, int b)
491 {
492 left += l;
493 top += t;
494 right -= r;
495 bottom -= b;
496 }
497
498 void OffsetRect(int x, int y)
499 {
500 ::OffsetRect(this, x, y);
501 }
502 void OffsetRect(SIZE size)
503 {
504 ::OffsetRect(this, size.cx, size.cy);
505 }
506
507 void OffsetRect(POINT point)
508 {
509 ::OffsetRect(this, point.x, point.y);
510 }
511
512 void NormalizeRect()
513 {
514 int nTemp;
515 if (left > right)
516 {
517 nTemp = left;
518 left = right;
519 right = nTemp;
520 }
521 if (top > bottom)
522 {
523 nTemp = top;
524 top = bottom;
525 bottom = nTemp;
526 }
527 }
528
529 // absolute position of rectangle
530 void MoveToY(int y)
531 {
532 bottom = Height() + y;
533 top = y;
534 }
535
536 void MoveToX(int x)
537 {
538 right = Width() + x;
539 left = x;
540 }
541
542 void MoveToXY(int x, int y)
543 {
544 MoveToX(x);
545 MoveToY(y);
546 }
547
548 void MoveToXY(POINT pt)
549 {
550 MoveToX(pt.x);
551 MoveToY(pt.y);
552 }
553
554 // operations that fill '*this' with result
555 BOOL IntersectRect(LPCRECT lpRect1, LPCRECT lpRect2)
556 {
557 return ::IntersectRect(this, lpRect1, lpRect2);
558 }
559
560 BOOL UnionRect(LPCRECT lpRect1, LPCRECT lpRect2)
561 {
562 return ::UnionRect(this, lpRect1, lpRect2);
563 }
564
565 BOOL SubtractRect(LPCRECT lpRectSrc1, LPCRECT lpRectSrc2)
566 {
567 return ::SubtractRect(this, lpRectSrc1, lpRectSrc2);
568 }
569
570 // Additional Operations
571 void operator =(const RECT& srcRect)
572 {
573 ::CopyRect(this, &srcRect);
574 }
575
576 BOOL operator ==(const RECT& rect) const
577 {
578 return ::EqualRect(this, &rect);
579 }
580
581 BOOL operator !=(const RECT& rect) const
582 {
583 return !::EqualRect(this, &rect);
584 }
585
586 void operator +=(POINT point)
587 {
588 ::OffsetRect(this, point.x, point.y);
589 }
590
591 void operator +=(SIZE size)
592 {
593 ::OffsetRect(this, size.cx, size.cy);
594 }
595
596 void operator +=(LPCRECT lpRect)
597 {
598 InflateRect(lpRect);
599 }
600
601 void operator -=(POINT point)
602 {
603 ::OffsetRect(this, -point.x, -point.y);
604 }
605
606 void operator -=(SIZE size)
607 {
608 ::OffsetRect(this, -size.cx, -size.cy);
609 }
610
611 void operator -=(LPCRECT lpRect)
612 {
613 DeflateRect(lpRect);
614 }
615
616 void operator &=(const RECT& rect)
617 {
618 ::IntersectRect(this, this, &rect);
619 }
620
621 void operator |=(const RECT& rect)
622 {
623 ::UnionRect(this, this, &rect);
624 }
625
626 // Operators returning CRect values
627 CRect operator +(POINT pt) const
628 {
629 CRect rect(*this);
630 ::OffsetRect(&rect, pt.x, pt.y);
631 return rect;
632 }
633
634 CRect operator -(POINT pt) const
635 {
636 CRect rect(*this);
637 ::OffsetRect(&rect, -pt.x, -pt.y);
638 return rect;
639 }
640
641 CRect operator +(LPCRECT lpRect) const
642 {
643 CRect rect(this);
644 rect.InflateRect(lpRect);
645 return rect;
646 }
647
648 CRect operator +(SIZE size) const
649 {
650 CRect rect(*this);
651 ::OffsetRect(&rect, size.cx, size.cy);
652 return rect;
653 }
654
655 CRect operator -(SIZE size) const
656 {
657 CRect rect(*this);
658 ::OffsetRect(&rect, -size.cx, -size.cy);
659 return rect;
660 }
661
662 CRect operator -(LPCRECT lpRect) const
663 {
664 CRect rect(this);
665 rect.DeflateRect(lpRect);
666 return rect;
667 }
668
669 CRect operator &(const RECT& rect2) const
670 {
671 CRect rect;
672 ::IntersectRect(&rect, this, &rect2);
673 return rect;
674 }
675
676 CRect operator |(const RECT& rect2) const
677 {
678 CRect rect;
679 ::UnionRect(&rect, this, &rect2);
680 return rect;
681 }
682
683 CRect MulDiv(int nMultiplier, int nDivisor) const
684 {
685 return CRect(
686 ::MulDiv(left, nMultiplier, nDivisor),
687 ::MulDiv(top, nMultiplier, nDivisor),
688 ::MulDiv(right, nMultiplier, nDivisor),
689 ::MulDiv(bottom, nMultiplier, nDivisor));
690 }
691 };
692
693
694 // CSize implementation
695
696 inline CPoint CSize::operator +(POINT point) const
697 { return CPoint(cx + point.x, cy + point.y); }
698
699 inline CPoint CSize::operator -(POINT point) const
700 { return CPoint(cx - point.x, cy - point.y); }
701
702 inline CRect CSize::operator +(const RECT* lpRect) const
703 { return CRect(lpRect) + *this; }
704
705 inline CRect CSize::operator -(const RECT* lpRect) const
706 { return CRect(lpRect) - *this; }
707
708
709 // CPoint implementation
710
711 inline CRect CPoint::operator +(const RECT* lpRect) const
712 { return CRect(lpRect) + *this; }
713
714 inline CRect CPoint::operator -(const RECT* lpRect) const
715 { return CRect(lpRect) - *this; }
716
717 #endif // !_WTL_NO_WTYPES
718
719
720 // WTL::CSize or ATL::CSize scalar operators
721
722 #if !defined(_WTL_NO_SIZE_SCALAR) && (!defined(_WTL_NO_WTYPES) || defined(__ATLT YPES_H__))
723
724 template <class Num>
725 inline CSize operator *(SIZE s, Num n)
726 {
727 return CSize((int)(s.cx * n), (int)(s.cy * n));
728 };
729
730 template <class Num>
731 inline void operator *=(SIZE & s, Num n)
732 {
733 s = s * n;
734 };
735
736 template <class Num>
737 inline CSize operator /(SIZE s, Num n)
738 {
739 return CSize((int)(s.cx / n), (int)(s.cy / n));
740 };
741
742 template <class Num>
743 inline void operator /=(SIZE & s, Num n)
744 {
745 s = s / n;
746 };
747
748 #endif // !defined(_WTL_NO_SIZE_SCALAR) && (!defined(_WTL_NO_WTYPES) || defined( __ATLTYPES_H__))
749
750
751 ///////////////////////////////////////////////////////////////////////////////
752 // CString - String class
753
754 #ifndef _WTL_NO_CSTRING
755
756 struct CStringData
757 {
758 long nRefs; // reference count
759 int nDataLength;
760 int nAllocLength;
761 // TCHAR data[nAllocLength]
762
763 TCHAR* data()
764 { return (TCHAR*)(this + 1); }
765 };
766
767 // Globals
768
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) + si zeof(CStringData));
775
776
777 class CString
778 {
779 public:
780 // Constructors
781 CString()
782 {
783 Init();
784 }
785
786 CString(const CString& stringSrc)
787 {
788 ATLASSERT(stringSrc.GetData()->nRefs != 0);
789 if (stringSrc.GetData()->nRefs >= 0)
790 {
791 ATLASSERT(stringSrc.GetData() != _atltmpDataNil);
792 m_pchData = stringSrc.m_pchData;
793 InterlockedIncrement(&GetData()->nRefs);
794 }
795 else
796 {
797 Init();
798 *this = stringSrc.m_pchData;
799 }
800 }
801
802 CString(TCHAR ch, int nRepeat = 1)
803 {
804 ATLASSERT(!_istlead(ch)); // can't create a lead byte string
805 Init();
806 if (nRepeat >= 1)
807 {
808 if(AllocBuffer(nRepeat))
809 {
810 #ifdef _UNICODE
811 for (int i = 0; i < nRepeat; i++)
812 m_pchData[i] = ch;
813 #else
814 memset(m_pchData, ch, nRepeat);
815 #endif
816 }
817 }
818 }
819
820 CString(LPCTSTR lpsz)
821 {
822 Init();
823 if (lpsz != NULL && HIWORD(lpsz) == NULL)
824 {
825 UINT nID = LOWORD((DWORD_PTR)lpsz);
826 if (!LoadString(nID))
827 ATLTRACE2(atlTraceUI, 0, _T("Warning: implicit L oadString(%u) in CString failed\n"), nID);
828 }
829 else
830 {
831 int nLen = SafeStrlen(lpsz);
832 if (nLen != 0)
833 {
834 if(AllocBuffer(nLen))
835 SecureHelper::memcpy_x(m_pchData, (nLen + 1) * sizeof(TCHAR), lpsz, nLen * sizeof(TCHAR));
836 }
837 }
838 }
839
840 #ifdef _UNICODE
841 CString(LPCSTR lpsz)
842 {
843 Init();
844 #if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800)
845 int nSrcLen = (lpsz != NULL) ? ATL::lstrlenA(lpsz) : 0;
846 #else
847 int nSrcLen = (lpsz != NULL) ? lstrlenA(lpsz) : 0;
848 #endif
849 if (nSrcLen != 0)
850 {
851 if(AllocBuffer(nSrcLen))
852 {
853 _mbstowcsz(m_pchData, lpsz, nSrcLen + 1);
854 ReleaseBuffer();
855 }
856 }
857 }
858 #else // !_UNICODE
859 CString(LPCWSTR lpsz)
860 {
861 Init();
862 int nSrcLen = (lpsz != NULL) ? (int)wcslen(lpsz) : 0;
863 if (nSrcLen != 0)
864 {
865 if(AllocBuffer(nSrcLen * 2))
866 {
867 _wcstombsz(m_pchData, lpsz, (nSrcLen * 2) + 1);
868 ReleaseBuffer();
869 }
870 }
871 }
872 #endif // !_UNICODE
873
874 CString(LPCTSTR lpch, int nLength)
875 {
876 Init();
877 if (nLength != 0)
878 {
879 if(AllocBuffer(nLength))
880 SecureHelper::memcpy_x(m_pchData, (nLength + 1) * sizeof(TCHAR), lpch, nLength * sizeof(TCHAR));
881 }
882 }
883
884 #ifdef _UNICODE
885 CString(LPCSTR lpsz, int nLength)
886 {
887 Init();
888 if (nLength != 0)
889 {
890 if(AllocBuffer(nLength))
891 {
892 int n = ::MultiByteToWideChar(CP_ACP, 0, lpsz, n Length, m_pchData, nLength + 1);
893 ReleaseBuffer((n >= 0) ? n : -1);
894 }
895 }
896 }
897 #else // !_UNICODE
898 CString(LPCWSTR lpsz, int nLength)
899 {
900 Init();
901 if (nLength != 0)
902 {
903 if(((nLength * 2) > nLength) && AllocBuffer(nLength * 2) )
904 {
905 int n = ::WideCharToMultiByte(CP_ACP, 0, lpsz, n Length, m_pchData, (nLength * 2) + 1, NULL, NULL);
906 ReleaseBuffer((n >= 0) ? n : -1);
907 }
908 }
909 }
910 #endif // !_UNICODE
911
912 CString(const unsigned char* lpsz)
913 {
914 Init();
915 *this = (LPCSTR)lpsz;
916 }
917
918 // Attributes & Operations
919 int GetLength() const // as an array of characters
920 {
921 return GetData()->nDataLength;
922 }
923
924 BOOL IsEmpty() const
925 {
926 return GetData()->nDataLength == 0;
927 }
928
929 void Empty() // free up the data
930 {
931 if (GetData()->nDataLength == 0)
932 return;
933
934 if (GetData()->nRefs >= 0)
935 Release();
936 else
937 *this = _T("");
938
939 ATLASSERT(GetData()->nDataLength == 0);
940 ATLASSERT(GetData()->nRefs < 0 || GetData()->nAllocLength == 0);
941 }
942
943 TCHAR GetAt(int nIndex) const // 0 based
944 {
945 ATLASSERT(nIndex >= 0);
946 ATLASSERT(nIndex < GetData()->nDataLength);
947 return m_pchData[nIndex];
948 }
949
950 TCHAR operator [](int nIndex) const // same as GetAt
951 {
952 // same as GetAt
953 ATLASSERT(nIndex >= 0);
954 ATLASSERT(nIndex < GetData()->nDataLength);
955 return m_pchData[nIndex];
956 }
957
958 void SetAt(int nIndex, TCHAR ch)
959 {
960 ATLASSERT(nIndex >= 0);
961 ATLASSERT(nIndex < GetData()->nDataLength);
962
963 CopyBeforeWrite();
964 m_pchData[nIndex] = ch;
965 }
966
967 operator LPCTSTR() const // as a C string
968 {
969 return m_pchData;
970 }
971
972 // overloaded assignment
973 CString& operator =(const CString& stringSrc)
974 {
975 if (m_pchData != stringSrc.m_pchData)
976 {
977 if ((GetData()->nRefs < 0 && GetData() != _atltmpDataNil ) || stringSrc.GetData()->nRefs < 0)
978 {
979 // actual copy necessary since one of the string s is locked
980 AssignCopy(stringSrc.GetData()->nDataLength, str ingSrc.m_pchData);
981 }
982 else
983 {
984 // can just copy references around
985 Release();
986 ATLASSERT(stringSrc.GetData() != _atltmpDataNil) ;
987 m_pchData = stringSrc.m_pchData;
988 InterlockedIncrement(&GetData()->nRefs);
989 }
990 }
991 return *this;
992 }
993
994 CString& operator =(TCHAR ch)
995 {
996 ATLASSERT(!_istlead(ch)); // can't set single lead byte
997 AssignCopy(1, &ch);
998 return *this;
999 }
1000
1001 #ifdef _UNICODE
1002 CString& operator =(char ch)
1003 {
1004 *this = (TCHAR)ch;
1005 return *this;
1006 }
1007 #endif
1008
1009 CString& operator =(LPCTSTR lpsz)
1010 {
1011 ATLASSERT(lpsz == NULL || _IsValidString(lpsz));
1012 AssignCopy(SafeStrlen(lpsz), lpsz);
1013 return *this;
1014 }
1015
1016 #ifdef _UNICODE
1017 CString& operator =(LPCSTR lpsz)
1018 {
1019 #if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800)
1020 int nSrcLen = (lpsz != NULL) ? ATL::lstrlenA(lpsz) : 0;
1021 #else
1022 int nSrcLen = (lpsz != NULL) ? lstrlenA(lpsz) : 0;
1023 #endif
1024 if(AllocBeforeWrite(nSrcLen))
1025 {
1026 _mbstowcsz(m_pchData, lpsz, nSrcLen + 1);
1027 ReleaseBuffer();
1028 }
1029 return *this;
1030 }
1031 #else // !_UNICODE
1032 CString& operator =(LPCWSTR lpsz)
1033 {
1034 int nSrcLen = (lpsz != NULL) ? (int)wcslen(lpsz) : 0;
1035 if(AllocBeforeWrite(nSrcLen * 2))
1036 {
1037 _wcstombsz(m_pchData, lpsz, (nSrcLen * 2) + 1);
1038 ReleaseBuffer();
1039 }
1040 return *this;
1041 }
1042 #endif // !_UNICODE
1043
1044 CString& operator =(const unsigned char* lpsz)
1045 {
1046 *this = (LPCSTR)lpsz;
1047 return *this;
1048 }
1049
1050 // string concatenation
1051 CString& operator +=(const CString& string)
1052 {
1053 ConcatInPlace(string.GetData()->nDataLength, string.m_pchData);
1054 return *this;
1055 }
1056
1057 CString& operator +=(TCHAR ch)
1058 {
1059 ConcatInPlace(1, &ch);
1060 return *this;
1061 }
1062
1063 #ifdef _UNICODE
1064 CString& operator +=(char ch)
1065 {
1066 *this += (TCHAR)ch;
1067 return *this;
1068 }
1069 #endif
1070
1071 CString& operator +=(LPCTSTR lpsz)
1072 {
1073 ATLASSERT(lpsz == NULL || _IsValidString(lpsz));
1074 ConcatInPlace(SafeStrlen(lpsz), lpsz);
1075 return *this;
1076 }
1077
1078 friend CString __stdcall operator +(const CString& string1, const CStrin g& string2);
1079 friend CString __stdcall operator +(const CString& string, TCHAR ch);
1080 friend CString __stdcall operator +(TCHAR ch, const CString& string);
1081 #ifdef _UNICODE
1082 friend CString __stdcall operator +(const CString& string, char ch);
1083 friend CString __stdcall operator +(char ch, const CString& string);
1084 #endif
1085 friend CString __stdcall operator +(const CString& string, LPCTSTR lpsz) ;
1086 friend CString __stdcall operator +(LPCTSTR lpsz, const CString& string) ;
1087
1088 // string comparison
1089 int Compare(LPCTSTR lpsz) const // straight character (MBCS/Unicode aw are)
1090 {
1091 return _cstrcmp(m_pchData, lpsz);
1092 }
1093
1094 int CompareNoCase(LPCTSTR lpsz) const // ignore case (MBCS/Unicode awa re)
1095 {
1096 return _cstrcmpi(m_pchData, lpsz);
1097 }
1098
1099 #ifndef _WIN32_WCE
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
1103 {
1104 return _cstrcoll(m_pchData, lpsz);
1105 }
1106
1107 int CollateNoCase(LPCTSTR lpsz) const // ignore case
1108 {
1109 return _cstrcolli(m_pchData, lpsz);
1110 }
1111 #endif // !_WIN32_WCE
1112
1113 // simple sub-string extraction
1114 CString Mid(int nFirst, int nCount) const
1115 {
1116 // out-of-bounds requests return sensible things
1117 if (nFirst < 0)
1118 nFirst = 0;
1119 if (nCount < 0)
1120 nCount = 0;
1121
1122 if (nFirst + nCount > GetData()->nDataLength)
1123 nCount = GetData()->nDataLength - nFirst;
1124 if (nFirst > GetData()->nDataLength)
1125 nCount = 0;
1126
1127 CString dest;
1128 AllocCopy(dest, nCount, nFirst, 0);
1129 return dest;
1130 }
1131
1132 CString Mid(int nFirst) const
1133 {
1134 return Mid(nFirst, GetData()->nDataLength - nFirst);
1135 }
1136
1137 CString Left(int nCount) const
1138 {
1139 if (nCount < 0)
1140 nCount = 0;
1141 else if (nCount > GetData()->nDataLength)
1142 nCount = GetData()->nDataLength;
1143
1144 CString dest;
1145 AllocCopy(dest, nCount, 0, 0);
1146 return dest;
1147 }
1148
1149 CString Right(int nCount) const
1150 {
1151 if (nCount < 0)
1152 nCount = 0;
1153 else if (nCount > GetData()->nDataLength)
1154 nCount = GetData()->nDataLength;
1155
1156 CString dest;
1157 AllocCopy(dest, nCount, GetData()->nDataLength-nCount, 0);
1158 return dest;
1159 }
1160
1161 CString SpanIncluding(LPCTSTR lpszCharSet) const // strspn equivalent
1162 {
1163 ATLASSERT(_IsValidString(lpszCharSet));
1164 return Left(_cstrspn(m_pchData, lpszCharSet));
1165 }
1166
1167 CString SpanExcluding(LPCTSTR lpszCharSet) const // strcspn equivalent
1168 {
1169 ATLASSERT(_IsValidString(lpszCharSet));
1170 return Left(_cstrcspn(m_pchData, lpszCharSet));
1171 }
1172
1173 // upper/lower/reverse conversion
1174 void MakeUpper()
1175 {
1176 CopyBeforeWrite();
1177 CharUpper(m_pchData);
1178 }
1179
1180 void MakeLower()
1181 {
1182 CopyBeforeWrite();
1183 CharLower(m_pchData);
1184 }
1185
1186 void MakeReverse()
1187 {
1188 CopyBeforeWrite();
1189 _cstrrev(m_pchData);
1190 }
1191
1192 // trimming whitespace (either side)
1193 void TrimRight()
1194 {
1195 CopyBeforeWrite();
1196
1197 // find beginning of trailing spaces by starting at beginning (D BCS aware)
1198 LPTSTR lpsz = m_pchData;
1199 LPTSTR lpszLast = NULL;
1200 while (*lpsz != _T('\0'))
1201 {
1202 if (_cstrisspace(*lpsz))
1203 {
1204 if (lpszLast == NULL)
1205 lpszLast = lpsz;
1206 }
1207 else
1208 {
1209 lpszLast = NULL;
1210 }
1211 lpsz = ::CharNext(lpsz);
1212 }
1213
1214 if (lpszLast != NULL)
1215 {
1216 // truncate at trailing space start
1217 *lpszLast = _T('\0');
1218 GetData()->nDataLength = (int)(DWORD_PTR)(lpszLast - m_p chData);
1219 }
1220 }
1221
1222 void TrimLeft()
1223 {
1224 CopyBeforeWrite();
1225
1226 // find first non-space character
1227 LPCTSTR lpsz = m_pchData;
1228 while (_cstrisspace(*lpsz))
1229 lpsz = ::CharNext(lpsz);
1230
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;
1235 }
1236
1237 // remove continuous occurrences of chTarget starting from right
1238 void TrimRight(TCHAR chTarget)
1239 {
1240 // find beginning of trailing matches
1241 // by starting at beginning (DBCS aware)
1242
1243 CopyBeforeWrite();
1244 LPTSTR lpsz = m_pchData;
1245 LPTSTR lpszLast = NULL;
1246
1247 while (*lpsz != _T('\0'))
1248 {
1249 if (*lpsz == chTarget)
1250 {
1251 if (lpszLast == NULL)
1252 lpszLast = lpsz;
1253 }
1254 else
1255 lpszLast = NULL;
1256 lpsz = ::CharNext(lpsz);
1257 }
1258
1259 if (lpszLast != NULL)
1260 {
1261 // truncate at left-most matching character
1262 *lpszLast = _T('\0');
1263 GetData()->nDataLength = (int)(DWORD_PTR)(lpszLast - m_p chData);
1264 }
1265 }
1266
1267 // remove continuous occcurrences of characters in passed string, starti ng from right
1268 void TrimRight(LPCTSTR lpszTargetList)
1269 {
1270 // find beginning of trailing matches by starting at beginning ( DBCS aware)
1271
1272 CopyBeforeWrite();
1273 LPTSTR lpsz = m_pchData;
1274 LPTSTR lpszLast = NULL;
1275
1276 while (*lpsz != _T('\0'))
1277 {
1278 TCHAR* pNext = ::CharNext(lpsz);
1279 if(pNext > lpsz + 1)
1280 {
1281 if (_cstrchr_db(lpszTargetList, *lpsz, *(lpsz + 1)) != NULL)
1282 {
1283 if (lpszLast == NULL)
1284 lpszLast = lpsz;
1285 }
1286 else
1287 {
1288 lpszLast = NULL;
1289 }
1290 }
1291 else
1292 {
1293 if (_cstrchr(lpszTargetList, *lpsz) != NULL)
1294 {
1295 if (lpszLast == NULL)
1296 lpszLast = lpsz;
1297 }
1298 else
1299 {
1300 lpszLast = NULL;
1301 }
1302 }
1303
1304 lpsz = pNext;
1305 }
1306
1307 if (lpszLast != NULL)
1308 {
1309 // truncate at left-most matching character
1310 *lpszLast = _T('\0');
1311 GetData()->nDataLength = (int)(DWORD_PTR)(lpszLast - m_p chData);
1312 }
1313 }
1314
1315 // remove continuous occurrences of chTarget starting from left
1316 void TrimLeft(TCHAR chTarget)
1317 {
1318 // find first non-matching character
1319
1320 CopyBeforeWrite();
1321 LPCTSTR lpsz = m_pchData;
1322
1323 while (chTarget == *lpsz)
1324 lpsz = ::CharNext(lpsz);
1325
1326 if (lpsz != m_pchData)
1327 {
1328 // fix up data and length
1329 int nDataLength = GetData()->nDataLength - (int)(DWORD_P TR)(lpsz - m_pchData);
1330 SecureHelper::memmove_x(m_pchData, (GetData()->nAllocLen gth + 1) * sizeof(TCHAR), lpsz, (nDataLength + 1) * sizeof(TCHAR));
1331 GetData()->nDataLength = nDataLength;
1332 }
1333 }
1334
1335 // remove continuous occcurrences of characters in passed string, starti ng from left
1336 void TrimLeft(LPCTSTR lpszTargets)
1337 {
1338 // if we're not trimming anything, we're not doing any work
1339 if (SafeStrlen(lpszTargets) == 0)
1340 return;
1341
1342 CopyBeforeWrite();
1343 LPCTSTR lpsz = m_pchData;
1344
1345 while (*lpsz != _T('\0'))
1346 {
1347 TCHAR* pNext = ::CharNext(lpsz);
1348 if(pNext > lpsz + 1)
1349 {
1350 if (_cstrchr_db(lpszTargets, *lpsz, *(lpsz + 1)) == NULL)
1351 break;
1352 }
1353 else
1354 {
1355 if (_cstrchr(lpszTargets, *lpsz) == NULL)
1356 break;
1357 }
1358 lpsz = pNext;
1359 }
1360
1361 if (lpsz != m_pchData)
1362 {
1363 // fix up data and length
1364 int nDataLength = GetData()->nDataLength - (int)(DWORD_P TR)(lpsz - m_pchData);
1365 SecureHelper::memmove_x(m_pchData, (GetData()->nAllocLen gth + 1) * sizeof(TCHAR), lpsz, (nDataLength + 1) * sizeof(TCHAR));
1366 GetData()->nDataLength = nDataLength;
1367 }
1368 }
1369
1370 // advanced manipulation
1371 // replace occurrences of chOld with chNew
1372 int Replace(TCHAR chOld, TCHAR chNew)
1373 {
1374 int nCount = 0;
1375
1376 // short-circuit the nop case
1377 if (chOld != chNew)
1378 {
1379 // otherwise modify each character that matches in the s tring
1380 CopyBeforeWrite();
1381 LPTSTR psz = m_pchData;
1382 LPTSTR pszEnd = psz + GetData()->nDataLength;
1383 while (psz < pszEnd)
1384 {
1385 // replace instances of the specified character only
1386 if (*psz == chOld)
1387 {
1388 *psz = chNew;
1389 nCount++;
1390 }
1391 psz = ::CharNext(psz);
1392 }
1393 }
1394 return nCount;
1395 }
1396
1397 // replace occurrences of substring lpszOld with lpszNew;
1398 // empty lpszNew removes instances of lpszOld
1399 int Replace(LPCTSTR lpszOld, LPCTSTR lpszNew)
1400 {
1401 // can't have empty or NULL lpszOld
1402
1403 int nSourceLen = SafeStrlen(lpszOld);
1404 if (nSourceLen == 0)
1405 return 0;
1406 int nReplacementLen = SafeStrlen(lpszNew);
1407
1408 // loop once to figure out the size of the result string
1409 int nCount = 0;
1410 LPTSTR lpszStart = m_pchData;
1411 LPTSTR lpszEnd = m_pchData + GetData()->nDataLength;
1412 LPTSTR lpszTarget = NULL;
1413 while (lpszStart < lpszEnd)
1414 {
1415 while ((lpszTarget = (TCHAR*)_cstrstr(lpszStart, lpszOld )) != NULL)
1416 {
1417 nCount++;
1418 lpszStart = lpszTarget + nSourceLen;
1419 }
1420 lpszStart += lstrlen(lpszStart) + 1;
1421 }
1422
1423 // if any changes were made, make them
1424 if (nCount > 0)
1425 {
1426 CopyBeforeWrite();
1427
1428 // if the buffer is too small, just allocate a new buffe r (slow but sure)
1429 int nOldLength = GetData()->nDataLength;
1430 int nNewLength = nOldLength + (nReplacementLen - nSourc eLen) * nCount;
1431 if (GetData()->nAllocLength < nNewLength || GetData()->n Refs > 1)
1432 {
1433 CStringData* pOldData = GetData();
1434 LPTSTR pstr = m_pchData;
1435 if(!AllocBuffer(nNewLength))
1436 return -1;
1437 SecureHelper::memcpy_x(m_pchData, (nNewLength + 1) * sizeof(TCHAR), pstr, pOldData->nDataLength * sizeof(TCHAR));
1438 CString::Release(pOldData);
1439 }
1440 // else, we just do it in-place
1441 lpszStart = m_pchData;
1442 lpszEnd = m_pchData + GetData()->nDataLength;
1443
1444 // loop again to actually do the work
1445 while (lpszStart < lpszEnd)
1446 {
1447 while ((lpszTarget = (TCHAR*)_cstrstr(lpszStart, lpszOld)) != NULL)
1448 {
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 + nRe placementLen, (cchBuffLen - nReplacementLen + 1) * sizeof(TCHAR), lpszTarget + n SourceLen, nBalance * sizeof(TCHAR));
1452 SecureHelper::memcpy_x(lpszTarget, (cchB uffLen + 1) * sizeof(TCHAR), lpszNew, nReplacementLen * sizeof(TCHAR));
1453 lpszStart = lpszTarget + nReplacementLen ;
1454 lpszStart[nBalance] = _T('\0');
1455 nOldLength += (nReplacementLen - nSource Len);
1456 }
1457 lpszStart += lstrlen(lpszStart) + 1;
1458 }
1459 ATLASSERT(m_pchData[nNewLength] == _T('\0'));
1460 GetData()->nDataLength = nNewLength;
1461 }
1462
1463 return nCount;
1464 }
1465
1466 // remove occurrences of chRemove
1467 int Remove(TCHAR chRemove)
1468 {
1469 CopyBeforeWrite();
1470
1471 LPTSTR pstrSource = m_pchData;
1472 LPTSTR pstrDest = m_pchData;
1473 LPTSTR pstrEnd = m_pchData + GetData()->nDataLength;
1474
1475 while (pstrSource < pstrEnd)
1476 {
1477 if (*pstrSource != chRemove)
1478 {
1479 *pstrDest = *pstrSource;
1480 pstrDest = ::CharNext(pstrDest);
1481 }
1482 pstrSource = ::CharNext(pstrSource);
1483 }
1484 *pstrDest = _T('\0');
1485 int nCount = (int)(DWORD_PTR)(pstrSource - pstrDest);
1486 GetData()->nDataLength -= nCount;
1487
1488 return nCount;
1489 }
1490
1491 // insert character at zero-based index; concatenates if index is past e nd of string
1492 int Insert(int nIndex, TCHAR ch)
1493 {
1494 CopyBeforeWrite();
1495
1496 if (nIndex < 0)
1497 nIndex = 0;
1498
1499 int nNewLength = GetData()->nDataLength;
1500 if (nIndex > nNewLength)
1501 nIndex = nNewLength;
1502 nNewLength++;
1503
1504 if (GetData()->nAllocLength < nNewLength)
1505 {
1506 CStringData* pOldData = GetData();
1507 LPTSTR pstr = m_pchData;
1508 if(!AllocBuffer(nNewLength))
1509 return -1;
1510 SecureHelper::memcpy_x(m_pchData, (nNewLength + 1) * siz eof(TCHAR), pstr, (pOldData->nDataLength + 1) * sizeof(TCHAR));
1511 CString::Release(pOldData);
1512 }
1513
1514 // move existing bytes down
1515 SecureHelper::memmove_x(m_pchData + nIndex + 1, (GetData()->nAll ocLength - nIndex) * sizeof(TCHAR), m_pchData + nIndex, (nNewLength - nIndex) * sizeof(TCHAR));
1516 m_pchData[nIndex] = ch;
1517 GetData()->nDataLength = nNewLength;
1518
1519 return nNewLength;
1520 }
1521
1522 // insert substring at zero-based index; concatenates if index is past e nd of string
1523 int Insert(int nIndex, LPCTSTR pstr)
1524 {
1525 if (nIndex < 0)
1526 nIndex = 0;
1527
1528 int nInsertLength = SafeStrlen(pstr);
1529 int nNewLength = GetData()->nDataLength;
1530 if (nInsertLength > 0)
1531 {
1532 CopyBeforeWrite();
1533 if (nIndex > nNewLength)
1534 nIndex = nNewLength;
1535 nNewLength += nInsertLength;
1536
1537 if (GetData()->nAllocLength < nNewLength)
1538 {
1539 CStringData* pOldData = GetData();
1540 LPTSTR pstr = m_pchData;
1541 if(!AllocBuffer(nNewLength))
1542 return -1;
1543 SecureHelper::memcpy_x(m_pchData, (nNewLength + 1) * sizeof(TCHAR), pstr, (pOldData->nDataLength + 1) * sizeof(TCHAR));
1544 CString::Release(pOldData);
1545 }
1546
1547 // move existing bytes down
1548 SecureHelper::memmove_x(m_pchData + nIndex + nInsertLeng th, (GetData()->nAllocLength + 1 - nIndex - nInsertLength) * sizeof(TCHAR), m_pc hData + nIndex, (nNewLength - nIndex - nInsertLength + 1) * sizeof(TCHAR));
1549 SecureHelper::memcpy_x(m_pchData + nIndex, (GetData()->n AllocLength + 1 - nIndex) * sizeof(TCHAR), pstr, nInsertLength * sizeof(TCHAR));
1550 GetData()->nDataLength = nNewLength;
1551 }
1552
1553 return nNewLength;
1554 }
1555
1556 // delete nCount characters starting at zero-based index
1557 int Delete(int nIndex, int nCount = 1)
1558 {
1559 if (nIndex < 0)
1560 nIndex = 0;
1561 int nLength = GetData()->nDataLength;
1562 if (nCount > 0 && nIndex < nLength)
1563 {
1564 if((nIndex + nCount) > nLength)
1565 nCount = nLength - nIndex;
1566 CopyBeforeWrite();
1567 int nBytesToCopy = nLength - (nIndex + nCount) + 1;
1568
1569 SecureHelper::memmove_x(m_pchData + nIndex, (GetData()-> nAllocLength + 1 - nIndex) * sizeof(TCHAR), m_pchData + nIndex + nCount, nBytesT oCopy * sizeof(TCHAR));
1570 nLength -= nCount;
1571 GetData()->nDataLength = nLength;
1572 }
1573
1574 return nLength;
1575 }
1576
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
1580 {
1581 return Find(ch, 0);
1582 }
1583
1584 int ReverseFind(TCHAR ch) const
1585 {
1586 // find last single character
1587 LPCTSTR lpsz = _cstrrchr(m_pchData, (_TUCHAR)ch);
1588
1589 // return -1 if not found, distance from beginning otherwise
1590 return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
1591 }
1592
1593 int Find(TCHAR ch, int nStart) const // starting at index
1594 {
1595 int nLength = GetData()->nDataLength;
1596 if (nStart < 0 || nStart >= nLength)
1597 return -1;
1598
1599 // find first single character
1600 LPCTSTR lpsz = _cstrchr(m_pchData + nStart, (_TUCHAR)ch);
1601
1602 // return -1 if not found and index otherwise
1603 return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
1604 }
1605
1606 int FindOneOf(LPCTSTR lpszCharSet) const
1607 {
1608 ATLASSERT(_IsValidString(lpszCharSet));
1609 LPCTSTR lpsz = _cstrpbrk(m_pchData, lpszCharSet);
1610 return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
1611 }
1612
1613 // look for a specific sub-string
1614 // find a sub-string (like strstr)
1615 int Find(LPCTSTR lpszSub) const // like "C" strstr
1616 {
1617 return Find(lpszSub, 0);
1618 }
1619
1620 int Find(LPCTSTR lpszSub, int nStart) const // starting at index
1621 {
1622 ATLASSERT(_IsValidString(lpszSub));
1623
1624 int nLength = GetData()->nDataLength;
1625 if (nStart < 0 || nStart > nLength)
1626 return -1;
1627
1628 // find first matching substring
1629 LPCTSTR lpsz = _cstrstr(m_pchData + nStart, lpszSub);
1630
1631 // return -1 for not found, distance from beginning otherwise
1632 return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
1633 }
1634
1635 // Concatentation for non strings
1636 CString& Append(int n)
1637 {
1638 const int cchBuff = 12;
1639 TCHAR szBuffer[cchBuff] = { 0 };
1640 SecureHelper::wsprintf_x(szBuffer, cchBuff, _T("%d"), n);
1641 ConcatInPlace(SafeStrlen(szBuffer), szBuffer);
1642 return *this;
1643 }
1644
1645 // simple formatting
1646 // formatting (using wsprintf style formatting)
1647 BOOL __cdecl Format(LPCTSTR lpszFormat, ...)
1648 {
1649 ATLASSERT(_IsValidString(lpszFormat));
1650
1651 va_list argList;
1652 va_start(argList, lpszFormat);
1653 BOOL bRet = FormatV(lpszFormat, argList);
1654 va_end(argList);
1655 return bRet;
1656 }
1657
1658 BOOL __cdecl Format(UINT nFormatID, ...)
1659 {
1660 CString strFormat;
1661 BOOL bRet = strFormat.LoadString(nFormatID);
1662 ATLASSERT(bRet != 0);
1663
1664 va_list argList;
1665 va_start(argList, nFormatID);
1666 bRet = FormatV(strFormat, argList);
1667 va_end(argList);
1668 return bRet;
1669 }
1670
1671 BOOL FormatV(LPCTSTR lpszFormat, va_list argList)
1672 {
1673 ATLASSERT(_IsValidString(lpszFormat));
1674
1675 enum _FormatModifiers
1676 {
1677 FORCE_ANSI = 0x10000,
1678 FORCE_UNICODE = 0x20000,
1679 FORCE_INT64 = 0x40000
1680 };
1681
1682 va_list argListSave = argList;
1683
1684 // make a guess at the maximum length of the resulting string
1685 int nMaxLen = 0;
1686 for (LPCTSTR lpsz = lpszFormat; *lpsz != _T('\0'); lpsz = ::Char Next(lpsz))
1687 {
1688 // handle '%' character, but watch out for '%%'
1689 if (*lpsz != _T('%') || *(lpsz = ::CharNext(lpsz)) == _T ('%'))
1690 {
1691 nMaxLen += (int)(::CharNext(lpsz) - lpsz);
1692 continue;
1693 }
1694
1695 int nItemLen = 0;
1696
1697 // handle '%' character with format
1698 int nWidth = 0;
1699 for (; *lpsz != _T('\0'); lpsz = ::CharNext(lpsz))
1700 {
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(' '))
1707 ;
1708 else // hit non-flag character
1709 break;
1710 }
1711 // get width and skip it
1712 if (nWidth == 0)
1713 {
1714 // width indicated by
1715 nWidth = _cstrtoi(lpsz);
1716 for (; *lpsz != _T('\0') && _cstrisdigit(*lpsz); lpsz = ::CharNext(lpsz))
1717 ;
1718 }
1719 ATLASSERT(nWidth >= 0);
1720
1721 int nPrecision = 0;
1722 if (*lpsz == _T('.'))
1723 {
1724 // skip past '.' separator (width.precision)
1725 lpsz = ::CharNext(lpsz);
1726
1727 // get precision and skip it
1728 if (*lpsz == _T('*'))
1729 {
1730 nPrecision = va_arg(argList, int);
1731 lpsz = ::CharNext(lpsz);
1732 }
1733 else
1734 {
1735 nPrecision = _cstrtoi(lpsz);
1736 for (; *lpsz != _T('\0') && _cstrisdigit (*lpsz); lpsz = ::CharNext(lpsz))
1737 ;
1738 }
1739 ATLASSERT(nPrecision >= 0);
1740 }
1741
1742 // should be on type modifier or specifier
1743 int nModifier = 0;
1744 if(lpsz[0] == _T('I') && lpsz[1] == _T('6') && lpsz[2] = = _T('4'))
1745 {
1746 lpsz += 3;
1747 nModifier = FORCE_INT64;
1748 }
1749 else
1750 {
1751 switch (*lpsz)
1752 {
1753 // modifiers that affect size
1754 case _T('h'):
1755 nModifier = FORCE_ANSI;
1756 lpsz = ::CharNext(lpsz);
1757 break;
1758 case _T('l'):
1759 nModifier = FORCE_UNICODE;
1760 lpsz = ::CharNext(lpsz);
1761 break;
1762
1763 // modifiers that do not affect size
1764 case _T('F'):
1765 case _T('N'):
1766 case _T('L'):
1767 lpsz = ::CharNext(lpsz);
1768 break;
1769 }
1770 }
1771
1772 // now should be on specifier
1773 switch (*lpsz | nModifier)
1774 {
1775 // single characters
1776 case _T('c'):
1777 case _T('C'):
1778 nItemLen = 2;
1779 va_arg(argList, TCHAR);
1780 break;
1781 case _T('c') | FORCE_ANSI:
1782 case _T('C') | FORCE_ANSI:
1783 nItemLen = 2;
1784 va_arg(argList, char);
1785 break;
1786 case _T('c') | FORCE_UNICODE:
1787 case _T('C') | FORCE_UNICODE:
1788 nItemLen = 2;
1789 va_arg(argList, WCHAR);
1790 break;
1791
1792 // strings
1793 case _T('s'):
1794 {
1795 LPCTSTR pstrNextArg = va_arg(argList, LPCTSTR);
1796 if (pstrNextArg == NULL)
1797 {
1798 nItemLen = 6; // "(null)"
1799 }
1800 else
1801 {
1802 nItemLen = lstrlen(pstrNextArg);
1803 nItemLen = __max(1, nItemLen);
1804 }
1805 break;
1806 }
1807
1808 case _T('S'):
1809 {
1810 #ifndef _UNICODE
1811 LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
1812 if (pstrNextArg == NULL)
1813 {
1814 nItemLen = 6; // "(null)"
1815 }
1816 else
1817 {
1818 nItemLen = (int)wcslen(pstrNextArg);
1819 nItemLen = __max(1, nItemLen);
1820 }
1821 #else // _UNICODE
1822 LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
1823 if (pstrNextArg == NULL)
1824 {
1825 nItemLen = 6; // "(null)"
1826 }
1827 else
1828 {
1829 #if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800)
1830 nItemLen = ATL::lstrlenA(pstrNextArg);
1831 #else
1832 nItemLen = lstrlenA(pstrNextArg);
1833 #endif
1834 nItemLen = __max(1, nItemLen);
1835 }
1836 #endif // _UNICODE
1837 break;
1838 }
1839
1840 case _T('s') | FORCE_ANSI:
1841 case _T('S') | FORCE_ANSI:
1842 {
1843 LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
1844 if (pstrNextArg == NULL)
1845 {
1846 nItemLen = 6; // "(null)"
1847 }
1848 else
1849 {
1850 #if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800)
1851 nItemLen = ATL::lstrlenA(pstrNextArg);
1852 #else
1853 nItemLen = lstrlenA(pstrNextArg);
1854 #endif
1855 nItemLen = __max(1, nItemLen);
1856 }
1857 break;
1858 }
1859
1860 case _T('s') | FORCE_UNICODE:
1861 case _T('S') | FORCE_UNICODE:
1862 {
1863 LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
1864 if (pstrNextArg == NULL)
1865 {
1866 nItemLen = 6; // "(null)"
1867 }
1868 else
1869 {
1870 nItemLen = (int)wcslen(pstrNextArg);
1871 nItemLen = __max(1, nItemLen);
1872 }
1873 break;
1874 }
1875 }
1876
1877 // adjust nItemLen for strings
1878 if (nItemLen != 0)
1879 {
1880 nItemLen = __max(nItemLen, nWidth);
1881 if (nPrecision != 0)
1882 nItemLen = __min(nItemLen, nPrecision);
1883 }
1884 else
1885 {
1886 switch (*lpsz)
1887 {
1888 // integers
1889 case _T('d'):
1890 case _T('i'):
1891 case _T('u'):
1892 case _T('x'):
1893 case _T('X'):
1894 case _T('o'):
1895 if (nModifier & FORCE_INT64)
1896 va_arg(argList, __int64);
1897 else
1898 va_arg(argList, int);
1899 nItemLen = 32;
1900 nItemLen = __max(nItemLen, nWidth + nPre cision);
1901 break;
1902
1903 #ifndef _ATL_USE_CSTRING_FLOAT
1904 case _T('e'):
1905 case _T('E'):
1906 case _T('f'):
1907 case _T('g'):
1908 case _T('G'):
1909 ATLASSERT(!"Floating point (%%e, %%E, %% f, %%g, and %%G) is not supported by the WTL::CString class.");
1910 #ifndef _DEBUG
1911 ::OutputDebugString(_T("Floating point ( %%e, %%f, %%g, and %%G) is not supported by the WTL::CString class."));
1912 #ifndef _WIN32_WCE
1913 ::DebugBreak();
1914 #else // CE specific
1915 DebugBreak();
1916 #endif // _WIN32_WCE
1917 #endif // !_DEBUG
1918 break;
1919 #else // _ATL_USE_CSTRING_FLOAT
1920 case _T('e'):
1921 case _T('E'):
1922 case _T('g'):
1923 case _T('G'):
1924 va_arg(argList, double);
1925 nItemLen = 128;
1926 nItemLen = __max(nItemLen, nWidth + nPre cision);
1927 break;
1928 case _T('f'):
1929 {
1930 double f = va_arg(argList, doubl e);
1931 // 312 == strlen("-1+(309 zeroes ).")
1932 // 309 zeroes == max precision o f a double
1933 // 6 == adjustment in case preci sion is not specified,
1934 // which means that the precis ion defaults to 6
1935 int cchLen = __max(nWidth, 312 + nPrecision + 6);
1936 CTempBuffer<TCHAR, _WTL_STACK_AL LOC_THRESHOLD> buff;
1937 LPTSTR pszTemp = buff.Allocate(c chLen);
1938 if(pszTemp != NULL)
1939 {
1940 SecureHelper::sprintf_x( pszTemp, cchLen, _T("%*.*f"), nWidth, nPrecision + 6, f);
1941 nItemLen = (int)_tcslen( pszTemp);
1942 }
1943 else
1944 {
1945 nItemLen = cchLen;
1946 }
1947 }
1948 break;
1949 #endif // _ATL_USE_CSTRING_FLOAT
1950
1951 case _T('p'):
1952 va_arg(argList, void*);
1953 nItemLen = 32;
1954 nItemLen = __max(nItemLen, nWidth + nPre cision);
1955 break;
1956
1957 // no output
1958 case _T('n'):
1959 va_arg(argList, int*);
1960 break;
1961
1962 default:
1963 ATLASSERT(FALSE); // unknown formatting option
1964 }
1965 }
1966
1967 // adjust nMaxLen for output nItemLen
1968 nMaxLen += nItemLen;
1969 }
1970
1971 if(GetBuffer(nMaxLen) == NULL)
1972 return FALSE;
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
1978 nRet; // ref
1979 ATLASSERT(nRet <= GetAllocLength());
1980 ReleaseBuffer();
1981
1982 va_end(argListSave);
1983 return TRUE;
1984 }
1985
1986 // formatting for localization (uses FormatMessage API)
1987 // formatting (using FormatMessage style formatting)
1988 BOOL __cdecl FormatMessage(LPCTSTR lpszFormat, ...)
1989 {
1990 // format message into temporary buffer lpszTemp
1991 va_list argList;
1992 va_start(argList, lpszFormat);
1993 LPTSTR lpszTemp;
1994 BOOL bRet = TRUE;
1995
1996 if (::FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ ALLOCATE_BUFFER,
1997 lpszFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList ) == 0 || lpszTemp == NULL)
1998 bRet = FALSE;
1999
2000 // assign lpszTemp into the resulting string and free the tempor ary
2001 *this = lpszTemp;
2002 LocalFree(lpszTemp);
2003 va_end(argList);
2004 return bRet;
2005 }
2006
2007 BOOL __cdecl FormatMessage(UINT nFormatID, ...)
2008 {
2009 // get format string from string table
2010 CString strFormat;
2011 BOOL bRetTmp = strFormat.LoadString(nFormatID);
2012 bRetTmp; // ref
2013 ATLASSERT(bRetTmp != 0);
2014
2015 // format message into temporary buffer lpszTemp
2016 va_list argList;
2017 va_start(argList, nFormatID);
2018 LPTSTR lpszTemp;
2019 BOOL bRet = TRUE;
2020
2021 if (::FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ ALLOCATE_BUFFER,
2022 strFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0 || lpszTemp == NULL)
2023 bRet = FALSE;
2024
2025 // assign lpszTemp into the resulting string and free lpszTemp
2026 *this = lpszTemp;
2027 LocalFree(lpszTemp);
2028 va_end(argList);
2029 return bRet;
2030 }
2031
2032 // Windows support
2033 BOOL LoadString(UINT nID) // load from string resource (255 chars max. )
2034 {
2035 #ifdef _UNICODE
2036 const int CHAR_FUDGE = 1; // one TCHAR unused is good enough
2037 #else
2038 const int CHAR_FUDGE = 2; // two BYTES unused for case of DBC last char
2039 #endif
2040
2041 // try fixed buffer first (to avoid wasting space in the heap)
2042 TCHAR szTemp[256];
2043 int nCount = sizeof(szTemp) / sizeof(szTemp[0]);
2044 int nLen = _LoadString(nID, szTemp, nCount);
2045 if (nCount - nLen > CHAR_FUDGE)
2046 {
2047 *this = szTemp;
2048 return (nLen > 0);
2049 }
2050
2051 // try buffer size of 512, then larger size until entire string is retrieved
2052 int nSize = 256;
2053 do
2054 {
2055 nSize += 256;
2056 LPTSTR lpstr = GetBuffer(nSize - 1);
2057 if(lpstr == NULL)
2058 {
2059 nLen = 0;
2060 break;
2061 }
2062 nLen = _LoadString(nID, lpstr, nSize);
2063 } while (nSize - nLen <= CHAR_FUDGE);
2064 ReleaseBuffer();
2065
2066 return (nLen > 0);
2067 }
2068
2069 #ifndef _UNICODE
2070 // ANSI <-> OEM support (convert string in place)
2071 void AnsiToOem()
2072 {
2073 CopyBeforeWrite();
2074 ::AnsiToOem(m_pchData, m_pchData);
2075 }
2076
2077 void OemToAnsi()
2078 {
2079 CopyBeforeWrite();
2080 ::OemToAnsi(m_pchData, m_pchData);
2081 }
2082 #endif
2083
2084 #ifndef _ATL_NO_COM
2085 // OLE BSTR support (use for OLE automation)
2086 BSTR AllocSysString() const
2087 {
2088 #if defined(_UNICODE) || defined(OLE2ANSI)
2089 BSTR bstr = ::SysAllocStringLen(m_pchData, GetData()->nDataLengt h);
2090 #else
2091 int nLen = MultiByteToWideChar(CP_ACP, 0, m_pchData,
2092 GetData()->nDataLength, NULL, NULL);
2093 BSTR bstr = ::SysAllocStringLen(NULL, nLen);
2094 if(bstr != NULL)
2095 MultiByteToWideChar(CP_ACP, 0, m_pchData, GetData()->nDa taLength, bstr, nLen);
2096 #endif
2097 return bstr;
2098 }
2099
2100 BSTR SetSysString(BSTR* pbstr) const
2101 {
2102 #if defined(_UNICODE) || defined(OLE2ANSI)
2103 ::SysReAllocStringLen(pbstr, m_pchData, GetData()->nDataLength);
2104 #else
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()->nDa taLength, *pbstr, nLen);
2109 #endif
2110 ATLASSERT(*pbstr != NULL);
2111 return *pbstr;
2112 }
2113 #endif // !_ATL_NO_COM
2114
2115 // Access to string implementation buffer as "C" character array
2116 LPTSTR GetBuffer(int nMinBufLength)
2117 {
2118 ATLASSERT(nMinBufLength >= 0);
2119
2120 if (GetData()->nRefs > 1 || nMinBufLength > GetData()->nAllocLen gth)
2121 {
2122 // we have to grow the buffer
2123 CStringData* pOldData = GetData();
2124 int nOldLen = GetData()->nDataLength; // AllocBuffer w ill tromp it
2125 if (nMinBufLength < nOldLen)
2126 nMinBufLength = nOldLen;
2127
2128 if(!AllocBuffer(nMinBufLength))
2129 return NULL;
2130
2131 SecureHelper::memcpy_x(m_pchData, (nMinBufLength + 1) * sizeof(TCHAR), pOldData->data(), (nOldLen + 1) * sizeof(TCHAR));
2132 GetData()->nDataLength = nOldLen;
2133 CString::Release(pOldData);
2134 }
2135 ATLASSERT(GetData()->nRefs <= 1);
2136
2137 // return a pointer to the character storage for this string
2138 ATLASSERT(m_pchData != NULL);
2139 return m_pchData;
2140 }
2141
2142 void ReleaseBuffer(int nNewLength = -1)
2143 {
2144 CopyBeforeWrite(); // just in case GetBuffer was not called
2145
2146 if (nNewLength == -1)
2147 nNewLength = lstrlen(m_pchData); // zero terminated
2148
2149 ATLASSERT(nNewLength <= GetData()->nAllocLength);
2150 GetData()->nDataLength = nNewLength;
2151 m_pchData[nNewLength] = _T('\0');
2152 }
2153
2154 LPTSTR GetBufferSetLength(int nNewLength)
2155 {
2156 ATLASSERT(nNewLength >= 0);
2157
2158 if(GetBuffer(nNewLength) == NULL)
2159 return NULL;
2160
2161 GetData()->nDataLength = nNewLength;
2162 m_pchData[nNewLength] = _T('\0');
2163 return m_pchData;
2164 }
2165
2166 void FreeExtra()
2167 {
2168 ATLASSERT(GetData()->nDataLength <= GetData()->nAllocLength);
2169 if (GetData()->nDataLength != GetData()->nAllocLength)
2170 {
2171 CStringData* pOldData = GetData();
2172 if(AllocBuffer(GetData()->nDataLength))
2173 {
2174 SecureHelper::memcpy_x(m_pchData, (GetData()->nA llocLength + 1) * sizeof(TCHAR), pOldData->data(), pOldData->nDataLength * sizeo f(TCHAR));
2175 ATLASSERT(m_pchData[GetData()->nDataLength] == _ T('\0'));
2176 CString::Release(pOldData);
2177 }
2178 }
2179 ATLASSERT(GetData() != NULL);
2180 }
2181
2182 // Use LockBuffer/UnlockBuffer to turn refcounting off
2183 LPTSTR LockBuffer()
2184 {
2185 LPTSTR lpsz = GetBuffer(0);
2186 if(lpsz != NULL)
2187 GetData()->nRefs = -1;
2188 return lpsz;
2189 }
2190
2191 void UnlockBuffer()
2192 {
2193 ATLASSERT(GetData()->nRefs == -1);
2194 if (GetData() != _atltmpDataNil)
2195 GetData()->nRefs = 1;
2196 }
2197
2198 // Implementation
2199 public:
2200 ~CString() // free any attached data
2201 {
2202 if (GetData() != _atltmpDataNil)
2203 {
2204 if (InterlockedDecrement(&GetData()->nRefs) <= 0)
2205 delete[] (BYTE*)GetData();
2206 }
2207 }
2208
2209 int GetAllocLength() const
2210 {
2211 return GetData()->nAllocLength;
2212 }
2213
2214 static BOOL __stdcall _IsValidString(LPCTSTR lpsz, int /*nLength*/ = -1)
2215 {
2216 return (lpsz != NULL) ? TRUE : FALSE;
2217 }
2218
2219 protected:
2220 LPTSTR m_pchData; // pointer to ref counted string data
2221
2222 // implementation helpers
2223 CStringData* GetData() const
2224 {
2225 ATLASSERT(m_pchData != NULL);
2226 return ((CStringData*)m_pchData) - 1;
2227 }
2228
2229 void Init()
2230 {
2231 m_pchData = _GetEmptyString().m_pchData;
2232 }
2233
2234 BOOL AllocCopy(CString& dest, int nCopyLen, int nCopyIndex, int nExtraLe n) const
2235 {
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 st ring
2240
2241 BOOL bRet = FALSE;
2242 int nNewLen = nCopyLen + nExtraLen;
2243 if (nNewLen == 0)
2244 {
2245 dest.Init();
2246 bRet = TRUE;
2247 }
2248 else if(nNewLen >= nCopyLen)
2249 {
2250 if(dest.AllocBuffer(nNewLen))
2251 {
2252 SecureHelper::memcpy_x(dest.m_pchData, (nNewLen + 1) * sizeof(TCHAR), m_pchData + nCopyIndex, nCopyLen * sizeof(TCHAR));
2253 bRet = TRUE;
2254 }
2255 }
2256
2257 return bRet;
2258 }
2259
2260 // always allocate one extra character for '\0' termination
2261 // assumes [optimistically] that data length will equal allocation lengt h
2262 BOOL AllocBuffer(int nLen)
2263 {
2264 ATLASSERT(nLen >= 0);
2265 ATLASSERT(nLen <= INT_MAX - 1); // max size (enough room for 1 extra)
2266
2267 if (nLen == 0)
2268 {
2269 Init();
2270 }
2271 else
2272 {
2273 CStringData* pData = NULL;
2274 ATLTRY(pData = (CStringData*)new BYTE[sizeof(CStringData ) + (nLen + 1) * sizeof(TCHAR)]);
2275 if(pData == NULL)
2276 return FALSE;
2277
2278 pData->nRefs = 1;
2279 pData->data()[nLen] = _T('\0');
2280 pData->nDataLength = nLen;
2281 pData->nAllocLength = nLen;
2282 m_pchData = pData->data();
2283 }
2284
2285 return TRUE;
2286 }
2287
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
2293 //
2294 // All routines return the new string (but as a 'const CString&' so tha t
2295 // assigning it again will cause a copy, eg: s1 = s2 = "hi there".
2296 //
2297 void AssignCopy(int nSrcLen, LPCTSTR lpszSrcData)
2298 {
2299 if(AllocBeforeWrite(nSrcLen))
2300 {
2301 SecureHelper::memcpy_x(m_pchData, (nSrcLen + 1) * sizeof (TCHAR), lpszSrcData, nSrcLen * sizeof(TCHAR));
2302 GetData()->nDataLength = nSrcLen;
2303 m_pchData[nSrcLen] = _T('\0');
2304 }
2305 }
2306
2307 // Concatenation
2308 // NOTE: "operator +" is done as friend functions for simplicity
2309 // There are three variants:
2310 // CString + CString
2311 // and for ? = TCHAR, LPCTSTR
2312 // CString + ?
2313 // ? + CString
2314 BOOL ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data, int nSrc2Len, LPCTST R lpszSrc2Data)
2315 {
2316 // -- master concatenation routine
2317 // Concatenate two sources
2318 // -- assume that 'this' is a new CString object
2319
2320 BOOL bRet = TRUE;
2321 int nNewLen = nSrc1Len + nSrc2Len;
2322 if(nNewLen < nSrc1Len || nNewLen < nSrc2Len)
2323 {
2324 bRet = FALSE;
2325 }
2326 else if(nNewLen != 0)
2327 {
2328 bRet = AllocBuffer(nNewLen);
2329 if (bRet)
2330 {
2331 SecureHelper::memcpy_x(m_pchData, (nNewLen + 1) * sizeof(TCHAR), lpszSrc1Data, nSrc1Len * sizeof(TCHAR));
2332 SecureHelper::memcpy_x(m_pchData + nSrc1Len, (nN ewLen + 1 - nSrc1Len) * sizeof(TCHAR), lpszSrc2Data, nSrc2Len * sizeof(TCHAR));
2333 }
2334 }
2335 return bRet;
2336 }
2337
2338 void ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData)
2339 {
2340 // -- the main routine for += operators
2341
2342 // concatenating an empty string is a no-op!
2343 if (nSrcLen == 0)
2344 return;
2345
2346 // if the buffer is too small, or we have a width mis-match, jus t
2347 // allocate a new buffer (slow but sure)
2348 if (GetData()->nRefs > 1 || GetData()->nDataLength + nSrcLen > G etData()->nAllocLength)
2349 {
2350 // we have to grow the buffer, use the ConcatCopy routin e
2351 CStringData* pOldData = GetData();
2352 if (ConcatCopy(GetData()->nDataLength, m_pchData, nSrcLe n, lpszSrcData))
2353 {
2354 ATLASSERT(pOldData != NULL);
2355 CString::Release(pOldData);
2356 }
2357 }
2358 else
2359 {
2360 // fast concatenation when buffer big enough
2361 SecureHelper::memcpy_x(m_pchData + GetData()->nDataLengt h, (GetData()->nAllocLength + 1) * sizeof(TCHAR), lpszSrcData, nSrcLen * sizeof( TCHAR));
2362 GetData()->nDataLength += nSrcLen;
2363 ATLASSERT(GetData()->nDataLength <= GetData()->nAllocLen gth);
2364 m_pchData[GetData()->nDataLength] = _T('\0');
2365 }
2366 }
2367
2368 void CopyBeforeWrite()
2369 {
2370 if (GetData()->nRefs > 1)
2371 {
2372 CStringData* pData = GetData();
2373 Release();
2374 if(AllocBuffer(pData->nDataLength))
2375 SecureHelper::memcpy_x(m_pchData, (GetData()->nA llocLength + 1) * sizeof(TCHAR), pData->data(), (pData->nDataLength + 1) * sizeo f(TCHAR));
2376 }
2377 ATLASSERT(GetData()->nRefs <= 1);
2378 }
2379
2380 BOOL AllocBeforeWrite(int nLen)
2381 {
2382 BOOL bRet = TRUE;
2383 if (GetData()->nRefs > 1 || nLen > GetData()->nAllocLength)
2384 {
2385 Release();
2386 bRet = AllocBuffer(nLen);
2387 }
2388 ATLASSERT(GetData()->nRefs <= 1);
2389 return bRet;
2390 }
2391
2392 void Release()
2393 {
2394 if (GetData() != _atltmpDataNil)
2395 {
2396 ATLASSERT(GetData()->nRefs != 0);
2397 if (InterlockedDecrement(&GetData()->nRefs) <= 0)
2398 delete[] (BYTE*)GetData();
2399 Init();
2400 }
2401 }
2402
2403 static void PASCAL Release(CStringData* pData)
2404 {
2405 if (pData != _atltmpDataNil)
2406 {
2407 ATLASSERT(pData->nRefs != 0);
2408 if (InterlockedDecrement(&pData->nRefs) <= 0)
2409 delete[] (BYTE*)pData;
2410 }
2411 }
2412
2413 static int PASCAL SafeStrlen(LPCTSTR lpsz)
2414 {
2415 return (lpsz == NULL) ? 0 : lstrlen(lpsz);
2416 }
2417
2418 static int __stdcall _LoadString(UINT nID, LPTSTR lpszBuf, UINT nMaxBuf)
2419 {
2420 #ifdef _DEBUG
2421 // LoadString without annoying warning from the Debug kernel if the
2422 // segment containing the string is not present
2423 if (::FindResource(ModuleHelper::GetResourceInstance(), MAKEINTR ESOURCE((nID >> 4) + 1), RT_STRING) == NULL)
2424 {
2425 lpszBuf[0] = _T('\0');
2426 return 0; // not found
2427 }
2428 #endif // _DEBUG
2429
2430 int nLen = ::LoadString(ModuleHelper::GetResourceInstance(), nID , lpszBuf, nMaxBuf);
2431 if (nLen == 0)
2432 lpszBuf[0] = _T('\0');
2433
2434 return nLen;
2435 }
2436
2437 static const CString& __stdcall _GetEmptyString()
2438 {
2439 return *(CString*)&_atltmpPchNil;
2440 }
2441
2442 // CString conversion helpers
2443 static int __cdecl _wcstombsz(char* mbstr, const wchar_t* wcstr, size_t count)
2444 {
2445 if (count == 0 && mbstr != NULL)
2446 return 0;
2447
2448 int result = ::WideCharToMultiByte(CP_ACP, 0, wcstr, -1, mbstr, (int)count, NULL, NULL);
2449 ATLASSERT(mbstr == NULL || result <= (int)count);
2450 if (result > 0)
2451 mbstr[result - 1] = 0;
2452 return result;
2453 }
2454
2455 static int __cdecl _mbstowcsz(wchar_t* wcstr, const char* mbstr, size_t count)
2456 {
2457 if (count == 0 && wcstr != NULL)
2458 return 0;
2459
2460 int result = ::MultiByteToWideChar(CP_ACP, 0, mbstr, -1, wcstr, (int)count);
2461 ATLASSERT(wcstr == NULL || result <= (int)count);
2462 if (result > 0)
2463 wcstr[result - 1] = 0;
2464 return result;
2465 }
2466
2467 // Helpers to avoid CRT startup code
2468 #ifdef _ATL_MIN_CRT
2469 static const TCHAR* _cstrchr(const TCHAR* p, TCHAR ch)
2470 {
2471 // strchr for '\0' should succeed
2472 while (*p != 0)
2473 {
2474 if (*p == ch)
2475 break;
2476 p = ::CharNext(p);
2477 }
2478 return (*p == ch) ? p : NULL;
2479 }
2480
2481 static const TCHAR* _cstrrchr(const TCHAR* p, TCHAR ch)
2482 {
2483 const TCHAR* lpsz = NULL;
2484 while (*p != 0)
2485 {
2486 if (*p == ch)
2487 lpsz = p;
2488 p = ::CharNext(p);
2489 }
2490 return lpsz;
2491 }
2492
2493 static TCHAR* _cstrrev(TCHAR* pStr)
2494 {
2495 // optimize NULL, zero-length, and single-char case
2496 if ((pStr == NULL) || (pStr[0] == _T('\0')) || (pStr[1] == _T('\ 0')))
2497 return pStr;
2498
2499 TCHAR* p = pStr;
2500
2501 while (*p != 0)
2502 {
2503 TCHAR* pNext = ::CharNext(p);
2504 if(pNext > p + 1)
2505 {
2506 char p1 = *(char*)p;
2507 *(char*)p = *(char*)(p + 1);
2508 *(char*)(p + 1) = p1;
2509 }
2510 p = pNext;
2511 }
2512
2513 p--;
2514 TCHAR* q = pStr;
2515
2516 while (q < p)
2517 {
2518 TCHAR t = *q;
2519 *q = *p;
2520 *p = t;
2521 q++;
2522 p--;
2523 }
2524 return pStr;
2525 }
2526
2527 static const TCHAR* _cstrstr(const TCHAR* pStr, const TCHAR* pCharSet)
2528 {
2529 int nLen = lstrlen(pCharSet);
2530 if (nLen == 0)
2531 return (TCHAR*)pStr;
2532
2533 const TCHAR* pRet = NULL;
2534 const TCHAR* pCur = pStr;
2535 while((pCur = _cstrchr(pCur, *pCharSet)) != NULL)
2536 {
2537 if(memcmp(pCur, pCharSet, nLen * sizeof(TCHAR)) == 0)
2538 {
2539 pRet = pCur;
2540 break;
2541 }
2542 pCur = ::CharNext(pCur);
2543 }
2544 return pRet;
2545 }
2546
2547 static int _cstrspn(const TCHAR* pStr, const TCHAR* pCharSet)
2548 {
2549 int nRet = 0;
2550 const TCHAR* p = pStr;
2551 while (*p != 0)
2552 {
2553 const TCHAR* pNext = ::CharNext(p);
2554 if(pNext > p + 1)
2555 {
2556 if(_cstrchr_db(pCharSet, *p, *(p + 1)) == NULL)
2557 break;
2558 nRet += 2;
2559 }
2560 else
2561 {
2562 if(_cstrchr(pCharSet, *p) == NULL)
2563 break;
2564 nRet++;
2565 }
2566 p = pNext;
2567 }
2568 return nRet;
2569 }
2570
2571 static int _cstrcspn(const TCHAR* pStr, const TCHAR* pCharSet)
2572 {
2573 int nRet = 0;
2574 TCHAR* p = (TCHAR*)pStr;
2575 while (*p != 0)
2576 {
2577 TCHAR* pNext = ::CharNext(p);
2578 if(pNext > p + 1)
2579 {
2580 if(_cstrchr_db(pCharSet, *p, *(p + 1)) != NULL)
2581 break;
2582 nRet += 2;
2583 }
2584 else
2585 {
2586 if(_cstrchr(pCharSet, *p) != NULL)
2587 break;
2588 nRet++;
2589 }
2590 p = pNext;
2591 }
2592 return nRet;
2593 }
2594
2595 static const TCHAR* _cstrpbrk(const TCHAR* p, const TCHAR* lpszCharSet)
2596 {
2597 int n = _cstrcspn(p, lpszCharSet);
2598 return (p[n] != 0) ? &p[n] : NULL;
2599 }
2600
2601 static int _cstrisdigit(TCHAR ch)
2602 {
2603 WORD type;
2604 GetStringTypeEx(GetThreadLocale(), CT_CTYPE1, &ch, 1, &type);
2605 return (type & C1_DIGIT) == C1_DIGIT;
2606 }
2607
2608 static int _cstrisspace(TCHAR ch)
2609 {
2610 WORD type;
2611 GetStringTypeEx(GetThreadLocale(), CT_CTYPE1, &ch, 1, &type);
2612 return (type & C1_SPACE) == C1_SPACE;
2613 }
2614
2615 static int _cstrcmp(const TCHAR* pstrOne, const TCHAR* pstrOther)
2616 {
2617 return lstrcmp(pstrOne, pstrOther);
2618 }
2619
2620 static int _cstrcmpi(const TCHAR* pstrOne, const TCHAR* pstrOther)
2621 {
2622 return lstrcmpi(pstrOne, pstrOther);
2623 }
2624
2625 static int _cstrcoll(const TCHAR* pstrOne, const TCHAR* pstrOther)
2626 {
2627 int nRet = CompareString(GetThreadLocale(), 0, pstrOne, -1, pstr Other, -1);
2628 ATLASSERT(nRet != 0);
2629 return nRet - 2; // convert to strcmp convention
2630 }
2631
2632 static int _cstrcolli(const TCHAR* pstrOne, const TCHAR* pstrOther)
2633 {
2634 int nRet = CompareString(GetThreadLocale(), NORM_IGNORECASE, pst rOne, -1, pstrOther, -1);
2635 ATLASSERT(nRet != 0);
2636 return nRet - 2; // convert to strcmp convention
2637 }
2638
2639 static int _cstrtoi(const TCHAR* nptr)
2640 {
2641 int c; // current char
2642 int total; // current total
2643 int sign; // if '-', then negative, otherwise positive
2644
2645 while (_cstrisspace(*nptr))
2646 ++nptr;
2647
2648 c = (int)(_TUCHAR)*nptr++;
2649 sign = c; // save sign indication
2650 if (c == _T('-') || c == _T('+'))
2651 c = (int)(_TUCHAR)*nptr++; // skip sign
2652
2653 total = 0;
2654
2655 while (_cstrisdigit((TCHAR)c))
2656 {
2657 total = 10 * total + (c - '0'); // accumulate digit
2658 c = (int)(_TUCHAR)*nptr++; // get next char
2659 }
2660
2661 if (sign == '-')
2662 return -total;
2663 else
2664 return total; // return result, negated if necessary
2665 }
2666 #else // !_ATL_MIN_CRT
2667 static const TCHAR* _cstrchr(const TCHAR* p, TCHAR ch)
2668 {
2669 return _tcschr(p, ch);
2670 }
2671
2672 static const TCHAR* _cstrrchr(const TCHAR* p, TCHAR ch)
2673 {
2674 return _tcsrchr(p, ch);
2675 }
2676
2677 static TCHAR* _cstrrev(TCHAR* pStr)
2678 {
2679 return _tcsrev(pStr);
2680 }
2681
2682 static const TCHAR* _cstrstr(const TCHAR* pStr, const TCHAR* pCharSet)
2683 {
2684 return _tcsstr(pStr, pCharSet);
2685 }
2686
2687 static int _cstrspn(const TCHAR* pStr, const TCHAR* pCharSet)
2688 {
2689 return (int)_tcsspn(pStr, pCharSet);
2690 }
2691
2692 static int _cstrcspn(const TCHAR* pStr, const TCHAR* pCharSet)
2693 {
2694 return (int)_tcscspn(pStr, pCharSet);
2695 }
2696
2697 static const TCHAR* _cstrpbrk(const TCHAR* p, const TCHAR* lpszCharSet)
2698 {
2699 return _tcspbrk(p, lpszCharSet);
2700 }
2701
2702 static int _cstrisdigit(TCHAR ch)
2703 {
2704 return _istdigit(ch);
2705 }
2706
2707 static int _cstrisspace(TCHAR ch)
2708 {
2709 return _istspace((_TUCHAR)ch);
2710 }
2711
2712 static int _cstrcmp(const TCHAR* pstrOne, const TCHAR* pstrOther)
2713 {
2714 return _tcscmp(pstrOne, pstrOther);
2715 }
2716
2717 static int _cstrcmpi(const TCHAR* pstrOne, const TCHAR* pstrOther)
2718 {
2719 return _tcsicmp(pstrOne, pstrOther);
2720 }
2721
2722 #ifndef _WIN32_WCE
2723 static int _cstrcoll(const TCHAR* pstrOne, const TCHAR* pstrOther)
2724 {
2725 return _tcscoll(pstrOne, pstrOther);
2726 }
2727
2728 static int _cstrcolli(const TCHAR* pstrOne, const TCHAR* pstrOther)
2729 {
2730 return _tcsicoll(pstrOne, pstrOther);
2731 }
2732 #endif // !_WIN32_WCE
2733
2734 static int _cstrtoi(const TCHAR* nptr)
2735 {
2736 return _ttoi(nptr);
2737 }
2738 #endif // !_ATL_MIN_CRT
2739
2740 static const TCHAR* _cstrchr_db(const TCHAR* p, TCHAR ch1, TCHAR ch2)
2741 {
2742 const TCHAR* lpsz = NULL;
2743 while (*p != 0)
2744 {
2745 if (*p == ch1 && *(p + 1) == ch2)
2746 {
2747 lpsz = p;
2748 break;
2749 }
2750 p = ::CharNext(p);
2751 }
2752 return lpsz;
2753 }
2754 };
2755
2756
2757 // Compare helpers
2758
2759 inline bool __stdcall operator ==(const CString& s1, const CString& s2)
2760 { return s1.Compare(s2) == 0; }
2761
2762 inline bool __stdcall operator ==(const CString& s1, LPCTSTR s2)
2763 { return s1.Compare(s2) == 0; }
2764
2765 inline bool __stdcall operator ==(LPCTSTR s1, const CString& s2)
2766 { return s2.Compare(s1) == 0; }
2767
2768 inline bool __stdcall operator !=(const CString& s1, const CString& s2)
2769 { return s1.Compare(s2) != 0; }
2770
2771 inline bool __stdcall operator !=(const CString& s1, LPCTSTR s2)
2772 { return s1.Compare(s2) != 0; }
2773
2774 inline bool __stdcall operator !=(LPCTSTR s1, const CString& s2)
2775 { return s2.Compare(s1) != 0; }
2776
2777 inline bool __stdcall operator <(const CString& s1, const CString& s2)
2778 { return s1.Compare(s2) < 0; }
2779
2780 inline bool __stdcall operator <(const CString& s1, LPCTSTR s2)
2781 { return s1.Compare(s2) < 0; }
2782
2783 inline bool __stdcall operator <(LPCTSTR s1, const CString& s2)
2784 { return s2.Compare(s1) > 0; }
2785
2786 inline bool __stdcall operator >(const CString& s1, const CString& s2)
2787 { return s1.Compare(s2) > 0; }
2788
2789 inline bool __stdcall operator >(const CString& s1, LPCTSTR s2)
2790 { return s1.Compare(s2) > 0; }
2791
2792 inline bool __stdcall operator >(LPCTSTR s1, const CString& s2)
2793 { return s2.Compare(s1) < 0; }
2794
2795 inline bool __stdcall operator <=(const CString& s1, const CString& s2)
2796 { return s1.Compare(s2) <= 0; }
2797
2798 inline bool __stdcall operator <=(const CString& s1, LPCTSTR s2)
2799 { return s1.Compare(s2) <= 0; }
2800
2801 inline bool __stdcall operator <=(LPCTSTR s1, const CString& s2)
2802 { return s2.Compare(s1) >= 0; }
2803
2804 inline bool __stdcall operator >=(const CString& s1, const CString& s2)
2805 { return s1.Compare(s2) >= 0; }
2806
2807 inline bool __stdcall operator >=(const CString& s1, LPCTSTR s2)
2808 { return s1.Compare(s2) >= 0; }
2809
2810 inline bool __stdcall operator >=(LPCTSTR s1, const CString& s2)
2811 { return s2.Compare(s1) <= 0; }
2812
2813
2814 // CString "operator +" functions
2815
2816 inline CString __stdcall operator +(const CString& string1, const CString& strin g2)
2817 {
2818 CString s;
2819 s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData, string2. GetData()->nDataLength, string2.m_pchData);
2820 return s;
2821 }
2822
2823 inline CString __stdcall operator +(const CString& string, TCHAR ch)
2824 {
2825 CString s;
2826 s.ConcatCopy(string.GetData()->nDataLength, string.m_pchData, 1, &ch);
2827 return s;
2828 }
2829
2830 inline CString __stdcall operator +(TCHAR ch, const CString& string)
2831 {
2832 CString s;
2833 s.ConcatCopy(1, &ch, string.GetData()->nDataLength, string.m_pchData);
2834 return s;
2835 }
2836
2837 #ifdef _UNICODE
2838 inline CString __stdcall operator +(const CString& string, char ch)
2839 {
2840 return string + (TCHAR)ch;
2841 }
2842
2843 inline CString __stdcall operator +(char ch, const CString& string)
2844 {
2845 return (TCHAR)ch + string;
2846 }
2847 #endif // _UNICODE
2848
2849 inline CString __stdcall operator +(const CString& string, LPCTSTR lpsz)
2850 {
2851 ATLASSERT(lpsz == NULL || CString::_IsValidString(lpsz));
2852 CString s;
2853 s.ConcatCopy(string.GetData()->nDataLength, string.m_pchData, CString::S afeStrlen(lpsz), lpsz);
2854 return s;
2855 }
2856
2857 inline CString __stdcall operator +(LPCTSTR lpsz, const CString& string)
2858 {
2859 ATLASSERT(lpsz == NULL || CString::_IsValidString(lpsz));
2860 CString s;
2861 s.ConcatCopy(CString::SafeStrlen(lpsz), lpsz, string.GetData()->nDataLen gth, string.m_pchData);
2862 return s;
2863 }
2864
2865 #endif // !_WTL_NO_CSTRING
2866
2867
2868 ///////////////////////////////////////////////////////////////////////////////
2869 // CRecentDocumentList - MRU List Support
2870
2871 #ifndef _WIN32_WCE
2872
2873 #ifndef _WTL_MRUEMPTY_TEXT
2874 #define _WTL_MRUEMPTY_TEXT _T("(empty)")
2875 #endif
2876
2877 // forward declaration
2878 inline bool AtlCompactPath(LPTSTR lpstrOut, LPCTSTR lpstrIn, int cchLen);
2879
2880 template <class T, int t_cchItemLen = MAX_PATH, int t_nFirstID = ID_FILE_MRU_FIR ST, int t_nLastID = ID_FILE_MRU_LAST>
2881 class CRecentDocumentListBase
2882 {
2883 public:
2884 // Declarations
2885 struct _DocEntry
2886 {
2887 TCHAR szDocName[t_cchItemLen];
2888 bool operator ==(const _DocEntry& de) const
2889 { return (lstrcmpi(szDocName, de.szDocName) == 0); }
2890 };
2891
2892 enum
2893 {
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
2899 };
2900
2901 // Data members
2902 ATL::CSimpleArray<_DocEntry> m_arrDocs;
2903 int m_nMaxEntries; // default is 4
2904 HMENU m_hMenu;
2905
2906 TCHAR m_szNoEntries[t_cchItemLen];
2907
2908 int m_cchMaxItemLen;
2909
2910 // Constructor
2911 CRecentDocumentListBase() : m_hMenu(NULL), m_nMaxEntries(4), m_cchMaxIte mLen(-1)
2912 {
2913 // These ASSERTs verify values of the template arguments
2914 ATLASSERT(t_cchItemLen > m_cchMaxItemLen_Min);
2915 ATLASSERT(m_nMaxEntries_Max > m_nMaxEntries_Min);
2916 }
2917
2918 // Attributes
2919 HMENU GetMenuHandle() const
2920 {
2921 return m_hMenu;
2922 }
2923
2924 void SetMenuHandle(HMENU hMenu)
2925 {
2926 ATLASSERT(hMenu == NULL || ::IsMenu(hMenu));
2927 m_hMenu = hMenu;
2928 if(m_hMenu == NULL || (::GetMenuString(m_hMenu, t_nFirstID, m_sz NoEntries, t_cchItemLen, MF_BYCOMMAND) == 0))
2929 {
2930 T* pT = static_cast<T*>(this);
2931 pT; // avoid level 4 warning
2932 SecureHelper::strncpy_x(m_szNoEntries, _countof(m_szNoEn tries), pT->GetMRUEmptyText(), _TRUNCATE);
2933 }
2934 }
2935
2936 int GetMaxEntries() const
2937 {
2938 return m_nMaxEntries;
2939 }
2940
2941 void SetMaxEntries(int nMaxEntries)
2942 {
2943 ATLASSERT(nMaxEntries >= m_nMaxEntries_Min && nMaxEntries <= m_n MaxEntries_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;
2949 }
2950
2951 int GetMaxItemLength() const
2952 {
2953 return m_cchMaxItemLen;
2954 }
2955
2956 void SetMaxItemLength(int cchMaxLen)
2957 {
2958 ATLASSERT((cchMaxLen >= m_cchMaxItemLen_Min && cchMaxLen <= m_cc hMaxItemLen_Max) || cchMaxLen == -1);
2959 if(cchMaxLen != -1)
2960 {
2961 if(cchMaxLen < m_cchMaxItemLen_Min)
2962 cchMaxLen = m_cchMaxItemLen_Min;
2963 else if(cchMaxLen > m_cchMaxItemLen_Max)
2964 cchMaxLen = m_cchMaxItemLen_Max;
2965 }
2966 m_cchMaxItemLen = cchMaxLen;
2967 T* pT = static_cast<T*>(this);
2968 pT->UpdateMenu();
2969 }
2970
2971 // Operations
2972 BOOL AddToList(LPCTSTR lpstrDocName)
2973 {
2974 _DocEntry de;
2975 errno_t nRet = SecureHelper::strncpy_x(de.szDocName, _countof(de .szDocName), lpstrDocName, _TRUNCATE);
2976 if(nRet != 0 && nRet != STRUNCATE)
2977 return FALSE;
2978
2979 for(int i = 0; i < m_arrDocs.GetSize(); i++)
2980 {
2981 if(lstrcmpi(m_arrDocs[i].szDocName, lpstrDocName) == 0)
2982 {
2983 m_arrDocs.RemoveAt(i);
2984 break;
2985 }
2986 }
2987
2988 if(m_arrDocs.GetSize() == m_nMaxEntries)
2989 m_arrDocs.RemoveAt(0);
2990
2991 BOOL bRet = m_arrDocs.Add(de);
2992 if(bRet)
2993 {
2994 T* pT = static_cast<T*>(this);
2995 bRet = pT->UpdateMenu();
2996 }
2997 return bRet;
2998 }
2999
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)
3004 #endif
3005 BOOL GetFromList(int /*nItemID*/, LPTSTR /*lpstrDocName*/)
3006 {
3007 ATLASSERT(FALSE);
3008 return FALSE;
3009 }
3010
3011 BOOL GetFromList(int nItemID, LPTSTR lpstrDocName, int cchLength)
3012 {
3013 int nIndex = m_arrDocs.GetSize() - (nItemID - t_nFirstID) - 1;
3014 if(nIndex < 0 || nIndex >= m_arrDocs.GetSize())
3015 return FALSE;
3016 if(lstrlen(m_arrDocs[nIndex].szDocName) >= cchLength)
3017 return FALSE;
3018 SecureHelper::strcpy_x(lpstrDocName, cchLength, m_arrDocs[nIndex ].szDocName);
3019
3020 return TRUE;
3021 }
3022
3023 #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
3024 BOOL GetFromList(int nItemID, _CSTRING_NS::CString& strDocName)
3025 {
3026 int nIndex = m_arrDocs.GetSize() - (nItemID - t_nFirstID) - 1;
3027 if(nIndex < 0 || nIndex >= m_arrDocs.GetSize())
3028 return FALSE;
3029 strDocName = m_arrDocs[nIndex].szDocName;
3030 return TRUE;
3031 }
3032 #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
3033
3034 BOOL RemoveFromList(int nItemID)
3035 {
3036 int nIndex = m_arrDocs.GetSize() - (nItemID - t_nFirstID) - 1;
3037 BOOL bRet = m_arrDocs.RemoveAt(nIndex);
3038 if(bRet)
3039 {
3040 T* pT = static_cast<T*>(this);
3041 bRet = pT->UpdateMenu();
3042 }
3043 return bRet;
3044 }
3045
3046 BOOL MoveToTop(int nItemID)
3047 {
3048 int nIndex = m_arrDocs.GetSize() - (nItemID - t_nFirstID) - 1;
3049 if(nIndex < 0 || nIndex >= m_arrDocs.GetSize())
3050 return FALSE;
3051 _DocEntry de;
3052 de = m_arrDocs[nIndex];
3053 m_arrDocs.RemoveAt(nIndex);
3054 BOOL bRet = m_arrDocs.Add(de);
3055 if(bRet)
3056 {
3057 T* pT = static_cast<T*>(this);
3058 bRet = pT->UpdateMenu();
3059 }
3060 return bRet;
3061 }
3062
3063 BOOL ReadFromRegistry(LPCTSTR lpstrRegKey)
3064 {
3065 T* pT = static_cast<T*>(this);
3066 ATL::CRegKey rkParent;
3067 ATL::CRegKey rk;
3068
3069 LONG lRet = rkParent.Open(HKEY_CURRENT_USER, lpstrRegKey);
3070 if(lRet != ERROR_SUCCESS)
3071 return FALSE;
3072 lRet = rk.Open(rkParent, pT->GetRegKeyName());
3073 if(lRet != ERROR_SUCCESS)
3074 return FALSE;
3075
3076 DWORD dwRet = 0;
3077 #if (_ATL_VER >= 0x0700)
3078 lRet = rk.QueryDWORDValue(pT->GetRegCountName(), dwRet);
3079 #else
3080 lRet = rk.QueryValue(dwRet, pT->GetRegCountName());
3081 #endif
3082 if(lRet != ERROR_SUCCESS)
3083 return FALSE;
3084 SetMaxEntries(dwRet);
3085
3086 m_arrDocs.RemoveAll();
3087
3088 TCHAR szRetString[t_cchItemLen] = { 0 };
3089 _DocEntry de;
3090
3091 for(int nItem = m_nMaxEntries; nItem > 0; nItem--)
3092 {
3093 TCHAR szBuff[m_cchItemNameLen] = { 0 };
3094 SecureHelper::wsprintf_x(szBuff, m_cchItemNameLen, pT->G etRegItemName(), nItem);
3095 #if (_ATL_VER >= 0x0700)
3096 ULONG ulCount = t_cchItemLen;
3097 lRet = rk.QueryStringValue(szBuff, szRetString, &ulCount );
3098 #else
3099 DWORD dwCount = t_cchItemLen * sizeof(TCHAR);
3100 lRet = rk.QueryValue(szRetString, szBuff, &dwCount);
3101 #endif
3102 if(lRet == ERROR_SUCCESS)
3103 {
3104 SecureHelper::strcpy_x(de.szDocName, _countof(de .szDocName), szRetString);
3105 m_arrDocs.Add(de);
3106 }
3107 }
3108
3109 rk.Close();
3110 rkParent.Close();
3111
3112 return pT->UpdateMenu();
3113 }
3114
3115 BOOL WriteToRegistry(LPCTSTR lpstrRegKey)
3116 {
3117 T* pT = static_cast<T*>(this);
3118 pT; // avoid level 4 warning
3119 ATL::CRegKey rkParent;
3120 ATL::CRegKey rk;
3121
3122 LONG lRet = rkParent.Create(HKEY_CURRENT_USER, lpstrRegKey);
3123 if(lRet != ERROR_SUCCESS)
3124 return FALSE;
3125 lRet = rk.Create(rkParent, pT->GetRegKeyName());
3126 if(lRet != ERROR_SUCCESS)
3127 return FALSE;
3128
3129 #if (_ATL_VER >= 0x0700)
3130 lRet = rk.SetDWORDValue(pT->GetRegCountName(), m_nMaxEntries);
3131 #else
3132 lRet = rk.SetValue(m_nMaxEntries, pT->GetRegCountName());
3133 #endif
3134 ATLASSERT(lRet == ERROR_SUCCESS);
3135
3136 // set new values
3137 int nItem;
3138 for(nItem = m_arrDocs.GetSize(); nItem > 0; nItem--)
3139 {
3140 TCHAR szBuff[m_cchItemNameLen] = { 0 };
3141 SecureHelper::wsprintf_x(szBuff, m_cchItemNameLen, pT->G etRegItemName(), nItem);
3142 TCHAR szDocName[t_cchItemLen] = { 0 };
3143 GetFromList(t_nFirstID + nItem - 1, szDocName, t_cchItem Len);
3144 #if (_ATL_VER >= 0x0700)
3145 lRet = rk.SetStringValue(szBuff, szDocName);
3146 #else
3147 lRet = rk.SetValue(szDocName, szBuff);
3148 #endif
3149 ATLASSERT(lRet == ERROR_SUCCESS);
3150 }
3151
3152 // delete unused keys
3153 for(nItem = m_arrDocs.GetSize() + 1; nItem < m_nMaxEntries_Max; nItem++)
3154 {
3155 TCHAR szBuff[m_cchItemNameLen] = { 0 };
3156 SecureHelper::wsprintf_x(szBuff, m_cchItemNameLen, pT->G etRegItemName(), nItem);
3157 rk.DeleteValue(szBuff);
3158 }
3159
3160 rk.Close();
3161 rkParent.Close();
3162
3163 return TRUE;
3164 }
3165
3166 // Implementation
3167 BOOL UpdateMenu()
3168 {
3169 if(m_hMenu == NULL)
3170 return FALSE;
3171 ATLASSERT(::IsMenu(m_hMenu));
3172
3173 int nItems = ::GetMenuItemCount(m_hMenu);
3174 int nInsertPoint;
3175 for(nInsertPoint = 0; nInsertPoint < nItems; nInsertPoint++)
3176 {
3177 CMenuItemInfo mi;
3178 mi.fMask = MIIM_ID;
3179 ::GetMenuItemInfo(m_hMenu, nInsertPoint, TRUE, &mi);
3180 if (mi.wID == t_nFirstID)
3181 break;
3182 }
3183 ATLASSERT(nInsertPoint < nItems && "You need a menu item with an ID = t_nFirstID");
3184
3185 int nItem;
3186 for(nItem = t_nFirstID; nItem < t_nFirstID + m_nMaxEntries; nIte m++)
3187 {
3188 // keep the first one as an insertion point
3189 if (nItem != t_nFirstID)
3190 ::DeleteMenu(m_hMenu, nItem, MF_BYCOMMAND);
3191 }
3192
3193 TCHAR szItemText[t_cchItemLen + 6] = { 0 }; // add space for & , 2 digits, and a space
3194 int nSize = m_arrDocs.GetSize();
3195 nItem = 0;
3196 if(nSize > 0)
3197 {
3198 for(nItem = 0; nItem < nSize; nItem++)
3199 {
3200 if(m_cchMaxItemLen == -1)
3201 {
3202 SecureHelper::wsprintf_x(szItemText, t_c chItemLen + 6, _T("&%i %s"), nItem + 1, m_arrDocs[nSize - 1 - nItem].szDocName);
3203 }
3204 else
3205 {
3206 TCHAR szBuff[t_cchItemLen] = { 0 };
3207 T* pT = static_cast<T*>(this);
3208 pT; // avoid level 4 warning
3209 bool bRet = pT->CompactDocumentName(szBu ff, m_arrDocs[nSize - 1 - nItem].szDocName, m_cchMaxItemLen);
3210 bRet; // avoid level 4 warning
3211 ATLASSERT(bRet);
3212 SecureHelper::wsprintf_x(szItemText, t_c chItemLen + 6, _T("&%i %s"), nItem + 1, szBuff);
3213 }
3214 ::InsertMenu(m_hMenu, nInsertPoint + nItem, MF_B YPOSITION | MF_STRING, t_nFirstID + nItem, szItemText);
3215 }
3216 }
3217 else // empty
3218 {
3219 ::InsertMenu(m_hMenu, nInsertPoint, MF_BYPOSITION | MF_S TRING, t_nFirstID, m_szNoEntries);
3220 ::EnableMenuItem(m_hMenu, t_nFirstID, MF_GRAYED);
3221 nItem++;
3222 }
3223 ::DeleteMenu(m_hMenu, nInsertPoint + nItem, MF_BYPOSITION);
3224
3225 return TRUE;
3226 }
3227
3228 // Overrideables
3229 // override to provide a different method of compacting document names
3230 static bool CompactDocumentName(LPTSTR lpstrOut, LPCTSTR lpstrIn, int cc hLen)
3231 {
3232 return AtlCompactPath(lpstrOut, lpstrIn, cchLen);
3233 }
3234
3235 static LPCTSTR GetRegKeyName()
3236 {
3237 return _T("Recent Document List");
3238 }
3239
3240 static LPCTSTR GetRegCountName()
3241 {
3242 return _T("DocumentCount");
3243 }
3244
3245 static LPCTSTR GetRegItemName()
3246 {
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");
3251 }
3252
3253 static LPCTSTR GetMRUEmptyText()
3254 {
3255 return _WTL_MRUEMPTY_TEXT;
3256 }
3257 };
3258
3259 class CRecentDocumentList : public CRecentDocumentListBase<CRecentDocumentList>
3260 {
3261 public:
3262 // nothing here
3263 };
3264
3265 #endif // _WIN32_WCE
3266
3267
3268 ///////////////////////////////////////////////////////////////////////////////
3269 // CFindFile - file search helper class
3270
3271 class CFindFile
3272 {
3273 public:
3274 // Data members
3275 WIN32_FIND_DATA m_fd;
3276 TCHAR m_lpszRoot[MAX_PATH];
3277 TCHAR m_chDirSeparator;
3278 HANDLE m_hFind;
3279 BOOL m_bFound;
3280
3281 // Constructor/destructor
3282 CFindFile() : m_hFind(NULL), m_chDirSeparator(_T('\\')), m_bFound(FALSE)
3283 { }
3284
3285 ~CFindFile()
3286 {
3287 Close();
3288 }
3289
3290 // Attributes
3291 ULONGLONG GetFileSize() const
3292 {
3293 ATLASSERT(m_hFind != NULL);
3294
3295 ULARGE_INTEGER nFileSize = { 0 };
3296
3297 if(m_bFound)
3298 {
3299 nFileSize.LowPart = m_fd.nFileSizeLow;
3300 nFileSize.HighPart = m_fd.nFileSizeHigh;
3301 }
3302 else
3303 {
3304 nFileSize.QuadPart = 0;
3305 }
3306
3307 return nFileSize.QuadPart;
3308 }
3309
3310 BOOL GetFileName(LPTSTR lpstrFileName, int cchLength) const
3311 {
3312 ATLASSERT(m_hFind != NULL);
3313 if(lstrlen(m_fd.cFileName) >= cchLength)
3314 return FALSE;
3315
3316 if(m_bFound)
3317 SecureHelper::strcpy_x(lpstrFileName, cchLength, m_fd.cF ileName);
3318
3319 return m_bFound;
3320 }
3321
3322 BOOL GetFilePath(LPTSTR lpstrFilePath, int cchLength) const
3323 {
3324 ATLASSERT(m_hFind != NULL);
3325
3326 int nLen = lstrlen(m_lpszRoot);
3327 #ifndef _WIN32_WCE
3328 ATLASSERT(nLen > 0);
3329 if(nLen == 0)
3330 return FALSE;
3331
3332 bool bAddSep = (m_lpszRoot[nLen - 1] != _T('\\') && m_lpszRoot[n Len - 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
3337
3338 if((lstrlen(m_lpszRoot) + (bAddSep ? 1 : 0)) >= cchLength)
3339 return FALSE;
3340
3341 SecureHelper::strcpy_x(lpstrFilePath, cchLength, m_lpszRoot);
3342
3343 if(bAddSep)
3344 {
3345 TCHAR szSeparator[2] = { m_chDirSeparator, 0 };
3346 SecureHelper::strcat_x(lpstrFilePath, cchLength, szSepar ator);
3347 }
3348
3349 SecureHelper::strcat_x(lpstrFilePath, cchLength, m_fd.cFileName) ;
3350
3351 return TRUE;
3352 }
3353
3354 #ifndef _WIN32_WCE
3355 BOOL GetFileTitle(LPTSTR lpstrFileTitle, int cchLength) const
3356 {
3357 ATLASSERT(m_hFind != NULL);
3358
3359 TCHAR szBuff[MAX_PATH] = { 0 };
3360 if(!GetFileName(szBuff, MAX_PATH))
3361 return FALSE;
3362
3363 if(lstrlen(szBuff) >= cchLength || cchLength < 1)
3364 return FALSE;
3365
3366 // find the last dot
3367 LPTSTR pstrDot = (LPTSTR)_cstrrchr(szBuff, _T('.'));
3368 if(pstrDot != NULL)
3369 *pstrDot = 0;
3370
3371 SecureHelper::strcpy_x(lpstrFileTitle, cchLength, szBuff);
3372
3373 return TRUE;
3374 }
3375 #endif // !_WIN32_WCE
3376
3377 BOOL GetFileURL(LPTSTR lpstrFileURL, int cchLength) const
3378 {
3379 ATLASSERT(m_hFind != NULL);
3380
3381 TCHAR szBuff[MAX_PATH] = { 0 };
3382 if(!GetFilePath(szBuff, MAX_PATH))
3383 return FALSE;
3384 LPCTSTR lpstrFileURLPrefix = _T("file://");
3385 if(lstrlen(szBuff) + lstrlen(lpstrFileURLPrefix) >= cchLength)
3386 return FALSE;
3387 SecureHelper::strcpy_x(lpstrFileURL, cchLength, lpstrFileURLPref ix);
3388 SecureHelper::strcat_x(lpstrFileURL, cchLength, szBuff);
3389
3390 return TRUE;
3391 }
3392
3393 BOOL GetRoot(LPTSTR lpstrRoot, int cchLength) const
3394 {
3395 ATLASSERT(m_hFind != NULL);
3396 if(lstrlen(m_lpszRoot) >= cchLength)
3397 return FALSE;
3398
3399 SecureHelper::strcpy_x(lpstrRoot, cchLength, m_lpszRoot);
3400
3401 return TRUE;
3402 }
3403
3404 #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
3405 _CSTRING_NS::CString GetFileName() const
3406 {
3407 ATLASSERT(m_hFind != NULL);
3408
3409 _CSTRING_NS::CString ret;
3410
3411 if(m_bFound)
3412 ret = m_fd.cFileName;
3413 return ret;
3414 }
3415
3416 _CSTRING_NS::CString GetFilePath() const
3417 {
3418 ATLASSERT(m_hFind != NULL);
3419
3420 _CSTRING_NS::CString strResult = m_lpszRoot;
3421 int nLen = strResult.GetLength();
3422 #ifndef _WIN32_WCE
3423 ATLASSERT(nLen > 0);
3424 if(nLen == 0)
3425 return strResult;
3426
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('\\')) && (strResu lt[nLen - 1] != _T('/'))))
3431 #endif // _WIN32_WCE
3432 strResult += m_chDirSeparator;
3433 strResult += GetFileName();
3434 return strResult;
3435 }
3436
3437 #ifndef _WIN32_WCE
3438 _CSTRING_NS::CString GetFileTitle() const
3439 {
3440 ATLASSERT(m_hFind != NULL);
3441
3442 _CSTRING_NS::CString strResult;
3443 GetFileTitle(strResult.GetBuffer(MAX_PATH), MAX_PATH);
3444 strResult.ReleaseBuffer();
3445
3446 return strResult;
3447 }
3448 #endif // !_WIN32_WCE
3449
3450 _CSTRING_NS::CString GetFileURL() const
3451 {
3452 ATLASSERT(m_hFind != NULL);
3453
3454 _CSTRING_NS::CString strResult("file://");
3455 strResult += GetFilePath();
3456 return strResult;
3457 }
3458
3459 _CSTRING_NS::CString GetRoot() const
3460 {
3461 ATLASSERT(m_hFind != NULL);
3462
3463 _CSTRING_NS::CString str = m_lpszRoot;
3464 return str;
3465 }
3466 #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
3467
3468 BOOL GetLastWriteTime(FILETIME* pTimeStamp) const
3469 {
3470 ATLASSERT(m_hFind != NULL);
3471 ATLASSERT(pTimeStamp != NULL);
3472
3473 if(m_bFound && pTimeStamp != NULL)
3474 {
3475 *pTimeStamp = m_fd.ftLastWriteTime;
3476 return TRUE;
3477 }
3478
3479 return FALSE;
3480 }
3481
3482 BOOL GetLastAccessTime(FILETIME* pTimeStamp) const
3483 {
3484 ATLASSERT(m_hFind != NULL);
3485 ATLASSERT(pTimeStamp != NULL);
3486
3487 if(m_bFound && pTimeStamp != NULL)
3488 {
3489 *pTimeStamp = m_fd.ftLastAccessTime;
3490 return TRUE;
3491 }
3492
3493 return FALSE;
3494 }
3495
3496 BOOL GetCreationTime(FILETIME* pTimeStamp) const
3497 {
3498 ATLASSERT(m_hFind != NULL);
3499
3500 if(m_bFound && pTimeStamp != NULL)
3501 {
3502 *pTimeStamp = m_fd.ftCreationTime;
3503 return TRUE;
3504 }
3505
3506 return FALSE;
3507 }
3508
3509 BOOL MatchesMask(DWORD dwMask) const
3510 {
3511 ATLASSERT(m_hFind != NULL);
3512
3513 if(m_bFound)
3514 return ((m_fd.dwFileAttributes & dwMask) != 0);
3515
3516 return FALSE;
3517 }
3518
3519 BOOL IsDots() const
3520 {
3521 ATLASSERT(m_hFind != NULL);
3522
3523 // return TRUE if the file name is "." or ".." and
3524 // the file is a directory
3525
3526 BOOL bResult = FALSE;
3527 if(m_bFound && IsDirectory())
3528 {
3529 if(m_fd.cFileName[0] == _T('.') && (m_fd.cFileName[1] == _T('\0') || (m_fd.cFileName[1] == _T('.') && m_fd.cFileName[2] == _T('\0'))))
3530 bResult = TRUE;
3531 }
3532
3533 return bResult;
3534 }
3535
3536 BOOL IsReadOnly() const
3537 {
3538 return MatchesMask(FILE_ATTRIBUTE_READONLY);
3539 }
3540
3541 BOOL IsDirectory() const
3542 {
3543 return MatchesMask(FILE_ATTRIBUTE_DIRECTORY);
3544 }
3545
3546 BOOL IsCompressed() const
3547 {
3548 return MatchesMask(FILE_ATTRIBUTE_COMPRESSED);
3549 }
3550
3551 BOOL IsSystem() const
3552 {
3553 return MatchesMask(FILE_ATTRIBUTE_SYSTEM);
3554 }
3555
3556 BOOL IsHidden() const
3557 {
3558 return MatchesMask(FILE_ATTRIBUTE_HIDDEN);
3559 }
3560
3561 BOOL IsTemporary() const
3562 {
3563 return MatchesMask(FILE_ATTRIBUTE_TEMPORARY);
3564 }
3565
3566 BOOL IsNormal() const
3567 {
3568 return MatchesMask(FILE_ATTRIBUTE_NORMAL);
3569 }
3570
3571 BOOL IsArchived() const
3572 {
3573 return MatchesMask(FILE_ATTRIBUTE_ARCHIVE);
3574 }
3575
3576 // Operations
3577 BOOL FindFile(LPCTSTR pstrName = NULL)
3578 {
3579 Close();
3580
3581 if(pstrName == NULL)
3582 {
3583 pstrName = _T("*.*");
3584 }
3585 else if(lstrlen(pstrName) >= MAX_PATH)
3586 {
3587 ATLASSERT(FALSE);
3588 return FALSE;
3589 }
3590
3591 SecureHelper::strcpy_x(m_fd.cFileName, _countof(m_fd.cFileName), pstrName);
3592
3593 m_hFind = ::FindFirstFile(pstrName, &m_fd);
3594
3595 if(m_hFind == INVALID_HANDLE_VALUE)
3596 return FALSE;
3597
3598 #ifndef _WIN32_WCE
3599 bool bFullPath = (::GetFullPathName(pstrName, MAX_PATH, m_lpszRo ot, NULL) != 0);
3600 #else // CE specific
3601 errno_t nRet = SecureHelper::strncpy_x(m_lpszRoot, _countof(m_lp szRoot), pstrName, _TRUNCATE);
3602 bool bFullPath = (nRet == 0 || nRet == STRUNCATE);
3603 #endif // _WIN32_WCE
3604
3605 // passed name isn't a valid path but was found by the API
3606 ATLASSERT(bFullPath);
3607 if(!bFullPath)
3608 {
3609 Close();
3610 ::SetLastError(ERROR_INVALID_NAME);
3611 return FALSE;
3612 }
3613 else
3614 {
3615 // find the last forward or backward whack
3616 LPTSTR pstrBack = (LPTSTR)_cstrrchr(m_lpszRoot, _T('\\' ));
3617 LPTSTR pstrFront = (LPTSTR)_cstrrchr(m_lpszRoot, _T('/') );
3618
3619 if(pstrFront != NULL || pstrBack != NULL)
3620 {
3621 if(pstrFront == NULL)
3622 pstrFront = m_lpszRoot;
3623 if(pstrBack == NULL)
3624 pstrBack = m_lpszRoot;
3625
3626 // from the start to the last whack is the root
3627
3628 if(pstrFront >= pstrBack)
3629 *pstrFront = _T('\0');
3630 else
3631 *pstrBack = _T('\0');
3632 }
3633 }
3634
3635 m_bFound = TRUE;
3636
3637 return TRUE;
3638 }
3639
3640 BOOL FindNextFile()
3641 {
3642 ATLASSERT(m_hFind != NULL);
3643
3644 if(m_hFind == NULL)
3645 return FALSE;
3646
3647 if(!m_bFound)
3648 return FALSE;
3649
3650 m_bFound = ::FindNextFile(m_hFind, &m_fd);
3651
3652 return m_bFound;
3653 }
3654
3655 void Close()
3656 {
3657 m_bFound = FALSE;
3658
3659 if(m_hFind != NULL && m_hFind != INVALID_HANDLE_VALUE)
3660 {
3661 ::FindClose(m_hFind);
3662 m_hFind = NULL;
3663 }
3664 }
3665
3666 // Helper
3667 static const TCHAR* _cstrrchr(const TCHAR* p, TCHAR ch)
3668 {
3669 #ifdef _ATL_MIN_CRT
3670 const TCHAR* lpsz = NULL;
3671 while (*p != 0)
3672 {
3673 if (*p == ch)
3674 lpsz = p;
3675 p = ::CharNext(p);
3676 }
3677 return lpsz;
3678 #else // !_ATL_MIN_CRT
3679 return _tcsrchr(p, ch);
3680 #endif // !_ATL_MIN_CRT
3681 }
3682 };
3683
3684
3685 ///////////////////////////////////////////////////////////////////////////////
3686 // Global functions for loading resources
3687
3688 inline HACCEL AtlLoadAccelerators(ATL::_U_STRINGorID table)
3689 {
3690 return ::LoadAccelerators(ModuleHelper::GetResourceInstance(), table.m_l pstr);
3691 }
3692
3693 inline HMENU AtlLoadMenu(ATL::_U_STRINGorID menu)
3694 {
3695 return ::LoadMenu(ModuleHelper::GetResourceInstance(), menu.m_lpstr);
3696 }
3697
3698 inline HBITMAP AtlLoadBitmap(ATL::_U_STRINGorID bitmap)
3699 {
3700 return ::LoadBitmap(ModuleHelper::GetResourceInstance(), bitmap.m_lpstr) ;
3701 }
3702
3703 #ifdef OEMRESOURCE
3704 inline HBITMAP AtlLoadSysBitmap(ATL::_U_STRINGorID bitmap)
3705 {
3706 #ifdef _DEBUG
3707 WORD wID = (WORD)bitmap.m_lpstr;
3708 ATLASSERT(wID >= 32734 && wID <= 32767);
3709 #endif // _DEBUG
3710 return ::LoadBitmap(NULL, bitmap.m_lpstr);
3711 }
3712 #endif // OEMRESOURCE
3713
3714 inline HCURSOR AtlLoadCursor(ATL::_U_STRINGorID cursor)
3715 {
3716 return ::LoadCursor(ModuleHelper::GetResourceInstance(), cursor.m_lpstr) ;
3717 }
3718
3719 inline HCURSOR AtlLoadSysCursor(LPCTSTR lpCursorName)
3720 {
3721 #if (WINVER >= 0x0500)
3722 ATLASSERT(lpCursorName == IDC_ARROW || lpCursorName == IDC_IBEAM || lpCu rsorName == IDC_WAIT ||
3723 lpCursorName == IDC_CROSS || lpCursorName == IDC_UPARROW || lpCu rsorName == IDC_SIZE ||
3724 lpCursorName == IDC_ICON || lpCursorName == IDC_SIZENWSE || lpCu rsorName == IDC_SIZENESW ||
3725 lpCursorName == IDC_SIZEWE || lpCursorName == IDC_SIZENS || lpCu rsorName == IDC_SIZEALL ||
3726 lpCursorName == IDC_NO || lpCursorName == IDC_APPSTARTING || lpC ursorName == IDC_HELP ||
3727 lpCursorName == IDC_HAND);
3728 #else // !(WINVER >= 0x0500)
3729 ATLASSERT(lpCursorName == IDC_ARROW || lpCursorName == IDC_IBEAM || lpCu rsorName == IDC_WAIT ||
3730 lpCursorName == IDC_CROSS || lpCursorName == IDC_UPARROW || lpCu rsorName == IDC_SIZE ||
3731 lpCursorName == IDC_ICON || lpCursorName == IDC_SIZENWSE || lpCu rsorName == IDC_SIZENESW ||
3732 lpCursorName == IDC_SIZEWE || lpCursorName == IDC_SIZENS || lpCu rsorName == IDC_SIZEALL ||
3733 lpCursorName == IDC_NO || lpCursorName == IDC_APPSTARTING || lpC ursorName == IDC_HELP);
3734 #endif // !(WINVER >= 0x0500)
3735 return ::LoadCursor(NULL, lpCursorName);
3736 }
3737
3738 inline HICON AtlLoadIcon(ATL::_U_STRINGorID icon)
3739 {
3740 return ::LoadIcon(ModuleHelper::GetResourceInstance(), icon.m_lpstr);
3741 }
3742
3743 #ifndef _WIN32_WCE
3744 inline HICON AtlLoadSysIcon(LPCTSTR lpIconName)
3745 {
3746 #if (WINVER >= 0x0600)
3747 ATLASSERT(lpIconName == IDI_APPLICATION || lpIconName == IDI_ASTERISK || lpIconName == IDI_EXCLAMATION ||
3748 lpIconName == IDI_HAND || lpIconName == IDI_QUESTION || lpIcon Name == 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 || lpIcon Name == IDI_WINLOGO);
3753 #endif // !(WINVER >= 0x0600)
3754 return ::LoadIcon(NULL, lpIconName);
3755 }
3756 #endif // !_WIN32_WCE
3757
3758 inline HBITMAP AtlLoadBitmapImage(ATL::_U_STRINGorID bitmap, UINT fuLoad = LR_DE FAULTCOLOR)
3759 {
3760 return (HBITMAP)::LoadImage(ModuleHelper::GetResourceInstance(), bitmap. m_lpstr, IMAGE_BITMAP, 0, 0, fuLoad);
3761 }
3762
3763 inline HCURSOR AtlLoadCursorImage(ATL::_U_STRINGorID cursor, UINT fuLoad = LR_DE FAULTCOLOR | LR_DEFAULTSIZE, int cxDesired = 0, int cyDesired = 0)
3764 {
3765 return (HCURSOR)::LoadImage(ModuleHelper::GetResourceInstance(), cursor. m_lpstr, IMAGE_CURSOR, cxDesired, cyDesired, fuLoad);
3766 }
3767
3768 inline HICON AtlLoadIconImage(ATL::_U_STRINGorID icon, UINT fuLoad = LR_DEFAULTC OLOR | LR_DEFAULTSIZE, int cxDesired = 0, int cyDesired = 0)
3769 {
3770 return (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), icon.m_lp str, IMAGE_ICON, cxDesired, cyDesired, fuLoad);
3771 }
3772
3773 #ifdef OEMRESOURCE
3774 inline HBITMAP AtlLoadSysBitmapImage(WORD wBitmapID, UINT fuLoad = LR_DEFAULTCOL OR)
3775 {
3776 ATLASSERT(wBitmapID >= 32734 && wBitmapID <= 32767);
3777 ATLASSERT((fuLoad & LR_LOADFROMFILE) == 0); // this one doesn't load f rom a file
3778 return (HBITMAP)::LoadImage(NULL, MAKEINTRESOURCE(wBitmapID), IMAGE_BITM AP, 0, 0, fuLoad);
3779 }
3780 #endif // OEMRESOURCE
3781
3782 inline HCURSOR AtlLoadSysCursorImage(ATL::_U_STRINGorID cursor, UINT fuLoad = LR _DEFAULTCOLOR | LR_DEFAULTSIZE, int cxDesired = 0, int cyDesired = 0)
3783 {
3784 #ifdef _DEBUG
3785 WORD wID = (WORD)cursor.m_lpstr;
3786 ATLASSERT((wID >= 32512 && wID <= 32516) || (wID >= 32640 && wID <= 3264 8) || (wID == 32650) || (wID == 32651));
3787 ATLASSERT((fuLoad & LR_LOADFROMFILE) == 0); // this one doesn't load f rom a file
3788 #endif // _DEBUG
3789 return (HCURSOR)::LoadImage(NULL, cursor.m_lpstr, IMAGE_CURSOR, cxDesire d, cyDesired, fuLoad);
3790 }
3791
3792 inline HICON AtlLoadSysIconImage(ATL::_U_STRINGorID icon, UINT fuLoad = LR_DEFAU LTCOLOR | LR_DEFAULTSIZE, int cxDesired = 0, int cyDesired = 0)
3793 {
3794 #ifdef _DEBUG
3795 WORD wID = (WORD)icon.m_lpstr;
3796 ATLASSERT(wID >= 32512 && wID <= 32517);
3797 ATLASSERT((fuLoad & LR_LOADFROMFILE) == 0); // this one doesn't load f rom a file
3798 #endif // _DEBUG
3799 return (HICON)::LoadImage(NULL, icon.m_lpstr, IMAGE_ICON, cxDesired, cyD esired, fuLoad);
3800 }
3801
3802 #if (_ATL_VER < 0x0700)
3803 inline int AtlLoadString(UINT uID, LPTSTR lpBuffer, int nBufferMax)
3804 {
3805 return ::LoadString(_Module.GetResourceInstance(), uID, lpBuffer, nBuffe rMax);
3806 }
3807 #endif // (_ATL_VER < 0x0700)
3808
3809 #ifdef _WIN32_WCE // CE only direct access to the resource
3810 inline LPCTSTR AtlLoadString(UINT uID)
3811 {
3812 LPCTSTR s = (LPCTSTR)::LoadString(ModuleHelper::GetResourceInstance(), u ID, NULL, 0);
3813 #ifdef DEBUG // Check for null-termination
3814 if(s != NULL)
3815 // Note: RC -n <file.rc> compiles null-terminated resource strin gs
3816 ATLASSERT(s[*((WORD*)s -1) - 1] == L'\0');
3817 #endif
3818 return s;
3819 }
3820 #endif // _WIN32_WCE
3821
3822 inline bool AtlLoadString(UINT uID, BSTR& bstrText)
3823 {
3824 USES_CONVERSION;
3825 ATLASSERT(bstrText == NULL);
3826
3827 LPTSTR lpstrText = NULL;
3828 int nRes = 0;
3829 for(int nLen = 256; ; nLen *= 2)
3830 {
3831 ATLTRY(lpstrText = new TCHAR[nLen]);
3832 if(lpstrText == NULL)
3833 break;
3834 nRes = ::LoadString(ModuleHelper::GetResourceInstance(), uID, lp strText, nLen);
3835 if(nRes < nLen - 1)
3836 break;
3837 delete [] lpstrText;
3838 lpstrText = NULL;
3839 }
3840
3841 if(lpstrText != NULL)
3842 {
3843 if(nRes != 0)
3844 bstrText = ::SysAllocString(T2OLE(lpstrText));
3845 delete [] lpstrText;
3846 }
3847
3848 return (bstrText != NULL) ? true : false;
3849 }
3850
3851
3852 ///////////////////////////////////////////////////////////////////////////////
3853 // Global functions for stock GDI objects
3854
3855 inline HPEN AtlGetStockPen(int nPen)
3856 {
3857 #if (_WIN32_WINNT >= 0x0500) && !defined(_WIN32_WCE)
3858 ATLASSERT(nPen == WHITE_PEN || nPen == BLACK_PEN || nPen == NULL_PEN || nPen == DC_PEN);
3859 #else
3860 ATLASSERT(nPen == WHITE_PEN || nPen == BLACK_PEN || nPen == NULL_PEN);
3861 #endif
3862 return (HPEN)::GetStockObject(nPen);
3863 }
3864
3865 inline HBRUSH AtlGetStockBrush(int nBrush)
3866 {
3867 #if (_WIN32_WINNT >= 0x0500) && !defined(_WIN32_WCE)
3868 ATLASSERT((nBrush >= WHITE_BRUSH && nBrush <= HOLLOW_BRUSH) || nBrush == DC_BRUSH);
3869 #else
3870 ATLASSERT(nBrush >= WHITE_BRUSH && nBrush <= HOLLOW_BRUSH);
3871 #endif
3872 return (HBRUSH)::GetStockObject(nBrush);
3873 }
3874
3875 inline HFONT AtlGetStockFont(int nFont)
3876 {
3877 #ifndef _WIN32_WCE
3878 ATLASSERT((nFont >= OEM_FIXED_FONT && nFont <= SYSTEM_FIXED_FONT) || nFo nt == DEFAULT_GUI_FONT);
3879 #else // CE specific
3880 ATLASSERT(nFont == SYSTEM_FONT);
3881 #endif // _WIN32_WCE
3882 return (HFONT)::GetStockObject(nFont);
3883 }
3884
3885 inline HPALETTE AtlGetStockPalette(int nPalette)
3886 {
3887 ATLASSERT(nPalette == DEFAULT_PALETTE); // the only one supported
3888 return (HPALETTE)::GetStockObject(nPalette);
3889 }
3890
3891
3892 ///////////////////////////////////////////////////////////////////////////////
3893 // Global function for compacting a path by replacing parts with ellipsis
3894
3895 // helper for multi-byte character sets
3896 inline bool _IsDBCSTrailByte(LPCTSTR lpstr, int nChar)
3897 {
3898 #ifndef _UNICODE
3899 int i = nChar;
3900 for( ; i > 0; i--)
3901 {
3902 if(!::IsDBCSLeadByte(lpstr[i - 1]))
3903 break;
3904 }
3905 return ((nChar > 0) && (((nChar - i) & 1) != 0));
3906 #else // _UNICODE
3907 lpstr; nChar;
3908 return false;
3909 #endif // _UNICODE
3910 }
3911
3912 inline bool AtlCompactPath(LPTSTR lpstrOut, LPCTSTR lpstrIn, int cchLen)
3913 {
3914 ATLASSERT(lpstrOut != NULL);
3915 ATLASSERT(lpstrIn != NULL);
3916 ATLASSERT(cchLen > 0);
3917
3918 LPCTSTR szEllipsis = _T("...");
3919 const int cchEndEllipsis = 3;
3920 const int cchMidEllipsis = 4;
3921
3922 if(lstrlen(lpstrIn) < cchLen)
3923 {
3924 SecureHelper::strcpy_x(lpstrOut, cchLen, lpstrIn);
3925 return true;
3926 }
3927
3928 lpstrOut[0] = 0;
3929
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(lpst r))
3933 {
3934 if((*lpstr == _T('/')) || (*lpstr == _T('\\')))
3935 chSlash = *lpstr;
3936 }
3937
3938 // find the filename portion of the path
3939 LPCTSTR lpstrFileName = lpstrIn;
3940 for(LPCTSTR pPath = lpstrIn; *pPath; pPath = ::CharNext(pPath))
3941 {
3942 if((pPath[0] == _T('\\') || pPath[0] == _T(':') || pPath[0] == _ T('/'))
3943 && pPath[1] && pPath[1] != _T('\\') && pPath[1] != _T('/'))
3944 lpstrFileName = pPath + 1;
3945 }
3946 int cchFileName = lstrlen(lpstrFileName);
3947
3948 // handle just the filename without a path
3949 if(lpstrFileName == lpstrIn && cchLen > cchEndEllipsis)
3950 {
3951 bool bRet = (SecureHelper::strncpy_x(lpstrOut, cchLen, lpstrIn, cchLen - cchEndEllipsis - 1) == 0);
3952 if(bRet)
3953 {
3954 #ifndef _UNICODE
3955 if(_IsDBCSTrailByte(lpstrIn, cchLen - cchEndEllipsis))
3956 lpstrOut[cchLen - cchEndEllipsis - 1] = 0;
3957 #endif // _UNICODE
3958 SecureHelper::strcat_x(lpstrOut, cchLen, szEllipsis);
3959 }
3960 return bRet;
3961 }
3962
3963 // handle just ellipsis
3964 if((cchLen < (cchMidEllipsis + cchEndEllipsis)))
3965 {
3966 for(int i = 0; i < cchLen - 1; i++)
3967 lpstrOut[i] = ((i + 1) == cchMidEllipsis) ? chSlash : _T ('.');
3968 lpstrOut[cchLen - 1] = 0;
3969 return true;
3970 }
3971
3972 // calc how much we have to copy
3973 int cchToCopy = cchLen - (cchMidEllipsis + cchFileName) - 1;
3974
3975 if(cchToCopy < 0)
3976 cchToCopy = 0;
3977
3978 #ifndef _UNICODE
3979 if(cchToCopy > 0 && _IsDBCSTrailByte(lpstrIn, cchToCopy))
3980 cchToCopy--;
3981 #endif // _UNICODE
3982
3983 bool bRet = (SecureHelper::strncpy_x(lpstrOut, cchLen, lpstrIn, cchToCop y) == 0);
3984 if(!bRet)
3985 return false;
3986
3987 // add ellipsis
3988 SecureHelper::strcat_x(lpstrOut, cchLen, szEllipsis);
3989 if(!bRet)
3990 return false;
3991 TCHAR szSlash[2] = { chSlash, 0 };
3992 SecureHelper::strcat_x(lpstrOut, cchLen, szSlash);
3993 if(!bRet)
3994 return false;
3995
3996 // add filename (and ellipsis, if needed)
3997 if(cchLen > (cchMidEllipsis + cchFileName))
3998 {
3999 SecureHelper::strcat_x(lpstrOut, cchLen, lpstrFileName);
4000 }
4001 else
4002 {
4003 cchToCopy = cchLen - cchMidEllipsis - cchEndEllipsis - 1;
4004 #ifndef _UNICODE
4005 if(cchToCopy > 0 && _IsDBCSTrailByte(lpstrFileName, cchToCopy))
4006 cchToCopy--;
4007 #endif // _UNICODE
4008 bRet = (SecureHelper::strncpy_x(&lpstrOut[cchMidEllipsis], cchLe n - cchMidEllipsis, lpstrFileName, cchToCopy) == 0);
4009 if(bRet)
4010 SecureHelper::strcat_x(lpstrOut, cchLen, szEllipsis);
4011 }
4012
4013 return bRet;
4014 }
4015
4016 }; // namespace WTL
4017
4018 #endif // __ATLMISC_H__
OLDNEW
« no previous file with comments | « third_party/wtl/include/atlgdi.h ('k') | third_party/wtl/include/atlprint.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698