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 |