OLD | NEW |
| (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__ | |
OLD | NEW |