Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3271 lines
85 KiB

  1. // WTL Version 3.1
  2. // Copyright (C) 1997-2000 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This file is a part of Windows Template Library.
  6. // The code and information is provided "as-is" without
  7. // warranty of any kind, either expressed or implied.
  8. #ifndef __ATLMISC_H__
  9. #define __ATLMISC_H__
  10. #pragma once
  11. #ifndef __cplusplus
  12. #error ATL requires C++ compilation (use a .cpp suffix)
  13. #endif
  14. #ifndef __ATLAPP_H__
  15. #error atlmisc.h requires atlapp.h to be included first
  16. #endif
  17. #ifndef _WTL_NO_WTYPES
  18. #define __ATLTYPES_H__
  19. #endif //!_WTL_NO_WTYPES
  20. #ifdef _ATL_TMP_NO_CSTRING
  21. #define _WTL_NO_CSTRING
  22. #endif
  23. #ifndef _WTL_NO_CSTRING
  24. #define __ATLSTR_H__
  25. #if defined(_ATL_USE_CSTRING_FLOAT) && defined(_ATL_MIN_CRT)
  26. #error Cannot use CString floating point formatting with _ATL_MIN_CRT defined
  27. #endif //defined(_ATL_USE_CSTRING_FLOAT) && defined(_ATL_MIN_CRT)
  28. #ifndef _DEBUG
  29. #include <stdio.h>
  30. #endif //!_DEBUG
  31. #endif //!_WTL_NO_CSTRING
  32. namespace WTL
  33. {
  34. /////////////////////////////////////////////////////////////////////////////
  35. // Forward declarations
  36. #ifndef _WTL_NO_WTYPES
  37. class CSize;
  38. class CPoint;
  39. class CRect;
  40. #endif //!_WTL_NO_WTYPES
  41. #ifndef _WTL_NO_CSTRING
  42. class CString;
  43. #endif //!_WTL_NO_CSTRING
  44. template <class T, int t_cchItemLen> class CRecentDocumentListBase;
  45. class CRecentDocumentList;
  46. class CFindFile;
  47. /////////////////////////////////////////////////////////////////////////////
  48. // CSize - Wrapper for Windows SIZE structure.
  49. #ifndef _WTL_NO_WTYPES
  50. class CSize : public tagSIZE
  51. {
  52. public:
  53. // Constructors
  54. CSize();
  55. CSize(int initCX, int initCY);
  56. CSize(SIZE initSize);
  57. CSize(POINT initPt);
  58. CSize(DWORD dwSize);
  59. // Operations
  60. BOOL operator==(SIZE size) const;
  61. BOOL operator!=(SIZE size) const;
  62. void operator+=(SIZE size);
  63. void operator-=(SIZE size);
  64. void SetSize(int CX, int CY);
  65. // Operators returning CSize values
  66. CSize operator+(SIZE size) const;
  67. CSize operator-(SIZE size) const;
  68. CSize operator-() const;
  69. // Operators returning CPoint values
  70. CPoint operator+(POINT point) const;
  71. CPoint operator-(POINT point) const;
  72. // Operators returning CRect values
  73. CRect operator+(const RECT* lpRect) const;
  74. CRect operator-(const RECT* lpRect) const;
  75. };
  76. /////////////////////////////////////////////////////////////////////////////
  77. // CPoint - Wrapper for Windows POINT structure.
  78. class CPoint : public tagPOINT
  79. {
  80. public:
  81. // Constructors
  82. CPoint();
  83. CPoint(int initX, int initY);
  84. CPoint(POINT initPt);
  85. CPoint(SIZE initSize);
  86. CPoint(DWORD dwPoint);
  87. // Operations
  88. void Offset(int xOffset, int yOffset);
  89. void Offset(POINT point);
  90. void Offset(SIZE size);
  91. BOOL operator==(POINT point) const;
  92. BOOL operator!=(POINT point) const;
  93. void operator+=(SIZE size);
  94. void operator-=(SIZE size);
  95. void operator+=(POINT point);
  96. void operator-=(POINT point);
  97. void SetPoint(int X, int Y);
  98. // Operators returning CPoint values
  99. CPoint operator+(SIZE size) const;
  100. CPoint operator-(SIZE size) const;
  101. CPoint operator-() const;
  102. CPoint operator+(POINT point) const;
  103. // Operators returning CSize values
  104. CSize operator-(POINT point) const;
  105. // Operators returning CRect values
  106. CRect operator+(const RECT* lpRect) const;
  107. CRect operator-(const RECT* lpRect) const;
  108. };
  109. /////////////////////////////////////////////////////////////////////////////
  110. // CRect - Wrapper for Windows RECT structure.
  111. class CRect : public tagRECT
  112. {
  113. public:
  114. // Constructors
  115. CRect();
  116. CRect(int l, int t, int r, int b);
  117. CRect(const RECT& srcRect);
  118. CRect(LPCRECT lpSrcRect);
  119. CRect(POINT point, SIZE size);
  120. CRect(POINT topLeft, POINT bottomRight);
  121. // Attributes (in addition to RECT members)
  122. int Width() const;
  123. int Height() const;
  124. CSize Size() const;
  125. CPoint& TopLeft();
  126. CPoint& BottomRight();
  127. const CPoint& TopLeft() const;
  128. const CPoint& BottomRight() const;
  129. CPoint CenterPoint() const;
  130. // convert between CRect and LPRECT/LPCRECT (no need for &)
  131. operator LPRECT();
  132. operator LPCRECT() const;
  133. BOOL IsRectEmpty() const;
  134. BOOL IsRectNull() const;
  135. BOOL PtInRect(POINT point) const;
  136. // Operations
  137. void SetRect(int x1, int y1, int x2, int y2);
  138. void SetRect(POINT topLeft, POINT bottomRight);
  139. void SetRectEmpty();
  140. void CopyRect(LPCRECT lpSrcRect);
  141. BOOL EqualRect(LPCRECT lpRect) const;
  142. void InflateRect(int x, int y);
  143. void InflateRect(SIZE size);
  144. void InflateRect(LPCRECT lpRect);
  145. void InflateRect(int l, int t, int r, int b);
  146. void DeflateRect(int x, int y);
  147. void DeflateRect(SIZE size);
  148. void DeflateRect(LPCRECT lpRect);
  149. void DeflateRect(int l, int t, int r, int b);
  150. void OffsetRect(int x, int y);
  151. void OffsetRect(SIZE size);
  152. void OffsetRect(POINT point);
  153. void NormalizeRect();
  154. // absolute position of rectangle
  155. void MoveToY(int y);
  156. void MoveToX(int x);
  157. void MoveToXY(int x, int y);
  158. void MoveToXY(POINT point);
  159. // operations that fill '*this' with result
  160. BOOL IntersectRect(LPCRECT lpRect1, LPCRECT lpRect2);
  161. BOOL UnionRect(LPCRECT lpRect1, LPCRECT lpRect2);
  162. BOOL SubtractRect(LPCRECT lpRectSrc1, LPCRECT lpRectSrc2);
  163. // Additional Operations
  164. void operator=(const RECT& srcRect);
  165. BOOL operator==(const RECT& rect) const;
  166. BOOL operator!=(const RECT& rect) const;
  167. void operator+=(POINT point);
  168. void operator+=(SIZE size);
  169. void operator+=(LPCRECT lpRect);
  170. void operator-=(POINT point);
  171. void operator-=(SIZE size);
  172. void operator-=(LPCRECT lpRect);
  173. void operator&=(const RECT& rect);
  174. void operator|=(const RECT& rect);
  175. // Operators returning CRect values
  176. CRect operator+(POINT point) const;
  177. CRect operator-(POINT point) const;
  178. CRect operator+(LPCRECT lpRect) const;
  179. CRect operator+(SIZE size) const;
  180. CRect operator-(SIZE size) const;
  181. CRect operator-(LPCRECT lpRect) const;
  182. CRect operator&(const RECT& rect2) const;
  183. CRect operator|(const RECT& rect2) const;
  184. CRect MulDiv(int nMultiplier, int nDivisor) const;
  185. };
  186. /////////////////////////////////////////////////////////////////////////////
  187. // CSize, CPoint, CRect Implementation
  188. // CSize
  189. inline CSize::CSize()
  190. { /* random filled */ }
  191. inline CSize::CSize(int initCX, int initCY)
  192. { cx = initCX; cy = initCY; }
  193. inline CSize::CSize(SIZE initSize)
  194. { *(SIZE*)this = initSize; }
  195. inline CSize::CSize(POINT initPt)
  196. { *(POINT*)this = initPt; }
  197. inline CSize::CSize(DWORD dwSize)
  198. {
  199. cx = (short)LOWORD(dwSize);
  200. cy = (short)HIWORD(dwSize);
  201. }
  202. inline BOOL CSize::operator==(SIZE size) const
  203. { return (cx == size.cx && cy == size.cy); }
  204. inline BOOL CSize::operator!=(SIZE size) const
  205. { return (cx != size.cx || cy != size.cy); }
  206. inline void CSize::operator+=(SIZE size)
  207. { cx += size.cx; cy += size.cy; }
  208. inline void CSize::operator-=(SIZE size)
  209. { cx -= size.cx; cy -= size.cy; }
  210. inline void CSize::SetSize(int CX, int CY)
  211. { cx = CX; cy = CY; }
  212. inline CSize CSize::operator+(SIZE size) const
  213. { return CSize(cx + size.cx, cy + size.cy); }
  214. inline CSize CSize::operator-(SIZE size) const
  215. { return CSize(cx - size.cx, cy - size.cy); }
  216. inline CSize CSize::operator-() const
  217. { return CSize(-cx, -cy); }
  218. inline CPoint CSize::operator+(POINT point) const
  219. { return CPoint(cx + point.x, cy + point.y); }
  220. inline CPoint CSize::operator-(POINT point) const
  221. { return CPoint(cx - point.x, cy - point.y); }
  222. inline CRect CSize::operator+(const RECT* lpRect) const
  223. { return CRect(lpRect) + *this; }
  224. inline CRect CSize::operator-(const RECT* lpRect) const
  225. { return CRect(lpRect) - *this; }
  226. // CPoint
  227. inline CPoint::CPoint()
  228. { /* random filled */ }
  229. inline CPoint::CPoint(int initX, int initY)
  230. { x = initX; y = initY; }
  231. inline CPoint::CPoint(POINT initPt)
  232. { *(POINT*)this = initPt; }
  233. inline CPoint::CPoint(SIZE initSize)
  234. { *(SIZE*)this = initSize; }
  235. inline CPoint::CPoint(DWORD dwPoint)
  236. {
  237. x = (short)LOWORD(dwPoint);
  238. y = (short)HIWORD(dwPoint);
  239. }
  240. inline void CPoint::Offset(int xOffset, int yOffset)
  241. { x += xOffset; y += yOffset; }
  242. inline void CPoint::Offset(POINT point)
  243. { x += point.x; y += point.y; }
  244. inline void CPoint::Offset(SIZE size)
  245. { x += size.cx; y += size.cy; }
  246. inline BOOL CPoint::operator==(POINT point) const
  247. { return (x == point.x && y == point.y); }
  248. inline BOOL CPoint::operator!=(POINT point) const
  249. { return (x != point.x || y != point.y); }
  250. inline void CPoint::operator+=(SIZE size)
  251. { x += size.cx; y += size.cy; }
  252. inline void CPoint::operator-=(SIZE size)
  253. { x -= size.cx; y -= size.cy; }
  254. inline void CPoint::operator+=(POINT point)
  255. { x += point.x; y += point.y; }
  256. inline void CPoint::operator-=(POINT point)
  257. { x -= point.x; y -= point.y; }
  258. inline void CPoint::SetPoint(int X, int Y)
  259. { x = X; y = Y; }
  260. inline CPoint CPoint::operator+(SIZE size) const
  261. { return CPoint(x + size.cx, y + size.cy); }
  262. inline CPoint CPoint::operator-(SIZE size) const
  263. { return CPoint(x - size.cx, y - size.cy); }
  264. inline CPoint CPoint::operator-() const
  265. { return CPoint(-x, -y); }
  266. inline CPoint CPoint::operator+(POINT point) const
  267. { return CPoint(x + point.x, y + point.y); }
  268. inline CSize CPoint::operator-(POINT point) const
  269. { return CSize(x - point.x, y - point.y); }
  270. inline CRect CPoint::operator+(const RECT* lpRect) const
  271. { return CRect(lpRect) + *this; }
  272. inline CRect CPoint::operator-(const RECT* lpRect) const
  273. { return CRect(lpRect) - *this; }
  274. // CRect
  275. inline CRect::CRect()
  276. { /* random filled */ }
  277. inline CRect::CRect(int l, int t, int r, int b)
  278. { left = l; top = t; right = r; bottom = b; }
  279. inline CRect::CRect(const RECT& srcRect)
  280. { ::CopyRect(this, &srcRect); }
  281. inline CRect::CRect(LPCRECT lpSrcRect)
  282. { ::CopyRect(this, lpSrcRect); }
  283. inline CRect::CRect(POINT point, SIZE size)
  284. { right = (left = point.x) + size.cx; bottom = (top = point.y) + size.cy; }
  285. inline CRect::CRect(POINT topLeft, POINT bottomRight)
  286. { left = topLeft.x; top = topLeft.y;
  287. right = bottomRight.x; bottom = bottomRight.y; }
  288. inline int CRect::Width() const
  289. { return right - left; }
  290. inline int CRect::Height() const
  291. { return bottom - top; }
  292. inline CSize CRect::Size() const
  293. { return CSize(right - left, bottom - top); }
  294. inline CPoint& CRect::TopLeft()
  295. { return *((CPoint*)this); }
  296. inline CPoint& CRect::BottomRight()
  297. { return *((CPoint*)this + 1); }
  298. inline const CPoint& CRect::TopLeft() const
  299. { return *((CPoint*)this); }
  300. inline const CPoint& CRect::BottomRight() const
  301. { return *((CPoint*)this + 1); }
  302. inline CPoint CRect::CenterPoint() const
  303. { return CPoint((left + right) / 2, (top + bottom) / 2); }
  304. inline CRect::operator LPRECT()
  305. { return this; }
  306. inline CRect::operator LPCRECT() const
  307. { return this; }
  308. inline BOOL CRect::IsRectEmpty() const
  309. { return ::IsRectEmpty(this); }
  310. inline BOOL CRect::IsRectNull() const
  311. { return (left == 0 && right == 0 && top == 0 && bottom == 0); }
  312. inline BOOL CRect::PtInRect(POINT point) const
  313. { return ::PtInRect(this, point); }
  314. inline void CRect::SetRect(int x1, int y1, int x2, int y2)
  315. { ::SetRect(this, x1, y1, x2, y2); }
  316. inline void CRect::SetRect(POINT topLeft, POINT bottomRight)
  317. { ::SetRect(this, topLeft.x, topLeft.y, bottomRight.x, bottomRight.y); }
  318. inline void CRect::SetRectEmpty()
  319. { ::SetRectEmpty(this); }
  320. inline void CRect::CopyRect(LPCRECT lpSrcRect)
  321. { ::CopyRect(this, lpSrcRect); }
  322. inline BOOL CRect::EqualRect(LPCRECT lpRect) const
  323. { return ::EqualRect(this, lpRect); }
  324. inline void CRect::InflateRect(int x, int y)
  325. { ::InflateRect(this, x, y); }
  326. inline void CRect::InflateRect(SIZE size)
  327. { ::InflateRect(this, size.cx, size.cy); }
  328. inline void CRect::DeflateRect(int x, int y)
  329. { ::InflateRect(this, -x, -y); }
  330. inline void CRect::DeflateRect(SIZE size)
  331. { ::InflateRect(this, -size.cx, -size.cy); }
  332. inline void CRect::OffsetRect(int x, int y)
  333. { ::OffsetRect(this, x, y); }
  334. inline void CRect::OffsetRect(POINT point)
  335. { ::OffsetRect(this, point.x, point.y); }
  336. inline void CRect::OffsetRect(SIZE size)
  337. { ::OffsetRect(this, size.cx, size.cy); }
  338. inline BOOL CRect::IntersectRect(LPCRECT lpRect1, LPCRECT lpRect2)
  339. { return ::IntersectRect(this, lpRect1, lpRect2);}
  340. inline BOOL CRect::UnionRect(LPCRECT lpRect1, LPCRECT lpRect2)
  341. { return ::UnionRect(this, lpRect1, lpRect2); }
  342. inline void CRect::operator=(const RECT& srcRect)
  343. { ::CopyRect(this, &srcRect); }
  344. inline BOOL CRect::operator==(const RECT& rect) const
  345. { return ::EqualRect(this, &rect); }
  346. inline BOOL CRect::operator!=(const RECT& rect) const
  347. { return !::EqualRect(this, &rect); }
  348. inline void CRect::operator+=(POINT point)
  349. { ::OffsetRect(this, point.x, point.y); }
  350. inline void CRect::operator+=(SIZE size)
  351. { ::OffsetRect(this, size.cx, size.cy); }
  352. inline void CRect::operator+=(LPCRECT lpRect)
  353. { InflateRect(lpRect); }
  354. inline void CRect::operator-=(POINT point)
  355. { ::OffsetRect(this, -point.x, -point.y); }
  356. inline void CRect::operator-=(SIZE size)
  357. { ::OffsetRect(this, -size.cx, -size.cy); }
  358. inline void CRect::operator-=(LPCRECT lpRect)
  359. { DeflateRect(lpRect); }
  360. inline void CRect::operator&=(const RECT& rect)
  361. { ::IntersectRect(this, this, &rect); }
  362. inline void CRect::operator|=(const RECT& rect)
  363. { ::UnionRect(this, this, &rect); }
  364. inline CRect CRect::operator+(POINT pt) const
  365. { CRect rect(*this); ::OffsetRect(&rect, pt.x, pt.y); return rect; }
  366. inline CRect CRect::operator-(POINT pt) const
  367. { CRect rect(*this); ::OffsetRect(&rect, -pt.x, -pt.y); return rect; }
  368. inline CRect CRect::operator+(SIZE size) const
  369. { CRect rect(*this); ::OffsetRect(&rect, size.cx, size.cy); return rect; }
  370. inline CRect CRect::operator-(SIZE size) const
  371. { CRect rect(*this); ::OffsetRect(&rect, -size.cx, -size.cy); return rect; }
  372. inline CRect CRect::operator+(LPCRECT lpRect) const
  373. { CRect rect(this); rect.InflateRect(lpRect); return rect; }
  374. inline CRect CRect::operator-(LPCRECT lpRect) const
  375. { CRect rect(this); rect.DeflateRect(lpRect); return rect; }
  376. inline CRect CRect::operator&(const RECT& rect2) const
  377. { CRect rect; ::IntersectRect(&rect, this, &rect2);
  378. return rect; }
  379. inline CRect CRect::operator|(const RECT& rect2) const
  380. { CRect rect; ::UnionRect(&rect, this, &rect2);
  381. return rect; }
  382. inline BOOL CRect::SubtractRect(LPCRECT lpRectSrc1, LPCRECT lpRectSrc2)
  383. { return ::SubtractRect(this, lpRectSrc1, lpRectSrc2); }
  384. inline void CRect::NormalizeRect()
  385. {
  386. int nTemp;
  387. if (left > right)
  388. {
  389. nTemp = left;
  390. left = right;
  391. right = nTemp;
  392. }
  393. if (top > bottom)
  394. {
  395. nTemp = top;
  396. top = bottom;
  397. bottom = nTemp;
  398. }
  399. }
  400. inline void CRect::MoveToY(int y)
  401. { bottom = Height() + y; top = y; }
  402. inline void CRect::MoveToX(int x)
  403. { right = Width() + x; left = x; }
  404. inline void CRect::MoveToXY(int x, int y)
  405. { MoveToX(x); MoveToY(y); }
  406. inline void CRect::MoveToXY(POINT pt)
  407. { MoveToX(pt.x); MoveToY(pt.y); }
  408. inline void CRect::InflateRect(LPCRECT lpRect)
  409. {
  410. left -= lpRect->left;
  411. top -= lpRect->top;
  412. right += lpRect->right;
  413. bottom += lpRect->bottom;
  414. }
  415. inline void CRect::InflateRect(int l, int t, int r, int b)
  416. {
  417. left -= l;
  418. top -= t;
  419. right += r;
  420. bottom += b;
  421. }
  422. inline void CRect::DeflateRect(LPCRECT lpRect)
  423. {
  424. left += lpRect->left;
  425. top += lpRect->top;
  426. right -= lpRect->right;
  427. bottom -= lpRect->bottom;
  428. }
  429. inline void CRect::DeflateRect(int l, int t, int r, int b)
  430. {
  431. left += l;
  432. top += t;
  433. right -= r;
  434. bottom -= b;
  435. }
  436. inline CRect CRect::MulDiv(int nMultiplier, int nDivisor) const
  437. {
  438. return CRect(
  439. ::MulDiv(left, nMultiplier, nDivisor),
  440. ::MulDiv(top, nMultiplier, nDivisor),
  441. ::MulDiv(right, nMultiplier, nDivisor),
  442. ::MulDiv(bottom, nMultiplier, nDivisor));
  443. }
  444. #endif //!_WTL_NO_WTYPES
  445. /////////////////////////////////////////////////////////////////////////////
  446. // CString - String class
  447. #ifndef _WTL_NO_CSTRING
  448. struct CStringData
  449. {
  450. long nRefs; // reference count
  451. int nDataLength;
  452. int nAllocLength;
  453. // TCHAR data[nAllocLength]
  454. TCHAR* data()
  455. { return (TCHAR*)(this + 1); }
  456. };
  457. // Globals
  458. // For an empty string, m_pchData will point here
  459. // (note: avoids special case of checking for NULL m_pchData)
  460. // empty string data (and locked)
  461. _declspec(selectany) int rgInitData[] = { -1, 0, 0, 0 };
  462. _declspec(selectany) CStringData* _atltmpDataNil = (CStringData*)&rgInitData;
  463. _declspec(selectany) LPCTSTR _atltmpPchNil = (LPCTSTR)(((BYTE*)&rgInitData) + sizeof(CStringData));
  464. class CString
  465. {
  466. public:
  467. // Constructors
  468. CString();
  469. CString(const CString& stringSrc);
  470. CString(TCHAR ch, int nRepeat = 1);
  471. CString(LPCSTR lpsz);
  472. CString(LPCWSTR lpsz);
  473. CString(LPCTSTR lpch, int nLength);
  474. CString(const unsigned char* psz);
  475. // Attributes & Operations
  476. // as an array of characters
  477. int GetLength() const;
  478. BOOL IsEmpty() const;
  479. void Empty(); // free up the data
  480. TCHAR GetAt(int nIndex) const; // 0 based
  481. TCHAR operator[](int nIndex) const; // same as GetAt
  482. void SetAt(int nIndex, TCHAR ch);
  483. operator LPCTSTR() const; // as a C string
  484. // overloaded assignment
  485. const CString& operator=(const CString& stringSrc);
  486. const CString& operator=(TCHAR ch);
  487. #ifdef _UNICODE
  488. const CString& operator=(char ch);
  489. #endif
  490. const CString& operator=(LPCSTR lpsz);
  491. const CString& operator=(LPCWSTR lpsz);
  492. const CString& operator=(const unsigned char* psz);
  493. // string concatenation
  494. const CString& operator+=(const CString& string);
  495. const CString& operator+=(TCHAR ch);
  496. #ifdef _UNICODE
  497. const CString& operator+=(char ch);
  498. #endif
  499. const CString& operator+=(LPCTSTR lpsz);
  500. friend CString __stdcall operator+(const CString& string1, const CString& string2);
  501. friend CString __stdcall operator+(const CString& string, TCHAR ch);
  502. friend CString __stdcall operator+(TCHAR ch, const CString& string);
  503. #ifdef _UNICODE
  504. friend CString __stdcall operator+(const CString& string, char ch);
  505. friend CString __stdcall operator+(char ch, const CString& string);
  506. #endif
  507. friend CString __stdcall operator+(const CString& string, LPCTSTR lpsz);
  508. friend CString __stdcall operator+(LPCTSTR lpsz, const CString& string);
  509. // string comparison
  510. int Compare(LPCTSTR lpsz) const; // straight character
  511. int CompareNoCase(LPCTSTR lpsz) const; // ignore case
  512. int Collate(LPCTSTR lpsz) const; // NLS aware
  513. // simple sub-string extraction
  514. CString Mid(int nFirst, int nCount) const;
  515. CString Mid(int nFirst) const;
  516. CString Left(int nCount) const;
  517. CString Right(int nCount) const;
  518. CString SpanIncluding(LPCTSTR lpszCharSet) const;
  519. CString SpanExcluding(LPCTSTR lpszCharSet) const;
  520. // upper/lower/reverse conversion
  521. void MakeUpper();
  522. void MakeLower();
  523. void MakeReverse();
  524. // trimming whitespace (either side)
  525. void TrimRight();
  526. void TrimLeft();
  527. // advanced manipulation
  528. // replace occurrences of chOld with chNew
  529. int Replace(TCHAR chOld, TCHAR chNew);
  530. // replace occurrences of substring lpszOld with lpszNew;
  531. // empty lpszNew removes instances of lpszOld
  532. int Replace(LPCTSTR lpszOld, LPCTSTR lpszNew);
  533. // remove occurrences of chRemove
  534. int Remove(TCHAR chRemove);
  535. // insert character at zero-based index; concatenates
  536. // if index is past end of string
  537. int Insert(int nIndex, TCHAR ch);
  538. // insert substring at zero-based index; concatenates
  539. // if index is past end of string
  540. int Insert(int nIndex, LPCTSTR pstr);
  541. // delete nCount characters starting at zero-based index
  542. int Delete(int nIndex, int nCount = 1);
  543. // searching (return starting index, or -1 if not found)
  544. // look for a single character match
  545. int Find(TCHAR ch) const; // like "C" strchr
  546. int ReverseFind(TCHAR ch) const;
  547. int FindOneOf(LPCTSTR lpszCharSet) const;
  548. // look for a specific sub-string
  549. int Find(LPCTSTR lpszSub) const; // like "C" strstr
  550. // Concatentation for non strings
  551. const CString& Append(int n)
  552. {
  553. TCHAR szBuffer[10];
  554. wsprintf(szBuffer,_T("%d"),n);
  555. ConcatInPlace(SafeStrlen(szBuffer), szBuffer);
  556. return *this;
  557. }
  558. // simple formatting
  559. void __cdecl Format(LPCTSTR lpszFormat, ...);
  560. void __cdecl Format(UINT nFormatID, ...);
  561. // formatting for localization (uses FormatMessage API)
  562. BOOL __cdecl FormatMessage(LPCTSTR lpszFormat, ...);
  563. BOOL __cdecl FormatMessage(UINT nFormatID, ...);
  564. // Windows support
  565. BOOL LoadString(UINT nID); // load from string resource
  566. // 255 chars max
  567. #ifndef _UNICODE
  568. // ANSI <-> OEM support (convert string in place)
  569. void AnsiToOem();
  570. void OemToAnsi();
  571. #endif
  572. #ifndef _ATL_NO_COM
  573. // OLE BSTR support (use for OLE automation)
  574. BSTR AllocSysString() const;
  575. BSTR SetSysString(BSTR* pbstr) const;
  576. #endif //!_ATL_NO_COM
  577. // Access to string implementation buffer as "C" character array
  578. LPTSTR GetBuffer(int nMinBufLength);
  579. void ReleaseBuffer(int nNewLength = -1);
  580. LPTSTR GetBufferSetLength(int nNewLength);
  581. void FreeExtra();
  582. // Use LockBuffer/UnlockBuffer to turn refcounting off
  583. LPTSTR LockBuffer();
  584. void UnlockBuffer();
  585. // Implementation
  586. public:
  587. ~CString();
  588. int GetAllocLength() const;
  589. static BOOL __stdcall _IsValidString(LPCWSTR lpsz, int nLength)
  590. {
  591. if(lpsz == NULL)
  592. return FALSE;
  593. return !::IsBadStringPtrW(lpsz, nLength);
  594. }
  595. static BOOL __stdcall _IsValidString(LPCSTR lpsz, int nLength)
  596. {
  597. if(lpsz == NULL)
  598. return FALSE;
  599. return !::IsBadStringPtrA(lpsz, nLength);
  600. }
  601. protected:
  602. LPTSTR m_pchData; // pointer to ref counted string data
  603. // implementation helpers
  604. CStringData* GetData() const;
  605. void Init();
  606. void AllocCopy(CString& dest, int nCopyLen, int nCopyIndex, int nExtraLen) const;
  607. BOOL AllocBuffer(int nLen);
  608. void AssignCopy(int nSrcLen, LPCTSTR lpszSrcData);
  609. BOOL ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data, int nSrc2Len, LPCTSTR lpszSrc2Data);
  610. void ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData);
  611. void FormatV(LPCTSTR lpszFormat, va_list argList);
  612. void CopyBeforeWrite();
  613. BOOL AllocBeforeWrite(int nLen);
  614. void Release();
  615. static void PASCAL Release(CStringData* pData);
  616. static int PASCAL SafeStrlen(LPCTSTR lpsz);
  617. static int __stdcall _LoadString(UINT nID, LPTSTR lpszBuf, UINT nMaxBuf)
  618. {
  619. #ifdef _DEBUG
  620. // LoadString without annoying warning from the Debug kernel if the
  621. // segment containing the string is not present
  622. if (::FindResource(_Module.GetResourceInstance(), MAKEINTRESOURCE((nID>>4) + 1), RT_STRING) == NULL)
  623. {
  624. lpszBuf[0] = '\0';
  625. return 0; // not found
  626. }
  627. #endif //_DEBUG
  628. int nLen = ::LoadString(_Module.GetResourceInstance(), nID, lpszBuf, nMaxBuf);
  629. if (nLen == 0)
  630. lpszBuf[0] = '\0';
  631. return nLen;
  632. }
  633. static const CString& __stdcall _GetEmptyString()
  634. {
  635. return *(CString*)&_atltmpPchNil;
  636. }
  637. // CString conversion helpers
  638. static int __cdecl _wcstombsz(char* mbstr, const wchar_t* wcstr, size_t count)
  639. {
  640. if (count == 0 && mbstr != NULL)
  641. return 0;
  642. int result = ::WideCharToMultiByte(CP_ACP, 0, wcstr, -1, mbstr, (int)count, NULL, NULL);
  643. ATLASSERT(mbstr == NULL || result <= (int)count);
  644. if (result > 0)
  645. mbstr[result - 1] = 0;
  646. return result;
  647. }
  648. static int __cdecl _mbstowcsz(wchar_t* wcstr, const char* mbstr, size_t count)
  649. {
  650. if (count == 0 && wcstr != NULL)
  651. return 0;
  652. int result = ::MultiByteToWideChar(CP_ACP, 0, mbstr, -1, wcstr, (int)count);
  653. ATLASSERT(wcstr == NULL || result <= (int)count);
  654. if (result > 0)
  655. wcstr[result - 1] = 0;
  656. return result;
  657. }
  658. // Helpers to avoid CRT startup code
  659. static TCHAR* _cstrchr(const TCHAR* p, TCHAR ch)
  660. {
  661. //strchr for '\0' should succeed
  662. while (*p != 0)
  663. {
  664. if (*p == ch)
  665. break;
  666. p = ::CharNext(p);
  667. }
  668. return (TCHAR*)((*p == ch) ? p : NULL);
  669. }
  670. static TCHAR* _cstrchr_db(const TCHAR* p, TCHAR ch1, TCHAR ch2)
  671. {
  672. const TCHAR* lpsz = NULL;
  673. while (*p != 0)
  674. {
  675. if (*p == ch1 && *(p + 1) == ch2)
  676. {
  677. lpsz = p;
  678. break;
  679. }
  680. p = ::CharNext(p);
  681. }
  682. return (TCHAR*)lpsz;
  683. }
  684. static TCHAR* _cstrrchr(const TCHAR* p, TCHAR ch)
  685. {
  686. const TCHAR* lpsz = NULL;
  687. while (*p != 0)
  688. {
  689. if (*p == ch)
  690. lpsz = p;
  691. p = ::CharNext(p);
  692. }
  693. return (TCHAR*)lpsz;
  694. }
  695. static TCHAR* _cstrrev(TCHAR* pStr)
  696. {
  697. // Optimize NULL, zero-length, and single-char case.
  698. if ((pStr == NULL) || (pStr[0] == '\0') || (pStr[1] == '\0'))
  699. return pStr;
  700. TCHAR* p = pStr;
  701. while (p[1] != 0)
  702. {
  703. TCHAR* pNext = ::CharNext(p);
  704. if(pNext > p + 1)
  705. {
  706. char p1 = *(char*)p;
  707. *(char*)p = *(char*)(p + 1);
  708. *(char*)(p + 1) = p1;
  709. }
  710. p = pNext;
  711. }
  712. TCHAR* q = pStr;
  713. while (q < p)
  714. {
  715. TCHAR t = *q;
  716. *q = *p;
  717. *p = t;
  718. q++;
  719. p--;
  720. }
  721. return (TCHAR*)pStr;
  722. }
  723. static TCHAR* _cstrstr(const TCHAR* pStr, const TCHAR* pCharSet)
  724. {
  725. int nLen = lstrlen(pCharSet);
  726. if (nLen == 0)
  727. return (TCHAR*)pStr;
  728. const TCHAR* pRet = NULL;
  729. const TCHAR* pCur = pStr;
  730. while((pStr = _cstrchr(pCur, *pCharSet)) != NULL)
  731. {
  732. if(memcmp(pCur, pCharSet, nLen * sizeof(TCHAR)) == 0)
  733. {
  734. pRet = pCur;
  735. break;
  736. }
  737. pCur = ::CharNext(pCur);
  738. }
  739. return (TCHAR*) pRet;
  740. }
  741. static int _cstrspn(const TCHAR* pStr, const TCHAR* pCharSet)
  742. {
  743. int nRet = 0;
  744. TCHAR* p = (TCHAR*)pStr;
  745. while (*p != 0)
  746. {
  747. TCHAR* pNext = ::CharNext(p);
  748. if(pNext > p + 1)
  749. {
  750. if(_cstrchr_db(pCharSet, *p, *(p + 1)) == NULL)
  751. break;
  752. nRet += 2;
  753. }
  754. else
  755. {
  756. if(_cstrchr(pCharSet, *p) == NULL)
  757. break;
  758. nRet++;
  759. }
  760. p = pNext;
  761. }
  762. return nRet;
  763. }
  764. static int _cstrcspn(const TCHAR* pStr, const TCHAR* pCharSet)
  765. {
  766. int nRet = 0;
  767. TCHAR* p = (TCHAR*)pStr;
  768. while (*p != 0)
  769. {
  770. TCHAR* pNext = ::CharNext(p);
  771. if(pNext > p + 1)
  772. {
  773. if(_cstrchr_db(pCharSet, *p, *(p + 1)) != NULL)
  774. break;
  775. nRet += 2;
  776. }
  777. else
  778. {
  779. if(_cstrchr(pCharSet, *p) != NULL)
  780. break;
  781. nRet++;
  782. }
  783. p = pNext;
  784. }
  785. return nRet;
  786. }
  787. static TCHAR* _cstrpbrk(const TCHAR* p, const TCHAR* lpszCharSet)
  788. {
  789. while (*p != 0)
  790. {
  791. if (_cstrchr(lpszCharSet, *p) != NULL)
  792. {
  793. return (TCHAR*)p;
  794. break;
  795. }
  796. p = ::CharNext(p);
  797. }
  798. return NULL;
  799. }
  800. static int _cstrisdigit(TCHAR ch)
  801. {
  802. WORD type;
  803. GetStringTypeEx(GetThreadLocale(), CT_CTYPE1, &ch, 1, &type);
  804. return (type & C1_DIGIT) == C1_DIGIT;
  805. }
  806. static int _cstrisspace(TCHAR ch)
  807. {
  808. WORD type;
  809. GetStringTypeEx(GetThreadLocale(), CT_CTYPE1, &ch, 1, &type);
  810. return (type & C1_SPACE) == C1_SPACE;
  811. }
  812. static int _cstrcmp(const TCHAR* pstrOne, const TCHAR* pstrOther)
  813. {
  814. return lstrcmp(pstrOne, pstrOther);
  815. }
  816. static int _cstrcmpi(const TCHAR* pstrOne, const TCHAR* pstrOther)
  817. {
  818. return lstrcmpi(pstrOne, pstrOther);
  819. }
  820. static int _cstrcoll(const TCHAR* pstrOne, const TCHAR* pstrOther)
  821. {
  822. int nRet = CompareString(GetThreadLocale(), 0, pstrOne, -1, pstrOther, -1);
  823. ATLASSERT(nRet != 0);
  824. return nRet - 2; // Convert to strcmp convention. This really is documented.
  825. }
  826. static int _cstrcolli(const TCHAR* pstrOne, const TCHAR* pstrOther)
  827. {
  828. int nRet = CompareString(GetThreadLocale(), NORM_IGNORECASE, pstrOne, -1, pstrOther, -1);
  829. ATLASSERT(nRet != 0);
  830. return nRet - 2; // Convert to strcmp convention. This really is documented.
  831. }
  832. };
  833. // Compare helpers
  834. bool __stdcall operator==(const CString& s1, const CString& s2);
  835. bool __stdcall operator==(const CString& s1, LPCTSTR s2);
  836. bool __stdcall operator==(LPCTSTR s1, const CString& s2);
  837. bool __stdcall operator!=(const CString& s1, const CString& s2);
  838. bool __stdcall operator!=(const CString& s1, LPCTSTR s2);
  839. bool __stdcall operator!=(LPCTSTR s1, const CString& s2);
  840. bool __stdcall operator<(const CString& s1, const CString& s2);
  841. bool __stdcall operator<(const CString& s1, LPCTSTR s2);
  842. bool __stdcall operator<(LPCTSTR s1, const CString& s2);
  843. bool __stdcall operator>(const CString& s1, const CString& s2);
  844. bool __stdcall operator>(const CString& s1, LPCTSTR s2);
  845. bool __stdcall operator>(LPCTSTR s1, const CString& s2);
  846. bool __stdcall operator<=(const CString& s1, const CString& s2);
  847. bool __stdcall operator<=(const CString& s1, LPCTSTR s2);
  848. bool __stdcall operator<=(LPCTSTR s1, const CString& s2);
  849. bool __stdcall operator>=(const CString& s1, const CString& s2);
  850. bool __stdcall operator>=(const CString& s1, LPCTSTR s2);
  851. bool __stdcall operator>=(LPCTSTR s1, const CString& s2);
  852. /////////////////////////////////////////////////////////////////////////////
  853. // CString Implementation
  854. inline CStringData* CString::GetData() const
  855. { ATLASSERT(m_pchData != NULL); return ((CStringData*)m_pchData) - 1; }
  856. inline void CString::Init()
  857. { m_pchData = _GetEmptyString().m_pchData; }
  858. inline CString::CString(const unsigned char* lpsz)
  859. { Init(); *this = (LPCSTR)lpsz; }
  860. inline const CString& CString::operator=(const unsigned char* lpsz)
  861. { *this = (LPCSTR)lpsz; return *this; }
  862. #ifdef _UNICODE
  863. inline const CString& CString::operator+=(char ch)
  864. { *this += (TCHAR)ch; return *this; }
  865. inline const CString& CString::operator=(char ch)
  866. { *this = (TCHAR)ch; return *this; }
  867. inline CString __stdcall operator+(const CString& string, char ch)
  868. { return string + (TCHAR)ch; }
  869. inline CString __stdcall operator+(char ch, const CString& string)
  870. { return (TCHAR)ch + string; }
  871. #endif
  872. inline int CString::GetLength() const
  873. { return GetData()->nDataLength; }
  874. inline int CString::GetAllocLength() const
  875. { return GetData()->nAllocLength; }
  876. inline BOOL CString::IsEmpty() const
  877. { return GetData()->nDataLength == 0; }
  878. inline CString::operator LPCTSTR() const
  879. { return m_pchData; }
  880. inline int PASCAL CString::SafeStrlen(LPCTSTR lpsz)
  881. { return (lpsz == NULL) ? 0 : lstrlen(lpsz); }
  882. // CString support (windows specific)
  883. inline int CString::Compare(LPCTSTR lpsz) const
  884. { return _cstrcmp(m_pchData, lpsz); } // MBCS/Unicode aware
  885. inline int CString::CompareNoCase(LPCTSTR lpsz) const
  886. { return _cstrcmpi(m_pchData, lpsz); } // MBCS/Unicode aware
  887. // CString::Collate is often slower than Compare but is MBSC/Unicode
  888. // aware as well as locale-sensitive with respect to sort order.
  889. inline int CString::Collate(LPCTSTR lpsz) const
  890. { return _cstrcoll(m_pchData, lpsz); } // locale sensitive
  891. inline TCHAR CString::GetAt(int nIndex) const
  892. {
  893. ATLASSERT(nIndex >= 0);
  894. ATLASSERT(nIndex < GetData()->nDataLength);
  895. return m_pchData[nIndex];
  896. }
  897. inline TCHAR CString::operator[](int nIndex) const
  898. {
  899. // same as GetAt
  900. ATLASSERT(nIndex >= 0);
  901. ATLASSERT(nIndex < GetData()->nDataLength);
  902. return m_pchData[nIndex];
  903. }
  904. inline bool __stdcall operator==(const CString& s1, const CString& s2)
  905. { return s1.Compare(s2) == 0; }
  906. inline bool __stdcall operator==(const CString& s1, LPCTSTR s2)
  907. { return s1.Compare(s2) == 0; }
  908. inline bool __stdcall operator==(LPCTSTR s1, const CString& s2)
  909. { return s2.Compare(s1) == 0; }
  910. inline bool __stdcall operator!=(const CString& s1, const CString& s2)
  911. { return s1.Compare(s2) != 0; }
  912. inline bool __stdcall operator!=(const CString& s1, LPCTSTR s2)
  913. { return s1.Compare(s2) != 0; }
  914. inline bool __stdcall operator!=(LPCTSTR s1, const CString& s2)
  915. { return s2.Compare(s1) != 0; }
  916. inline bool __stdcall operator<(const CString& s1, const CString& s2)
  917. { return s1.Compare(s2) < 0; }
  918. inline bool __stdcall operator<(const CString& s1, LPCTSTR s2)
  919. { return s1.Compare(s2) < 0; }
  920. inline bool __stdcall operator<(LPCTSTR s1, const CString& s2)
  921. { return s2.Compare(s1) > 0; }
  922. inline bool __stdcall operator>(const CString& s1, const CString& s2)
  923. { return s1.Compare(s2) > 0; }
  924. inline bool __stdcall operator>(const CString& s1, LPCTSTR s2)
  925. { return s1.Compare(s2) > 0; }
  926. inline bool __stdcall operator>(LPCTSTR s1, const CString& s2)
  927. { return s2.Compare(s1) < 0; }
  928. inline bool __stdcall operator<=(const CString& s1, const CString& s2)
  929. { return s1.Compare(s2) <= 0; }
  930. inline bool __stdcall operator<=(const CString& s1, LPCTSTR s2)
  931. { return s1.Compare(s2) <= 0; }
  932. inline bool __stdcall operator<=(LPCTSTR s1, const CString& s2)
  933. { return s2.Compare(s1) >= 0; }
  934. inline bool __stdcall operator>=(const CString& s1, const CString& s2)
  935. { return s1.Compare(s2) >= 0; }
  936. inline bool __stdcall operator>=(const CString& s1, LPCTSTR s2)
  937. { return s1.Compare(s2) >= 0; }
  938. inline bool __stdcall operator>=(LPCTSTR s1, const CString& s2)
  939. { return s2.Compare(s1) <= 0; }
  940. inline CString::CString()
  941. {
  942. Init();
  943. }
  944. inline CString::CString(const CString& stringSrc)
  945. {
  946. ATLASSERT(stringSrc.GetData()->nRefs != 0);
  947. if (stringSrc.GetData()->nRefs >= 0)
  948. {
  949. ATLASSERT(stringSrc.GetData() != _atltmpDataNil);
  950. m_pchData = stringSrc.m_pchData;
  951. InterlockedIncrement(&GetData()->nRefs);
  952. }
  953. else
  954. {
  955. Init();
  956. *this = stringSrc.m_pchData;
  957. }
  958. }
  959. inline BOOL CString::AllocBuffer(int nLen)
  960. // always allocate one extra character for '\0' termination
  961. // assumes [optimistically] that data length will equal allocation length
  962. {
  963. ATLASSERT(nLen >= 0);
  964. ATLASSERT(nLen <= INT_MAX - 1); // max size (enough room for 1 extra)
  965. if (nLen == 0)
  966. {
  967. Init();
  968. }
  969. else
  970. {
  971. CStringData* pData = NULL;
  972. ATLTRY(pData = (CStringData*)new BYTE[sizeof(CStringData) + (nLen + 1) * sizeof(TCHAR)]);
  973. if(pData == NULL)
  974. return FALSE;
  975. pData->nRefs = 1;
  976. pData->data()[nLen] = '\0';
  977. pData->nDataLength = nLen;
  978. pData->nAllocLength = nLen;
  979. m_pchData = pData->data();
  980. }
  981. return TRUE;
  982. }
  983. inline void CString::Release()
  984. {
  985. if (GetData() != _atltmpDataNil)
  986. {
  987. ATLASSERT(GetData()->nRefs != 0);
  988. if (InterlockedDecrement(&GetData()->nRefs) <= 0)
  989. delete[] (BYTE*)GetData();
  990. Init();
  991. }
  992. }
  993. inline void PASCAL CString::Release(CStringData* pData)
  994. {
  995. if (pData != _atltmpDataNil)
  996. {
  997. ATLASSERT(pData->nRefs != 0);
  998. if (InterlockedDecrement(&pData->nRefs) <= 0)
  999. delete[] (BYTE*)pData;
  1000. }
  1001. }
  1002. inline void CString::Empty()
  1003. {
  1004. if (GetData()->nDataLength == 0)
  1005. return;
  1006. if (GetData()->nRefs >= 0)
  1007. Release();
  1008. else
  1009. *this = _T("");
  1010. ATLASSERT(GetData()->nDataLength == 0);
  1011. ATLASSERT(GetData()->nRefs < 0 || GetData()->nAllocLength == 0);
  1012. }
  1013. inline void CString::CopyBeforeWrite()
  1014. {
  1015. if (GetData()->nRefs > 1)
  1016. {
  1017. CStringData* pData = GetData();
  1018. Release();
  1019. if(AllocBuffer(pData->nDataLength))
  1020. memcpy(m_pchData, pData->data(), (pData->nDataLength + 1) * sizeof(TCHAR));
  1021. }
  1022. ATLASSERT(GetData()->nRefs <= 1);
  1023. }
  1024. inline BOOL CString::AllocBeforeWrite(int nLen)
  1025. {
  1026. BOOL bRet = TRUE;
  1027. if (GetData()->nRefs > 1 || nLen > GetData()->nAllocLength)
  1028. {
  1029. Release();
  1030. bRet = AllocBuffer(nLen);
  1031. }
  1032. ATLASSERT(GetData()->nRefs <= 1);
  1033. return bRet;
  1034. }
  1035. inline CString::~CString()
  1036. // free any attached data
  1037. {
  1038. if (GetData() != _atltmpDataNil)
  1039. {
  1040. if (InterlockedDecrement(&GetData()->nRefs) <= 0)
  1041. delete[] (BYTE*)GetData();
  1042. }
  1043. }
  1044. inline void CString::AllocCopy(CString& dest, int nCopyLen, int nCopyIndex,
  1045. int nExtraLen) const
  1046. {
  1047. // will clone the data attached to this string
  1048. // allocating 'nExtraLen' characters
  1049. // Places results in uninitialized string 'dest'
  1050. // Will copy the part or all of original data to start of new string
  1051. int nNewLen = nCopyLen + nExtraLen;
  1052. if (nNewLen == 0)
  1053. {
  1054. dest.Init();
  1055. }
  1056. else
  1057. {
  1058. if(dest.AllocBuffer(nNewLen))
  1059. memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen * sizeof(TCHAR));
  1060. }
  1061. }
  1062. inline CString::CString(LPCTSTR lpsz)
  1063. {
  1064. Init();
  1065. if (lpsz != NULL && HIWORD(lpsz) == NULL)
  1066. {
  1067. UINT nID = LOWORD((DWORD_PTR)lpsz);
  1068. if (!LoadString(nID))
  1069. ATLTRACE2(atlTraceUI, 0, _T("Warning: implicit LoadString(%u) in CString failed\n"), nID);
  1070. }
  1071. else
  1072. {
  1073. int nLen = SafeStrlen(lpsz);
  1074. if (nLen != 0)
  1075. {
  1076. if(AllocBuffer(nLen))
  1077. memcpy(m_pchData, lpsz, nLen * sizeof(TCHAR));
  1078. }
  1079. }
  1080. }
  1081. #ifdef _UNICODE
  1082. inline CString::CString(LPCSTR lpsz)
  1083. {
  1084. Init();
  1085. int nSrcLen = lpsz != NULL ? lstrlenA(lpsz) : 0;
  1086. if (nSrcLen != 0)
  1087. {
  1088. if(AllocBuffer(nSrcLen))
  1089. {
  1090. _mbstowcsz(m_pchData, lpsz, nSrcLen + 1);
  1091. ReleaseBuffer();
  1092. }
  1093. }
  1094. }
  1095. #else //_UNICODE
  1096. inline CString::CString(LPCWSTR lpsz)
  1097. {
  1098. Init();
  1099. int nSrcLen = lpsz != NULL ? wcslen(lpsz) : 0;
  1100. if (nSrcLen != 0)
  1101. {
  1102. if(AllocBuffer(nSrcLen * 2))
  1103. {
  1104. _wcstombsz(m_pchData, lpsz, (nSrcLen * 2) + 1);
  1105. ReleaseBuffer();
  1106. }
  1107. }
  1108. }
  1109. #endif //!_UNICODE
  1110. // Assignment operators
  1111. // All assign a new value to the string
  1112. // (a) first see if the buffer is big enough
  1113. // (b) if enough room, copy on top of old buffer, set size and type
  1114. // (c) otherwise free old string data, and create a new one
  1115. //
  1116. // All routines return the new string (but as a 'const CString&' so that
  1117. // assigning it again will cause a copy, eg: s1 = s2 = "hi there".
  1118. //
  1119. inline void CString::AssignCopy(int nSrcLen, LPCTSTR lpszSrcData)
  1120. {
  1121. if(AllocBeforeWrite(nSrcLen))
  1122. {
  1123. memcpy(m_pchData, lpszSrcData, nSrcLen * sizeof(TCHAR));
  1124. GetData()->nDataLength = nSrcLen;
  1125. m_pchData[nSrcLen] = '\0';
  1126. }
  1127. }
  1128. inline const CString& CString::operator=(const CString& stringSrc)
  1129. {
  1130. if (m_pchData != stringSrc.m_pchData)
  1131. {
  1132. if ((GetData()->nRefs < 0 && GetData() != _atltmpDataNil) || stringSrc.GetData()->nRefs < 0)
  1133. {
  1134. // actual copy necessary since one of the strings is locked
  1135. AssignCopy(stringSrc.GetData()->nDataLength, stringSrc.m_pchData);
  1136. }
  1137. else
  1138. {
  1139. // can just copy references around
  1140. Release();
  1141. ATLASSERT(stringSrc.GetData() != _atltmpDataNil);
  1142. m_pchData = stringSrc.m_pchData;
  1143. InterlockedIncrement(&GetData()->nRefs);
  1144. }
  1145. }
  1146. return *this;
  1147. }
  1148. inline const CString& CString::operator=(LPCTSTR lpsz)
  1149. {
  1150. ATLASSERT(lpsz == NULL || _IsValidString(lpsz, FALSE));
  1151. AssignCopy(SafeStrlen(lpsz), lpsz);
  1152. return *this;
  1153. }
  1154. #ifdef _UNICODE
  1155. inline const CString& CString::operator=(LPCSTR lpsz)
  1156. {
  1157. int nSrcLen = lpsz != NULL ? lstrlenA(lpsz) : 0;
  1158. if(AllocBeforeWrite(nSrcLen))
  1159. {
  1160. _mbstowcsz(m_pchData, lpsz, nSrcLen + 1);
  1161. ReleaseBuffer();
  1162. }
  1163. return *this;
  1164. }
  1165. #else //!_UNICODE
  1166. inline const CString& CString::operator=(LPCWSTR lpsz)
  1167. {
  1168. int nSrcLen = lpsz != NULL ? wcslen(lpsz) : 0;
  1169. if(AllocBeforeWrite(nSrcLen * 2))
  1170. {
  1171. _wcstombsz(m_pchData, lpsz, (nSrcLen * 2) + 1);
  1172. ReleaseBuffer();
  1173. }
  1174. return *this;
  1175. }
  1176. #endif //!_UNICODE
  1177. // Concatenation
  1178. // NOTE: "operator+" is done as friend functions for simplicity
  1179. // There are three variants:
  1180. // CString + CString
  1181. // and for ? = TCHAR, LPCTSTR
  1182. // CString + ?
  1183. // ? + CString
  1184. inline BOOL CString::ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data,
  1185. int nSrc2Len, LPCTSTR lpszSrc2Data)
  1186. {
  1187. // -- master concatenation routine
  1188. // Concatenate two sources
  1189. // -- assume that 'this' is a new CString object
  1190. BOOL bRet = TRUE;
  1191. int nNewLen = nSrc1Len + nSrc2Len;
  1192. if (nNewLen != 0)
  1193. {
  1194. bRet = AllocBuffer(nNewLen);
  1195. if (bRet)
  1196. {
  1197. memcpy(m_pchData, lpszSrc1Data, nSrc1Len * sizeof(TCHAR));
  1198. memcpy(m_pchData + nSrc1Len, lpszSrc2Data, nSrc2Len * sizeof(TCHAR));
  1199. }
  1200. }
  1201. return bRet;
  1202. }
  1203. inline CString __stdcall operator+(const CString& string1, const CString& string2)
  1204. {
  1205. CString s;
  1206. s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData, string2.GetData()->nDataLength, string2.m_pchData);
  1207. return s;
  1208. }
  1209. inline CString __stdcall operator+(const CString& string, LPCTSTR lpsz)
  1210. {
  1211. ATLASSERT(lpsz == NULL || CString::_IsValidString(lpsz, FALSE));
  1212. CString s;
  1213. s.ConcatCopy(string.GetData()->nDataLength, string.m_pchData, CString::SafeStrlen(lpsz), lpsz);
  1214. return s;
  1215. }
  1216. inline CString __stdcall operator+(LPCTSTR lpsz, const CString& string)
  1217. {
  1218. ATLASSERT(lpsz == NULL || CString::_IsValidString(lpsz, FALSE));
  1219. CString s;
  1220. s.ConcatCopy(CString::SafeStrlen(lpsz), lpsz, string.GetData()->nDataLength, string.m_pchData);
  1221. return s;
  1222. }
  1223. inline void CString::ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData)
  1224. {
  1225. // -- the main routine for += operators
  1226. // concatenating an empty string is a no-op!
  1227. if (nSrcLen == 0)
  1228. return;
  1229. // if the buffer is too small, or we have a width mis-match, just
  1230. // allocate a new buffer (slow but sure)
  1231. if (GetData()->nRefs > 1 || GetData()->nDataLength + nSrcLen > GetData()->nAllocLength)
  1232. {
  1233. // we have to grow the buffer, use the ConcatCopy routine
  1234. CStringData* pOldData = GetData();
  1235. if (ConcatCopy(GetData()->nDataLength, m_pchData, nSrcLen, lpszSrcData))
  1236. {
  1237. ATLASSERT(pOldData != NULL);
  1238. CString::Release(pOldData);
  1239. }
  1240. }
  1241. else
  1242. {
  1243. // fast concatenation when buffer big enough
  1244. memcpy(m_pchData + GetData()->nDataLength, lpszSrcData, nSrcLen * sizeof(TCHAR));
  1245. GetData()->nDataLength += nSrcLen;
  1246. ATLASSERT(GetData()->nDataLength <= GetData()->nAllocLength);
  1247. m_pchData[GetData()->nDataLength] = '\0';
  1248. }
  1249. }
  1250. inline const CString& CString::operator+=(LPCTSTR lpsz)
  1251. {
  1252. ATLASSERT(lpsz == NULL || _IsValidString(lpsz, FALSE));
  1253. ConcatInPlace(SafeStrlen(lpsz), lpsz);
  1254. return *this;
  1255. }
  1256. inline const CString& CString::operator+=(TCHAR ch)
  1257. {
  1258. ConcatInPlace(1, &ch);
  1259. return *this;
  1260. }
  1261. inline const CString& CString::operator+=(const CString& string)
  1262. {
  1263. ConcatInPlace(string.GetData()->nDataLength, string.m_pchData);
  1264. return *this;
  1265. }
  1266. inline LPTSTR CString::GetBuffer(int nMinBufLength)
  1267. {
  1268. ATLASSERT(nMinBufLength >= 0);
  1269. if (GetData()->nRefs > 1 || nMinBufLength > GetData()->nAllocLength)
  1270. {
  1271. // we have to grow the buffer
  1272. CStringData* pOldData = GetData();
  1273. int nOldLen = GetData()->nDataLength; // AllocBuffer will tromp it
  1274. if (nMinBufLength < nOldLen)
  1275. nMinBufLength = nOldLen;
  1276. if(AllocBuffer(nMinBufLength))
  1277. {
  1278. memcpy(m_pchData, pOldData->data(), (nOldLen + 1) * sizeof(TCHAR));
  1279. GetData()->nDataLength = nOldLen;
  1280. CString::Release(pOldData);
  1281. }
  1282. }
  1283. ATLASSERT(GetData()->nRefs <= 1);
  1284. // return a pointer to the character storage for this string
  1285. ATLASSERT(m_pchData != NULL);
  1286. return m_pchData;
  1287. }
  1288. inline void CString::ReleaseBuffer(int nNewLength)
  1289. {
  1290. CopyBeforeWrite(); // just in case GetBuffer was not called
  1291. if (nNewLength == -1)
  1292. nNewLength = lstrlen(m_pchData); // zero terminated
  1293. ATLASSERT(nNewLength <= GetData()->nAllocLength);
  1294. GetData()->nDataLength = nNewLength;
  1295. m_pchData[nNewLength] = '\0';
  1296. }
  1297. inline LPTSTR CString::GetBufferSetLength(int nNewLength)
  1298. {
  1299. ATLASSERT(nNewLength >= 0);
  1300. GetBuffer(nNewLength);
  1301. GetData()->nDataLength = nNewLength;
  1302. m_pchData[nNewLength] = '\0';
  1303. return m_pchData;
  1304. }
  1305. inline void CString::FreeExtra()
  1306. {
  1307. ATLASSERT(GetData()->nDataLength <= GetData()->nAllocLength);
  1308. if (GetData()->nDataLength != GetData()->nAllocLength)
  1309. {
  1310. CStringData* pOldData = GetData();
  1311. if(AllocBuffer(GetData()->nDataLength))
  1312. {
  1313. memcpy(m_pchData, pOldData->data(), pOldData->nDataLength * sizeof(TCHAR));
  1314. ATLASSERT(m_pchData[GetData()->nDataLength] == '\0');
  1315. CString::Release(pOldData);
  1316. }
  1317. }
  1318. ATLASSERT(GetData() != NULL);
  1319. }
  1320. inline LPTSTR CString::LockBuffer()
  1321. {
  1322. LPTSTR lpsz = GetBuffer(0);
  1323. GetData()->nRefs = -1;
  1324. return lpsz;
  1325. }
  1326. inline void CString::UnlockBuffer()
  1327. {
  1328. ATLASSERT(GetData()->nRefs == -1);
  1329. if (GetData() != _atltmpDataNil)
  1330. GetData()->nRefs = 1;
  1331. }
  1332. inline int CString::Find(TCHAR ch) const
  1333. {
  1334. // find first single character
  1335. LPTSTR lpsz = _cstrchr(m_pchData, (_TUCHAR)ch);
  1336. // return -1 if not found and index otherwise
  1337. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  1338. }
  1339. inline int CString::FindOneOf(LPCTSTR lpszCharSet) const
  1340. {
  1341. ATLASSERT(_IsValidString(lpszCharSet, FALSE));
  1342. LPTSTR lpsz = _cstrpbrk(m_pchData, lpszCharSet);
  1343. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  1344. }
  1345. inline void CString::MakeUpper()
  1346. {
  1347. CopyBeforeWrite();
  1348. CharUpper(m_pchData);
  1349. }
  1350. inline void CString::MakeLower()
  1351. {
  1352. CopyBeforeWrite();
  1353. CharLower(m_pchData);
  1354. }
  1355. inline void CString::MakeReverse()
  1356. {
  1357. CopyBeforeWrite();
  1358. _cstrrev(m_pchData);
  1359. }
  1360. inline void CString::SetAt(int nIndex, TCHAR ch)
  1361. {
  1362. ATLASSERT(nIndex >= 0);
  1363. ATLASSERT(nIndex < GetData()->nDataLength);
  1364. CopyBeforeWrite();
  1365. m_pchData[nIndex] = ch;
  1366. }
  1367. #ifndef _UNICODE
  1368. inline void CString::AnsiToOem()
  1369. {
  1370. CopyBeforeWrite();
  1371. ::AnsiToOem(m_pchData, m_pchData);
  1372. }
  1373. inline void CString::OemToAnsi()
  1374. {
  1375. CopyBeforeWrite();
  1376. ::OemToAnsi(m_pchData, m_pchData);
  1377. }
  1378. #endif
  1379. inline CString::CString(TCHAR ch, int nLength)
  1380. {
  1381. ATLASSERT(!_istlead(ch)); // can't create a lead byte string
  1382. Init();
  1383. if (nLength >= 1)
  1384. {
  1385. if(AllocBuffer(nLength))
  1386. {
  1387. #ifdef _UNICODE
  1388. for (int i = 0; i < nLength; i++)
  1389. m_pchData[i] = ch;
  1390. #else
  1391. memset(m_pchData, ch, nLength);
  1392. #endif
  1393. }
  1394. }
  1395. }
  1396. inline CString::CString(LPCTSTR lpch, int nLength)
  1397. {
  1398. Init();
  1399. if (nLength != 0)
  1400. {
  1401. if(AllocBuffer(nLength))
  1402. memcpy(m_pchData, lpch, nLength * sizeof(TCHAR));
  1403. }
  1404. }
  1405. inline const CString& CString::operator=(TCHAR ch)
  1406. {
  1407. ATLASSERT(!_istlead(ch)); // can't set single lead byte
  1408. AssignCopy(1, &ch);
  1409. return *this;
  1410. }
  1411. inline CString __stdcall operator+(const CString& string1, TCHAR ch)
  1412. {
  1413. CString s;
  1414. s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData, 1, &ch);
  1415. return s;
  1416. }
  1417. inline CString __stdcall operator+(TCHAR ch, const CString& string)
  1418. {
  1419. CString s;
  1420. s.ConcatCopy(1, &ch, string.GetData()->nDataLength, string.m_pchData);
  1421. return s;
  1422. }
  1423. inline CString CString::Mid(int nFirst) const
  1424. {
  1425. return Mid(nFirst, GetData()->nDataLength - nFirst);
  1426. }
  1427. inline CString CString::Mid(int nFirst, int nCount) const
  1428. {
  1429. // out-of-bounds requests return sensible things
  1430. if (nFirst < 0)
  1431. nFirst = 0;
  1432. if (nCount < 0)
  1433. nCount = 0;
  1434. if (nFirst + nCount > GetData()->nDataLength)
  1435. nCount = GetData()->nDataLength - nFirst;
  1436. if (nFirst > GetData()->nDataLength)
  1437. nCount = 0;
  1438. CString dest;
  1439. AllocCopy(dest, nCount, nFirst, 0);
  1440. return dest;
  1441. }
  1442. inline CString CString::Right(int nCount) const
  1443. {
  1444. if (nCount < 0)
  1445. nCount = 0;
  1446. else if (nCount > GetData()->nDataLength)
  1447. nCount = GetData()->nDataLength;
  1448. CString dest;
  1449. AllocCopy(dest, nCount, GetData()->nDataLength-nCount, 0);
  1450. return dest;
  1451. }
  1452. inline CString CString::Left(int nCount) const
  1453. {
  1454. if (nCount < 0)
  1455. nCount = 0;
  1456. else if (nCount > GetData()->nDataLength)
  1457. nCount = GetData()->nDataLength;
  1458. CString dest;
  1459. AllocCopy(dest, nCount, 0, 0);
  1460. return dest;
  1461. }
  1462. // strspn equivalent
  1463. inline CString CString::SpanIncluding(LPCTSTR lpszCharSet) const
  1464. {
  1465. ATLASSERT(_IsValidString(lpszCharSet, FALSE));
  1466. return Left(_cstrspn(m_pchData, lpszCharSet));
  1467. }
  1468. // strcspn equivalent
  1469. inline CString CString::SpanExcluding(LPCTSTR lpszCharSet) const
  1470. {
  1471. ATLASSERT(_IsValidString(lpszCharSet, FALSE));
  1472. return Left(_cstrcspn(m_pchData, lpszCharSet));
  1473. }
  1474. inline int CString::ReverseFind(TCHAR ch) const
  1475. {
  1476. // find last single character
  1477. LPTSTR lpsz = _cstrrchr(m_pchData, (_TUCHAR)ch);
  1478. // return -1 if not found, distance from beginning otherwise
  1479. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  1480. }
  1481. // find a sub-string (like strstr)
  1482. inline int CString::Find(LPCTSTR lpszSub) const
  1483. {
  1484. ATLASSERT(_IsValidString(lpszSub, FALSE));
  1485. // find first matching substring
  1486. LPTSTR lpsz = _cstrstr(m_pchData, lpszSub);
  1487. // return -1 for not found, distance from beginning otherwise
  1488. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  1489. }
  1490. inline void CString::FormatV(LPCTSTR lpszFormat, va_list argList)
  1491. {
  1492. ATLASSERT(_IsValidString(lpszFormat, FALSE));
  1493. enum _FormatModifiers
  1494. {
  1495. FORCE_ANSI = 0x10000,
  1496. FORCE_UNICODE = 0x20000,
  1497. FORCE_INT64 = 0x40000
  1498. };
  1499. va_list argListSave = argList;
  1500. // make a guess at the maximum length of the resulting string
  1501. int nMaxLen = 0;
  1502. for (LPCTSTR lpsz = lpszFormat; *lpsz != '\0'; lpsz = ::CharNext(lpsz))
  1503. {
  1504. // handle '%' character, but watch out for '%%'
  1505. if (*lpsz != '%' || *(lpsz = ::CharNext(lpsz)) == '%')
  1506. {
  1507. nMaxLen += (int)lstrlen(lpsz);
  1508. continue;
  1509. }
  1510. int nItemLen = 0;
  1511. // handle '%' character with format
  1512. int nWidth = 0;
  1513. for (; *lpsz != '\0'; lpsz = ::CharNext(lpsz))
  1514. {
  1515. // check for valid flags
  1516. if (*lpsz == '#')
  1517. nMaxLen += 2; // for '0x'
  1518. else if (*lpsz == '*')
  1519. nWidth = va_arg(argList, int);
  1520. else if (*lpsz == '-' || *lpsz == '+' || *lpsz == '0' || *lpsz == ' ')
  1521. ;
  1522. else // hit non-flag character
  1523. break;
  1524. }
  1525. // get width and skip it
  1526. if (nWidth == 0)
  1527. {
  1528. // width indicated by
  1529. nWidth = _ttoi(lpsz);
  1530. for (; *lpsz != '\0' && _cstrisdigit(*lpsz); lpsz = ::CharNext(lpsz))
  1531. ;
  1532. }
  1533. ATLASSERT(nWidth >= 0);
  1534. int nPrecision = 0;
  1535. if (*lpsz == '.')
  1536. {
  1537. // skip past '.' separator (width.precision)
  1538. lpsz = ::CharNext(lpsz);
  1539. // get precision and skip it
  1540. if (*lpsz == '*')
  1541. {
  1542. nPrecision = va_arg(argList, int);
  1543. lpsz = ::CharNext(lpsz);
  1544. }
  1545. else
  1546. {
  1547. nPrecision = _ttoi(lpsz);
  1548. for (; *lpsz != '\0' && _cstrisdigit(*lpsz); lpsz = ::CharNext(lpsz))
  1549. ;
  1550. }
  1551. ATLASSERT(nPrecision >= 0);
  1552. }
  1553. // should be on type modifier or specifier
  1554. int nModifier = 0;
  1555. if(lpsz[0] == _T('I') && lpsz[1] == _T('6') && lpsz[2] == _T('4'))
  1556. {
  1557. lpsz += 3;
  1558. nModifier = FORCE_INT64;
  1559. }
  1560. else
  1561. {
  1562. switch (*lpsz)
  1563. {
  1564. // modifiers that affect size
  1565. case 'h':
  1566. nModifier = FORCE_ANSI;
  1567. lpsz = ::CharNext(lpsz);
  1568. break;
  1569. case 'l':
  1570. nModifier = FORCE_UNICODE;
  1571. lpsz = ::CharNext(lpsz);
  1572. break;
  1573. // modifiers that do not affect size
  1574. case 'F':
  1575. case 'N':
  1576. case 'L':
  1577. lpsz = ::CharNext(lpsz);
  1578. break;
  1579. }
  1580. }
  1581. // now should be on specifier
  1582. switch (*lpsz | nModifier)
  1583. {
  1584. // single characters
  1585. case 'c':
  1586. case 'C':
  1587. nItemLen = 2;
  1588. va_arg(argList, TCHAR);
  1589. break;
  1590. case 'c' | FORCE_ANSI:
  1591. case 'C' | FORCE_ANSI:
  1592. nItemLen = 2;
  1593. va_arg(argList, char);
  1594. break;
  1595. case 'c' | FORCE_UNICODE:
  1596. case 'C' | FORCE_UNICODE:
  1597. nItemLen = 2;
  1598. va_arg(argList, WCHAR);
  1599. break;
  1600. // strings
  1601. case 's':
  1602. {
  1603. LPCTSTR pstrNextArg = va_arg(argList, LPCTSTR);
  1604. if (pstrNextArg == NULL)
  1605. {
  1606. nItemLen = 6; // "(null)"
  1607. }
  1608. else
  1609. {
  1610. nItemLen = lstrlen(pstrNextArg);
  1611. nItemLen = max(1, nItemLen);
  1612. }
  1613. break;
  1614. }
  1615. case 'S':
  1616. {
  1617. #ifndef _UNICODE
  1618. LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
  1619. if (pstrNextArg == NULL)
  1620. {
  1621. nItemLen = 6; // "(null)"
  1622. }
  1623. else
  1624. {
  1625. nItemLen = (int)wcslen(pstrNextArg);
  1626. nItemLen = max(1, nItemLen);
  1627. }
  1628. #else
  1629. LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
  1630. if (pstrNextArg == NULL)
  1631. {
  1632. nItemLen = 6; // "(null)"
  1633. }
  1634. else
  1635. {
  1636. nItemLen = lstrlenA(pstrNextArg);
  1637. nItemLen = max(1, nItemLen);
  1638. }
  1639. #endif
  1640. break;
  1641. }
  1642. case 's' | FORCE_ANSI:
  1643. case 'S' | FORCE_ANSI:
  1644. {
  1645. LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
  1646. if (pstrNextArg == NULL)
  1647. {
  1648. nItemLen = 6; // "(null)"
  1649. }
  1650. else
  1651. {
  1652. nItemLen = lstrlenA(pstrNextArg);
  1653. nItemLen = max(1, nItemLen);
  1654. }
  1655. break;
  1656. }
  1657. case 's' | FORCE_UNICODE:
  1658. case 'S' | FORCE_UNICODE:
  1659. {
  1660. LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
  1661. if (pstrNextArg == NULL)
  1662. {
  1663. nItemLen = 6; // "(null)"
  1664. }
  1665. else
  1666. {
  1667. nItemLen = (int)wcslen(pstrNextArg);
  1668. nItemLen = max(1, nItemLen);
  1669. }
  1670. break;
  1671. }
  1672. }
  1673. // adjust nItemLen for strings
  1674. if (nItemLen != 0)
  1675. {
  1676. nItemLen = max(nItemLen, nWidth);
  1677. if (nPrecision != 0)
  1678. nItemLen = min(nItemLen, nPrecision);
  1679. }
  1680. else
  1681. {
  1682. switch (*lpsz)
  1683. {
  1684. // integers
  1685. case 'd':
  1686. case 'i':
  1687. case 'u':
  1688. case 'x':
  1689. case 'X':
  1690. case 'o':
  1691. if (nModifier & FORCE_INT64)
  1692. va_arg(argList, __int64);
  1693. else
  1694. va_arg(argList, int);
  1695. nItemLen = 32;
  1696. nItemLen = max(nItemLen, nWidth + nPrecision);
  1697. break;
  1698. #ifndef _ATL_USE_CSTRING_FLOAT
  1699. case 'e':
  1700. case 'f':
  1701. case 'g':
  1702. case 'G':
  1703. ATLASSERT(!"Floating point (%%e, %%f, %%g, and %%G) is not supported by the WTL::CString class.");
  1704. #ifndef _DEBUG
  1705. ::OutputDebugString(_T("Floating point (%%e, %%f, %%g, and %%G) is not supported by the WTL::CString class."));
  1706. ::DebugBreak();
  1707. #endif //!_DEBUG
  1708. break;
  1709. #else //_ATL_USE_CSTRING_FLOAT
  1710. case 'e':
  1711. case 'g':
  1712. case 'G':
  1713. va_arg(argList, double);
  1714. nItemLen = 128;
  1715. nItemLen = max(nItemLen, nWidth + nPrecision);
  1716. break;
  1717. case 'f':
  1718. {
  1719. double f;
  1720. LPTSTR pszTemp;
  1721. // 312 == strlen("-1+(309 zeroes).")
  1722. // 309 zeroes == max precision of a double
  1723. // 6 == adjustment in case precision is not specified,
  1724. // which means that the precision defaults to 6
  1725. pszTemp = (LPTSTR)_alloca(max(nWidth, 312 + nPrecision + 6));
  1726. f = va_arg(argList, double);
  1727. _stprintf(pszTemp, _T( "%*.*f" ), nWidth, nPrecision + 6, f);
  1728. nItemLen = _tcslen(pszTemp);
  1729. }
  1730. break;
  1731. #endif //_ATL_USE_CSTRING_FLOAT
  1732. case 'p':
  1733. va_arg(argList, void*);
  1734. nItemLen = 32;
  1735. nItemLen = max(nItemLen, nWidth + nPrecision);
  1736. break;
  1737. // no output
  1738. case 'n':
  1739. va_arg(argList, int*);
  1740. break;
  1741. default:
  1742. ATLASSERT(FALSE); // unknown formatting option
  1743. }
  1744. }
  1745. // adjust nMaxLen for output nItemLen
  1746. nMaxLen += nItemLen;
  1747. }
  1748. GetBuffer(nMaxLen);
  1749. #ifndef _ATL_USE_CSTRING_FLOAT
  1750. int nRet = wvsprintf(m_pchData, lpszFormat, argListSave);
  1751. #else //_ATL_USE_CSTRING_FLOAT
  1752. int nRet = _vstprintf(m_pchData, lpszFormat, argListSave);
  1753. #endif //_ATL_USE_CSTRING_FLOAT
  1754. nRet; // ref
  1755. ATLASSERT(nRet <= GetAllocLength());
  1756. ReleaseBuffer();
  1757. va_end(argListSave);
  1758. }
  1759. // formatting (using wsprintf style formatting)
  1760. inline void __cdecl CString::Format(LPCTSTR lpszFormat, ...)
  1761. {
  1762. ATLASSERT(_IsValidString(lpszFormat, FALSE));
  1763. va_list argList;
  1764. va_start(argList, lpszFormat);
  1765. FormatV(lpszFormat, argList);
  1766. va_end(argList);
  1767. }
  1768. inline void __cdecl CString::Format(UINT nFormatID, ...)
  1769. {
  1770. CString strFormat;
  1771. BOOL bRet = strFormat.LoadString(nFormatID);
  1772. bRet; // ref
  1773. ATLASSERT(bRet != 0);
  1774. va_list argList;
  1775. va_start(argList, nFormatID);
  1776. FormatV(strFormat, argList);
  1777. va_end(argList);
  1778. }
  1779. // formatting (using FormatMessage style formatting)
  1780. inline BOOL __cdecl CString::FormatMessage(LPCTSTR lpszFormat, ...)
  1781. {
  1782. // format message into temporary buffer lpszTemp
  1783. va_list argList;
  1784. va_start(argList, lpszFormat);
  1785. LPTSTR lpszTemp;
  1786. BOOL bRet = TRUE;
  1787. if (::FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  1788. lpszFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0 || lpszTemp == NULL)
  1789. bRet = FALSE;
  1790. // assign lpszTemp into the resulting string and free the temporary
  1791. *this = lpszTemp;
  1792. LocalFree(lpszTemp);
  1793. va_end(argList);
  1794. return bRet;
  1795. }
  1796. inline BOOL __cdecl CString::FormatMessage(UINT nFormatID, ...)
  1797. {
  1798. // get format string from string table
  1799. CString strFormat;
  1800. BOOL bRetTmp = strFormat.LoadString(nFormatID);
  1801. bRetTmp; // ref
  1802. ATLASSERT(bRetTmp != 0);
  1803. // format message into temporary buffer lpszTemp
  1804. va_list argList;
  1805. va_start(argList, nFormatID);
  1806. LPTSTR lpszTemp;
  1807. BOOL bRet = TRUE;
  1808. if (::FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  1809. strFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0 || lpszTemp == NULL)
  1810. bRet = FALSE;
  1811. // assign lpszTemp into the resulting string and free lpszTemp
  1812. *this = lpszTemp;
  1813. LocalFree(lpszTemp);
  1814. va_end(argList);
  1815. return bRet;
  1816. }
  1817. inline void CString::TrimRight()
  1818. {
  1819. CopyBeforeWrite();
  1820. // find beginning of trailing spaces by starting at beginning (DBCS aware)
  1821. LPTSTR lpsz = m_pchData;
  1822. LPTSTR lpszLast = NULL;
  1823. while (*lpsz != '\0')
  1824. {
  1825. if (_cstrisspace(*lpsz))
  1826. {
  1827. if (lpszLast == NULL)
  1828. lpszLast = lpsz;
  1829. }
  1830. else
  1831. {
  1832. lpszLast = NULL;
  1833. }
  1834. lpsz = ::CharNext(lpsz);
  1835. }
  1836. if (lpszLast != NULL)
  1837. {
  1838. // truncate at trailing space start
  1839. *lpszLast = '\0';
  1840. GetData()->nDataLength = (int)(DWORD_PTR)(lpszLast - m_pchData);
  1841. }
  1842. }
  1843. inline void CString::TrimLeft()
  1844. {
  1845. CopyBeforeWrite();
  1846. // find first non-space character
  1847. LPCTSTR lpsz = m_pchData;
  1848. while (_cstrisspace(*lpsz))
  1849. lpsz = ::CharNext(lpsz);
  1850. // fix up data and length
  1851. int nDataLength = GetData()->nDataLength - (int)(DWORD_PTR)(lpsz - m_pchData);
  1852. memmove(m_pchData, lpsz, (nDataLength + 1) * sizeof(TCHAR));
  1853. GetData()->nDataLength = nDataLength;
  1854. }
  1855. inline int CString::Delete(int nIndex, int nCount /* = 1 */)
  1856. {
  1857. if (nIndex < 0)
  1858. nIndex = 0;
  1859. int nNewLength = GetData()->nDataLength;
  1860. if (nCount > 0 && nIndex < nNewLength)
  1861. {
  1862. CopyBeforeWrite();
  1863. int nBytesToCopy = nNewLength - (nIndex + nCount) + 1;
  1864. memmove(m_pchData + nIndex, m_pchData + nIndex + nCount, nBytesToCopy * sizeof(TCHAR));
  1865. GetData()->nDataLength = nNewLength - nCount;
  1866. }
  1867. return nNewLength;
  1868. }
  1869. inline int CString::Insert(int nIndex, TCHAR ch)
  1870. {
  1871. CopyBeforeWrite();
  1872. if (nIndex < 0)
  1873. nIndex = 0;
  1874. int nNewLength = GetData()->nDataLength;
  1875. if (nIndex > nNewLength)
  1876. nIndex = nNewLength;
  1877. nNewLength++;
  1878. if (GetData()->nAllocLength < nNewLength)
  1879. {
  1880. CStringData* pOldData = GetData();
  1881. LPTSTR pstr = m_pchData;
  1882. if(!AllocBuffer(nNewLength))
  1883. return -1;
  1884. memcpy(m_pchData, pstr, (pOldData->nDataLength + 1) * sizeof(TCHAR));
  1885. CString::Release(pOldData);
  1886. }
  1887. // move existing bytes down
  1888. memmove(m_pchData + nIndex + 1, m_pchData + nIndex, (nNewLength - nIndex) * sizeof(TCHAR));
  1889. m_pchData[nIndex] = ch;
  1890. GetData()->nDataLength = nNewLength;
  1891. return nNewLength;
  1892. }
  1893. inline int CString::Insert(int nIndex, LPCTSTR pstr)
  1894. {
  1895. if (nIndex < 0)
  1896. nIndex = 0;
  1897. int nInsertLength = SafeStrlen(pstr);
  1898. int nNewLength = GetData()->nDataLength;
  1899. if (nInsertLength > 0)
  1900. {
  1901. CopyBeforeWrite();
  1902. if (nIndex > nNewLength)
  1903. nIndex = nNewLength;
  1904. nNewLength += nInsertLength;
  1905. if (GetData()->nAllocLength < nNewLength)
  1906. {
  1907. CStringData* pOldData = GetData();
  1908. LPTSTR pstr = m_pchData;
  1909. if(!AllocBuffer(nNewLength))
  1910. return -1;
  1911. memcpy(m_pchData, pstr, (pOldData->nDataLength + 1) * sizeof(TCHAR));
  1912. CString::Release(pOldData);
  1913. }
  1914. // move existing bytes down
  1915. memmove(m_pchData + nIndex + nInsertLength, m_pchData + nIndex, (nNewLength - nIndex - nInsertLength + 1) * sizeof(TCHAR));
  1916. memcpy(m_pchData + nIndex, pstr, nInsertLength * sizeof(TCHAR));
  1917. GetData()->nDataLength = nNewLength;
  1918. }
  1919. return nNewLength;
  1920. }
  1921. inline int CString::Replace(TCHAR chOld, TCHAR chNew)
  1922. {
  1923. int nCount = 0;
  1924. // short-circuit the nop case
  1925. if (chOld != chNew)
  1926. {
  1927. // otherwise modify each character that matches in the string
  1928. CopyBeforeWrite();
  1929. LPTSTR psz = m_pchData;
  1930. LPTSTR pszEnd = psz + GetData()->nDataLength;
  1931. while (psz < pszEnd)
  1932. {
  1933. // replace instances of the specified character only
  1934. if (*psz == chOld)
  1935. {
  1936. *psz = chNew;
  1937. nCount++;
  1938. }
  1939. psz = ::CharNext(psz);
  1940. }
  1941. }
  1942. return nCount;
  1943. }
  1944. inline int CString::Replace(LPCTSTR lpszOld, LPCTSTR lpszNew)
  1945. {
  1946. // can't have empty or NULL lpszOld
  1947. int nSourceLen = SafeStrlen(lpszOld);
  1948. if (nSourceLen == 0)
  1949. return 0;
  1950. int nReplacementLen = SafeStrlen(lpszNew);
  1951. // loop once to figure out the size of the result string
  1952. int nCount = 0;
  1953. LPTSTR lpszStart = m_pchData;
  1954. LPTSTR lpszEnd = m_pchData + GetData()->nDataLength;
  1955. LPTSTR lpszTarget;
  1956. while (lpszStart < lpszEnd)
  1957. {
  1958. while ((lpszTarget = _cstrstr(lpszStart, lpszOld)) != NULL)
  1959. {
  1960. nCount++;
  1961. lpszStart = lpszTarget + nSourceLen;
  1962. }
  1963. lpszStart += lstrlen(lpszStart) + 1;
  1964. }
  1965. // if any changes were made, make them
  1966. if (nCount > 0)
  1967. {
  1968. CopyBeforeWrite();
  1969. // if the buffer is too small, just
  1970. // allocate a new buffer (slow but sure)
  1971. int nOldLength = GetData()->nDataLength;
  1972. int nNewLength = nOldLength + (nReplacementLen - nSourceLen) * nCount;
  1973. if (GetData()->nAllocLength < nNewLength || GetData()->nRefs > 1)
  1974. {
  1975. CStringData* pOldData = GetData();
  1976. LPTSTR pstr = m_pchData;
  1977. if(!AllocBuffer(nNewLength))
  1978. return -1;
  1979. memcpy(m_pchData, pstr, pOldData->nDataLength * sizeof(TCHAR));
  1980. CString::Release(pOldData);
  1981. }
  1982. // else, we just do it in-place
  1983. lpszStart = m_pchData;
  1984. lpszEnd = m_pchData + GetData()->nDataLength;
  1985. // loop again to actually do the work
  1986. while (lpszStart < lpszEnd)
  1987. {
  1988. while ( (lpszTarget = _cstrstr(lpszStart, lpszOld)) != NULL)
  1989. {
  1990. int nBalance = nOldLength - ((int)(DWORD_PTR)(lpszTarget - m_pchData) + nSourceLen);
  1991. memmove(lpszTarget + nReplacementLen, lpszTarget + nSourceLen, nBalance * sizeof(TCHAR));
  1992. memcpy(lpszTarget, lpszNew, nReplacementLen * sizeof(TCHAR));
  1993. lpszStart = lpszTarget + nReplacementLen;
  1994. lpszStart[nBalance] = '\0';
  1995. nOldLength += (nReplacementLen - nSourceLen);
  1996. }
  1997. lpszStart += lstrlen(lpszStart) + 1;
  1998. }
  1999. ATLASSERT(m_pchData[nNewLength] == '\0');
  2000. GetData()->nDataLength = nNewLength;
  2001. }
  2002. return nCount;
  2003. }
  2004. inline int CString::Remove(TCHAR chRemove)
  2005. {
  2006. CopyBeforeWrite();
  2007. LPTSTR pstrSource = m_pchData;
  2008. LPTSTR pstrDest = m_pchData;
  2009. LPTSTR pstrEnd = m_pchData + GetData()->nDataLength;
  2010. while (pstrSource < pstrEnd)
  2011. {
  2012. if (*pstrSource != chRemove)
  2013. {
  2014. *pstrDest = *pstrSource;
  2015. pstrDest = ::CharNext(pstrDest);
  2016. }
  2017. pstrSource = ::CharNext(pstrSource);
  2018. }
  2019. *pstrDest = '\0';
  2020. int nCount = (int)(DWORD_PTR)(pstrSource - pstrDest);
  2021. GetData()->nDataLength -= nCount;
  2022. return nCount;
  2023. }
  2024. #ifdef _UNICODE
  2025. #define CHAR_FUDGE 1 // one TCHAR unused is good enough
  2026. #else
  2027. #define CHAR_FUDGE 2 // two BYTES unused for case of DBC last char
  2028. #endif
  2029. inline BOOL CString::LoadString(UINT nID)
  2030. {
  2031. // try fixed buffer first (to avoid wasting space in the heap)
  2032. TCHAR szTemp[256];
  2033. int nCount = sizeof(szTemp) / sizeof(szTemp[0]);
  2034. int nLen = _LoadString(nID, szTemp, nCount);
  2035. if (nCount - nLen > CHAR_FUDGE)
  2036. {
  2037. *this = szTemp;
  2038. return nLen > 0;
  2039. }
  2040. // try buffer size of 512, then larger size until entire string is retrieved
  2041. int nSize = 256;
  2042. do
  2043. {
  2044. nSize += 256;
  2045. nLen = _LoadString(nID, GetBuffer(nSize - 1), nSize);
  2046. } while (nSize - nLen <= CHAR_FUDGE);
  2047. ReleaseBuffer();
  2048. return nLen > 0;
  2049. }
  2050. #ifndef _ATL_NO_COM
  2051. inline BSTR CString::AllocSysString() const
  2052. {
  2053. #if defined(_UNICODE) || defined(OLE2ANSI)
  2054. BSTR bstr = ::SysAllocStringLen(m_pchData, GetData()->nDataLength);
  2055. #else
  2056. int nLen = MultiByteToWideChar(CP_ACP, 0, m_pchData,
  2057. GetData()->nDataLength, NULL, NULL);
  2058. BSTR bstr = ::SysAllocStringLen(NULL, nLen);
  2059. if(bstr != NULL)
  2060. MultiByteToWideChar(CP_ACP, 0, m_pchData, GetData()->nDataLength, bstr, nLen);
  2061. #endif
  2062. return bstr;
  2063. }
  2064. inline BSTR CString::SetSysString(BSTR* pbstr) const
  2065. {
  2066. #if defined(_UNICODE) || defined(OLE2ANSI)
  2067. ::SysReAllocStringLen(pbstr, m_pchData, GetData()->nDataLength);
  2068. #else
  2069. int nLen = MultiByteToWideChar(CP_ACP, 0, m_pchData,
  2070. GetData()->nDataLength, NULL, NULL);
  2071. if(::SysReAllocStringLen(pbstr, NULL, nLen))
  2072. MultiByteToWideChar(CP_ACP, 0, m_pchData, GetData()->nDataLength, *pbstr, nLen);
  2073. #endif
  2074. ATLASSERT(*pbstr != NULL);
  2075. return *pbstr;
  2076. }
  2077. #endif //!_ATL_NO_COM
  2078. #endif //!_WTL_NO_CSTRING
  2079. /////////////////////////////////////////////////////////////////////////////
  2080. // CRecentDocumentList - MRU List Support
  2081. // forward declaration
  2082. inline bool AtlCompactPath(LPTSTR lpstrOut, LPCTSTR lpstrIn, int cchLen);
  2083. template <class T, int t_cchItemLen = MAX_PATH>
  2084. class CRecentDocumentListBase
  2085. {
  2086. public:
  2087. // Declarations
  2088. struct _DocEntry
  2089. {
  2090. TCHAR szDocName[t_cchItemLen];
  2091. bool operator==(const _DocEntry& de) const
  2092. { return (lstrcmpi(szDocName, de.szDocName) == 0); }
  2093. };
  2094. enum
  2095. {
  2096. m_nMaxEntries_Min = 2,
  2097. m_nMaxEntries_Max = ID_FILE_MRU_LAST - ID_FILE_MRU_FIRST + 1,
  2098. m_cchMaxItemLen_Min = 6,
  2099. m_cchMaxItemLen_Max = t_cchItemLen
  2100. };
  2101. // Data members
  2102. CSimpleArray<_DocEntry> m_arrDocs;
  2103. int m_nMaxEntries; // default is 4
  2104. HMENU m_hMenu;
  2105. TCHAR m_szNoEntries[t_cchItemLen];
  2106. int m_cchMaxItemLen;
  2107. // Constructor
  2108. CRecentDocumentListBase() : m_hMenu(NULL), m_nMaxEntries(4), m_cchMaxItemLen(-1)
  2109. {
  2110. ATLASSERT(t_cchItemLen > m_cchMaxItemLen_Min);
  2111. }
  2112. // Attributes
  2113. HMENU GetMenuHandle() const
  2114. {
  2115. return m_hMenu;
  2116. }
  2117. void SetMenuHandle(HMENU hMenu)
  2118. {
  2119. ATLASSERT(hMenu == NULL || ::IsMenu(hMenu));
  2120. m_hMenu = hMenu;
  2121. if(m_hMenu == NULL || (::GetMenuString(m_hMenu, ID_FILE_MRU_FIRST, m_szNoEntries, t_cchItemLen, MF_BYCOMMAND) == 0))
  2122. lstrcpy(m_szNoEntries, _T("(empty)"));
  2123. }
  2124. int GetMaxEntries() const
  2125. {
  2126. return m_nMaxEntries;
  2127. }
  2128. void SetMaxEntries(int nMaxEntries)
  2129. {
  2130. ATLASSERT(nMaxEntries > m_nMaxEntries_Min && nMaxEntries < m_nMaxEntries_Max);
  2131. if(nMaxEntries < m_nMaxEntries_Min)
  2132. nMaxEntries = m_nMaxEntries_Min;
  2133. else if(nMaxEntries > m_nMaxEntries_Max)
  2134. nMaxEntries = m_nMaxEntries_Max;
  2135. m_nMaxEntries = nMaxEntries;
  2136. }
  2137. int GetMaxItemLength() const
  2138. {
  2139. return m_cchMaxItemLen;
  2140. }
  2141. void SetMaxItemLength(int cchMaxLen)
  2142. {
  2143. ATLASSERT((cchMaxLen >= m_cchMaxItemLen_Min && cchMaxLen <= m_cchMaxItemLen_Max) || cchMaxLen == -1);
  2144. if(cchMaxLen != -1)
  2145. {
  2146. if(cchMaxLen < m_cchMaxItemLen_Min)
  2147. cchMaxLen = m_cchMaxItemLen_Min;
  2148. else if(cchMaxLen > m_cchMaxItemLen_Max)
  2149. cchMaxLen = m_cchMaxItemLen_Max;
  2150. }
  2151. m_cchMaxItemLen = cchMaxLen;
  2152. T* pT = static_cast<T*>(this);
  2153. pT->UpdateMenu();
  2154. }
  2155. // Operations
  2156. BOOL AddToList(LPCTSTR lpstrDocName)
  2157. {
  2158. _DocEntry de;
  2159. if(lstrcpy(de.szDocName, lpstrDocName) == NULL)
  2160. return FALSE;
  2161. for(int i = 0; i < m_arrDocs.GetSize(); i++)
  2162. {
  2163. if(lstrcmpi(m_arrDocs[i].szDocName, lpstrDocName) == 0)
  2164. {
  2165. m_arrDocs.RemoveAt(i);
  2166. break;
  2167. }
  2168. }
  2169. if(m_arrDocs.GetSize() == m_nMaxEntries)
  2170. m_arrDocs.RemoveAt(0);
  2171. BOOL bRet = m_arrDocs.Add(de);
  2172. if(bRet)
  2173. {
  2174. T* pT = static_cast<T*>(this);
  2175. bRet = pT->UpdateMenu();
  2176. }
  2177. return bRet;
  2178. }
  2179. BOOL GetFromList(int nItemID, LPTSTR lpstrDocName)
  2180. {
  2181. int nIndex = m_arrDocs.GetSize() - (nItemID - ID_FILE_MRU_FIRST) - 1;
  2182. if(nIndex < 0 || nIndex >= m_arrDocs.GetSize())
  2183. return FALSE;
  2184. return (lstrcpy(lpstrDocName, m_arrDocs[nIndex].szDocName) != NULL);
  2185. }
  2186. BOOL RemoveFromList(int nItemID)
  2187. {
  2188. int nIndex = m_arrDocs.GetSize() - (nItemID - ID_FILE_MRU_FIRST) - 1;
  2189. BOOL bRet = m_arrDocs.RemoveAt(nIndex);
  2190. if(bRet)
  2191. {
  2192. T* pT = static_cast<T*>(this);
  2193. bRet = pT->UpdateMenu();
  2194. }
  2195. return bRet;
  2196. }
  2197. BOOL MoveToTop(int nItemID)
  2198. {
  2199. int nIndex = m_arrDocs.GetSize() - 1 - (nItemID - ID_FILE_MRU_FIRST);
  2200. if(nIndex < 0 || nIndex >= m_arrDocs.GetSize())
  2201. return FALSE;
  2202. _DocEntry de;
  2203. de = m_arrDocs[nIndex];
  2204. m_arrDocs.RemoveAt(nIndex);
  2205. BOOL bRet = m_arrDocs.Add(de);
  2206. if(bRet)
  2207. {
  2208. T* pT = static_cast<T*>(this);
  2209. bRet = pT->UpdateMenu();
  2210. }
  2211. return bRet;
  2212. }
  2213. BOOL ReadFromRegistry(LPCTSTR lpstrRegKey)
  2214. {
  2215. CRegKey rkParent;
  2216. CRegKey rk;
  2217. LONG lRet = rkParent.Open(HKEY_CURRENT_USER, lpstrRegKey);
  2218. if(lRet != ERROR_SUCCESS)
  2219. return FALSE;
  2220. lRet = rk.Open(rkParent, _T("Recent Document List"));
  2221. if(lRet != ERROR_SUCCESS)
  2222. return FALSE;
  2223. DWORD dwRet;
  2224. lRet = rk.QueryValue(dwRet, _T("DocumentCount"));
  2225. if(lRet == ERROR_SUCCESS || dwRet > 0 && dwRet < (ID_FILE_MRU_LAST - ID_FILE_MRU_FIRST + 1))
  2226. m_nMaxEntries = dwRet;
  2227. m_arrDocs.RemoveAll();
  2228. TCHAR szRetString[t_cchItemLen];
  2229. _DocEntry de;
  2230. for(int nItem = m_nMaxEntries; nItem > 0; nItem--)
  2231. {
  2232. TCHAR szBuff[11];
  2233. wsprintf(szBuff, _T("Document%i"), nItem);
  2234. DWORD dwCount = t_cchItemLen * sizeof(TCHAR);
  2235. lRet = rk.QueryValue(szRetString, szBuff, &dwCount);
  2236. if(lRet == ERROR_SUCCESS && (lstrcpy(de.szDocName, szRetString) != NULL))
  2237. m_arrDocs.Add(de);
  2238. }
  2239. rk.Close();
  2240. rkParent.Close();
  2241. T* pT = static_cast<T*>(this);
  2242. return pT->UpdateMenu();
  2243. }
  2244. BOOL WriteToRegistry(LPCTSTR lpstrRegKey)
  2245. {
  2246. CRegKey rkParent;
  2247. CRegKey rk;
  2248. LONG lRet = rkParent.Create(HKEY_CURRENT_USER, lpstrRegKey);
  2249. if(lRet != ERROR_SUCCESS)
  2250. return FALSE;
  2251. lRet = rk.Create(rkParent, _T("Recent Document List"));
  2252. if(lRet != ERROR_SUCCESS)
  2253. return FALSE;
  2254. lRet = rk.SetValue(m_nMaxEntries, _T("DocumentCount"));
  2255. ATLASSERT(lRet == ERROR_SUCCESS);
  2256. // set new values
  2257. int nItem;
  2258. for(nItem = m_arrDocs.GetSize(); nItem > 0; nItem--)
  2259. {
  2260. TCHAR szBuff[11];
  2261. wsprintf(szBuff, _T("Document%i"), nItem);
  2262. TCHAR szDocName[t_cchItemLen];
  2263. GetFromList(ID_FILE_MRU_FIRST + nItem - 1, szDocName);
  2264. lRet = rk.SetValue(szDocName, szBuff);
  2265. ATLASSERT(lRet == ERROR_SUCCESS);
  2266. }
  2267. // delete unused keys
  2268. for(nItem = m_arrDocs.GetSize() + 1; nItem < (ID_FILE_MRU_LAST - ID_FILE_MRU_FIRST + 1); nItem++)
  2269. {
  2270. TCHAR szBuff[11];
  2271. wsprintf(szBuff, _T("Document%i"), nItem);
  2272. rk.DeleteValue(szBuff);
  2273. }
  2274. rk.Close();
  2275. rkParent.Close();
  2276. return TRUE;
  2277. }
  2278. // Implementation
  2279. BOOL UpdateMenu()
  2280. {
  2281. if(m_hMenu == NULL)
  2282. return FALSE;
  2283. ATLASSERT(::IsMenu(m_hMenu));
  2284. int nItems = ::GetMenuItemCount(m_hMenu);
  2285. int nInsertPoint;
  2286. for(nInsertPoint = 0; nInsertPoint < nItems; nInsertPoint++)
  2287. {
  2288. MENUITEMINFO mi;
  2289. mi.cbSize = sizeof(MENUITEMINFO);
  2290. mi.fMask = MIIM_ID;
  2291. ::GetMenuItemInfo(m_hMenu, nInsertPoint, TRUE, &mi);
  2292. if (mi.wID == ID_FILE_MRU_FIRST)
  2293. break;
  2294. }
  2295. ATLASSERT(nInsertPoint < nItems && "You need a menu item with an ID = ID_FILE_MRU_FIRST");
  2296. int nItem;
  2297. for(nItem = ID_FILE_MRU_FIRST; nItem < ID_FILE_MRU_FIRST + m_nMaxEntries; nItem++)
  2298. {
  2299. // keep the first one as an insertion point
  2300. if (nItem != ID_FILE_MRU_FIRST)
  2301. ::DeleteMenu(m_hMenu, nItem, MF_BYCOMMAND);
  2302. }
  2303. TCHAR szItemText[t_cchItemLen + 6]; // add space for &, 2 digits, and a space
  2304. int nSize = m_arrDocs.GetSize();
  2305. nItem = 0;
  2306. if(nSize > 0)
  2307. {
  2308. for(nItem = 0; nItem < nSize; nItem++)
  2309. {
  2310. if(m_cchMaxItemLen == -1)
  2311. {
  2312. wsprintf(szItemText, _T("&%i %s"), nItem + 1, m_arrDocs[nSize - 1 - nItem].szDocName);
  2313. }
  2314. else
  2315. {
  2316. TCHAR szBuff[t_cchItemLen];
  2317. T* pT = static_cast<T*>(this);
  2318. pT; // avoid level 4 warning
  2319. bool bRet = pT->CompactDocumentName(szBuff, m_arrDocs[nSize - 1 - nItem].szDocName, m_cchMaxItemLen);
  2320. bRet; // avoid level 4 warning
  2321. ATLASSERT(bRet);
  2322. wsprintf(szItemText, _T("&%i %s"), nItem + 1, szBuff);
  2323. }
  2324. ::InsertMenu(m_hMenu, nInsertPoint + nItem, MF_BYPOSITION | MF_STRING, ID_FILE_MRU_FIRST + nItem, szItemText);
  2325. }
  2326. }
  2327. else // empty
  2328. {
  2329. ::InsertMenu(m_hMenu, nInsertPoint, MF_BYPOSITION | MF_STRING, ID_FILE_MRU_FIRST, m_szNoEntries);
  2330. ::EnableMenuItem(m_hMenu, ID_FILE_MRU_FIRST, MF_GRAYED);
  2331. nItem++;
  2332. }
  2333. ::DeleteMenu(m_hMenu, nInsertPoint + nItem, MF_BYPOSITION);
  2334. return TRUE;
  2335. }
  2336. // Overrideable
  2337. // override to provide a different method of compacting document names
  2338. static bool CompactDocumentName(LPTSTR lpstrOut, LPCTSTR lpstrIn, int cchLen)
  2339. {
  2340. return AtlCompactPath(lpstrOut, lpstrIn, cchLen);
  2341. }
  2342. };
  2343. class CRecentDocumentList : public CRecentDocumentListBase<CRecentDocumentList>
  2344. {
  2345. public:
  2346. // nothing here
  2347. };
  2348. /////////////////////////////////////////////////////////////////////////////
  2349. // CFindFile - file search helper class
  2350. class CFindFile
  2351. {
  2352. public:
  2353. // Data members
  2354. WIN32_FIND_DATA m_fd;
  2355. TCHAR m_lpszRoot[MAX_PATH];
  2356. TCHAR m_chDirSeparator;
  2357. HANDLE m_hFind;
  2358. BOOL m_bFound;
  2359. // Constructor/destructor
  2360. CFindFile() : m_hFind(NULL), m_chDirSeparator('\\'), m_bFound(FALSE)
  2361. { }
  2362. ~CFindFile()
  2363. {
  2364. Close();
  2365. }
  2366. // Attributes
  2367. ULONGLONG GetFileSize() const
  2368. {
  2369. ATLASSERT(m_hFind != NULL);
  2370. ULARGE_INTEGER nFileSize;
  2371. if(m_bFound)
  2372. {
  2373. nFileSize.LowPart = m_fd.nFileSizeLow;
  2374. nFileSize.HighPart = m_fd.nFileSizeHigh;
  2375. }
  2376. else
  2377. {
  2378. nFileSize.QuadPart = 0;
  2379. }
  2380. return nFileSize.QuadPart;
  2381. }
  2382. BOOL GetFileName(LPTSTR lpstrFileName, int cchLength) const
  2383. {
  2384. ATLASSERT(m_hFind != NULL);
  2385. if(lstrlen(m_fd.cFileName) >= cchLength)
  2386. return FALSE;
  2387. return (m_bFound && (lstrcpy(lpstrFileName, m_fd.cFileName) != NULL));
  2388. }
  2389. BOOL GetFilePath(LPTSTR lpstrFilePath, int cchLength) const
  2390. {
  2391. ATLASSERT(m_hFind != NULL);
  2392. int nLen = lstrlen(m_lpszRoot);
  2393. ATLASSERT(nLen > 0);
  2394. if(nLen == 0)
  2395. return FALSE;
  2396. bool bAddSep = (m_lpszRoot[nLen - 1] != '\\' && m_lpszRoot[nLen - 1] != '/');
  2397. if((lstrlen(m_lpszRoot) + (bAddSep ? 1 : 0)) >= cchLength)
  2398. return FALSE;
  2399. BOOL bRet = (lstrcpy(lpstrFilePath, m_lpszRoot) != NULL);
  2400. if(bRet)
  2401. {
  2402. TCHAR szSeparator[2] = { m_chDirSeparator, 0 };
  2403. bRet = (lstrcat(lpstrFilePath, szSeparator) != NULL);
  2404. }
  2405. return bRet;
  2406. }
  2407. BOOL GetFileTitle(LPTSTR lpstrFileTitle, int cchLength) const
  2408. {
  2409. ATLASSERT(m_hFind != NULL);
  2410. TCHAR szBuff[MAX_PATH];
  2411. if(!GetFileName(szBuff, MAX_PATH))
  2412. return FALSE;
  2413. TCHAR szNameBuff[_MAX_FNAME];
  2414. _tsplitpath(szBuff, NULL, NULL, szNameBuff, NULL);
  2415. if(lstrlen(szNameBuff) >= cchLength)
  2416. return FALSE;
  2417. return (lstrcpy(lpstrFileTitle, szNameBuff) != NULL);
  2418. }
  2419. BOOL GetFileURL(LPTSTR lpstrFileURL, int cchLength) const
  2420. {
  2421. ATLASSERT(m_hFind != NULL);
  2422. TCHAR szBuff[MAX_PATH];
  2423. if(!GetFilePath(szBuff, MAX_PATH))
  2424. return FALSE;
  2425. LPCTSTR lpstrFileURLPrefix = _T("file://");
  2426. if(lstrlen(szBuff) + lstrlen(lpstrFileURLPrefix) >= cchLength)
  2427. return FALSE;
  2428. if(lstrcpy(lpstrFileURL, lpstrFileURLPrefix) == NULL)
  2429. return FALSE;
  2430. return (lstrcat(lpstrFileURL, szBuff) != NULL);
  2431. }
  2432. BOOL GetRoot(LPTSTR lpstrRoot, int cchLength) const
  2433. {
  2434. ATLASSERT(m_hFind != NULL);
  2435. if(lstrlen(m_lpszRoot) >= cchLength)
  2436. return FALSE;
  2437. return (lstrcpy(lpstrRoot, m_lpszRoot) != NULL);
  2438. }
  2439. #ifndef _WTL_NO_CSTRING
  2440. CString GetFileName() const
  2441. {
  2442. ATLASSERT(m_hFind != NULL);
  2443. CString ret;
  2444. if(m_bFound)
  2445. ret = m_fd.cFileName;
  2446. return ret;
  2447. }
  2448. CString GetFilePath() const
  2449. {
  2450. ATLASSERT(m_hFind != NULL);
  2451. CString strResult = m_lpszRoot;
  2452. if(strResult[strResult.GetLength() - 1] != '\\' &&
  2453. strResult[strResult.GetLength() - 1] != '/')
  2454. strResult += m_chDirSeparator;
  2455. strResult += GetFileName();
  2456. return strResult;
  2457. }
  2458. CString GetFileTitle() const
  2459. {
  2460. ATLASSERT(m_hFind != NULL);
  2461. CString strFullName = GetFileName();
  2462. CString strResult;
  2463. _tsplitpath(strFullName, NULL, NULL, strResult.GetBuffer(MAX_PATH), NULL);
  2464. strResult.ReleaseBuffer();
  2465. return strResult;
  2466. }
  2467. CString GetFileURL() const
  2468. {
  2469. ATLASSERT(m_hFind != NULL);
  2470. CString strResult("file://");
  2471. strResult += GetFilePath();
  2472. return strResult;
  2473. }
  2474. CString GetRoot() const
  2475. {
  2476. ATLASSERT(m_hFind != NULL);
  2477. CString str = m_lpszRoot;
  2478. return str;
  2479. }
  2480. #endif //!_WTL_NO_CSTRING
  2481. BOOL GetLastWriteTime(FILETIME* pTimeStamp) const
  2482. {
  2483. ATLASSERT(m_hFind != NULL);
  2484. ATLASSERT(pTimeStamp != NULL);
  2485. if(m_bFound && pTimeStamp != NULL)
  2486. {
  2487. *pTimeStamp = m_fd.ftLastWriteTime;
  2488. return TRUE;
  2489. }
  2490. return FALSE;
  2491. }
  2492. BOOL GetLastAccessTime(FILETIME* pTimeStamp) const
  2493. {
  2494. ATLASSERT(m_hFind != NULL);
  2495. ATLASSERT(pTimeStamp != NULL);
  2496. if(m_bFound && pTimeStamp != NULL)
  2497. {
  2498. *pTimeStamp = m_fd.ftLastAccessTime;
  2499. return TRUE;
  2500. }
  2501. return FALSE;
  2502. }
  2503. BOOL GetCreationTime(FILETIME* pTimeStamp) const
  2504. {
  2505. ATLASSERT(m_hFind != NULL);
  2506. if(m_bFound && pTimeStamp != NULL)
  2507. {
  2508. *pTimeStamp = m_fd.ftCreationTime;
  2509. return TRUE;
  2510. }
  2511. return FALSE;
  2512. }
  2513. BOOL MatchesMask(DWORD dwMask) const
  2514. {
  2515. ATLASSERT(m_hFind != NULL);
  2516. if(m_bFound)
  2517. return ((m_fd.dwFileAttributes & dwMask) != 0);
  2518. return FALSE;
  2519. }
  2520. BOOL IsDots() const
  2521. {
  2522. ATLASSERT(m_hFind != NULL);
  2523. // return TRUE if the file name is "." or ".." and
  2524. // the file is a directory
  2525. BOOL bResult = FALSE;
  2526. if(m_bFound && IsDirectory())
  2527. {
  2528. if(m_fd.cFileName[0] == '.' && (m_fd.cFileName[1] == '\0' || (m_fd.cFileName[1] == '.' && m_fd.cFileName[2] == '\0')))
  2529. bResult = TRUE;
  2530. }
  2531. return bResult;
  2532. }
  2533. BOOL IsReadOnly() const
  2534. {
  2535. return MatchesMask(FILE_ATTRIBUTE_READONLY);
  2536. }
  2537. BOOL IsDirectory() const
  2538. {
  2539. return MatchesMask(FILE_ATTRIBUTE_DIRECTORY);
  2540. }
  2541. BOOL IsCompressed() const
  2542. {
  2543. return MatchesMask(FILE_ATTRIBUTE_COMPRESSED);
  2544. }
  2545. BOOL IsSystem() const
  2546. {
  2547. return MatchesMask(FILE_ATTRIBUTE_SYSTEM);
  2548. }
  2549. BOOL IsHidden() const
  2550. {
  2551. return MatchesMask(FILE_ATTRIBUTE_HIDDEN);
  2552. }
  2553. BOOL IsTemporary() const
  2554. {
  2555. return MatchesMask(FILE_ATTRIBUTE_TEMPORARY);
  2556. }
  2557. BOOL IsNormal() const
  2558. {
  2559. return MatchesMask(FILE_ATTRIBUTE_NORMAL);
  2560. }
  2561. BOOL IsArchived() const
  2562. {
  2563. return MatchesMask(FILE_ATTRIBUTE_ARCHIVE);
  2564. }
  2565. // Operations
  2566. BOOL FindFile(LPCTSTR pstrName = NULL)
  2567. {
  2568. Close();
  2569. if(pstrName == NULL)
  2570. pstrName = _T("*.*");
  2571. lstrcpy(m_fd.cFileName, pstrName);
  2572. m_hFind = ::FindFirstFile(pstrName, &m_fd);
  2573. if(m_hFind == INVALID_HANDLE_VALUE)
  2574. return FALSE;
  2575. LPCTSTR pstr = _tfullpath(m_lpszRoot, pstrName, MAX_PATH);
  2576. // passed name isn't a valid path but was found by the API
  2577. ATLASSERT(pstr != NULL);
  2578. if(pstr == NULL)
  2579. {
  2580. Close();
  2581. ::SetLastError(ERROR_INVALID_NAME);
  2582. return FALSE;
  2583. }
  2584. else
  2585. {
  2586. // find the last forward or backward whack
  2587. LPTSTR pstrBack = _tcsrchr(m_lpszRoot, '\\');
  2588. LPTSTR pstrFront = _tcsrchr(m_lpszRoot, '/');
  2589. if(pstrFront != NULL || pstrBack != NULL)
  2590. {
  2591. if(pstrFront == NULL)
  2592. pstrFront = m_lpszRoot;
  2593. if(pstrBack == NULL)
  2594. pstrBack = m_lpszRoot;
  2595. // from the start to the last whack is the root
  2596. if(pstrFront >= pstrBack)
  2597. *pstrFront = '\0';
  2598. else
  2599. *pstrBack = '\0';
  2600. }
  2601. }
  2602. m_bFound = TRUE;
  2603. return TRUE;
  2604. }
  2605. BOOL FindNextFile()
  2606. {
  2607. ATLASSERT(m_hFind != NULL);
  2608. if(m_hFind == NULL)
  2609. return FALSE;
  2610. if(!m_bFound)
  2611. return FALSE;
  2612. m_bFound = ::FindNextFile(m_hFind, &m_fd);
  2613. return m_bFound;
  2614. }
  2615. void Close()
  2616. {
  2617. m_bFound = FALSE;
  2618. if(m_hFind != NULL && m_hFind != INVALID_HANDLE_VALUE)
  2619. {
  2620. ::FindClose(m_hFind);
  2621. m_hFind = NULL;
  2622. }
  2623. }
  2624. };
  2625. /////////////////////////////////////////////////////////////////////////////
  2626. // Global functions for loading resources
  2627. inline HACCEL AtlLoadAccelerators(_U_STRINGorID table)
  2628. {
  2629. return ::LoadAccelerators(_Module.GetResourceInstance(), table.m_lpstr);
  2630. }
  2631. inline HMENU AtlLoadMenu(_U_STRINGorID menu)
  2632. {
  2633. return ::LoadMenu(_Module.GetResourceInstance(), menu.m_lpstr);
  2634. }
  2635. inline HBITMAP AtlLoadBitmap(_U_STRINGorID bitmap)
  2636. {
  2637. return ::LoadBitmap(_Module.GetResourceInstance(), bitmap.m_lpstr);
  2638. }
  2639. #ifdef OEMRESOURCE
  2640. inline HBITMAP AtlLoadSysBitmap(LPCTSTR lpBitmapName)
  2641. {
  2642. #ifdef _DEBUG
  2643. WORD wID = (WORD)lpBitmapName;
  2644. ATLASSERT(wID >= 32734 && wID <= 32767);
  2645. #endif //_DEBUG
  2646. return ::LoadBitmap(NULL, lpBitmapName);
  2647. }
  2648. #endif //OEMRESOURCE
  2649. inline HCURSOR AtlLoadCursor(_U_STRINGorID cursor)
  2650. {
  2651. return ::LoadCursor(_Module.GetResourceInstance(), cursor.m_lpstr);
  2652. }
  2653. inline HCURSOR AtlLoadSysCursor(LPCTSTR lpCursorName)
  2654. {
  2655. ATLASSERT(lpCursorName == IDC_ARROW || lpCursorName == IDC_IBEAM || lpCursorName == IDC_WAIT ||
  2656. lpCursorName == IDC_CROSS || lpCursorName == IDC_UPARROW || lpCursorName == IDC_SIZE ||
  2657. lpCursorName == IDC_ICON || lpCursorName == IDC_SIZENWSE || lpCursorName == IDC_SIZENESW ||
  2658. lpCursorName == IDC_SIZEWE || lpCursorName == IDC_SIZENS || lpCursorName == IDC_SIZEALL ||
  2659. lpCursorName == IDC_NO || lpCursorName == IDC_APPSTARTING || lpCursorName == IDC_HELP);
  2660. return ::LoadCursor(NULL, lpCursorName);
  2661. }
  2662. inline HICON AtlLoadIcon(_U_STRINGorID icon)
  2663. {
  2664. return ::LoadIcon(_Module.GetResourceInstance(), icon.m_lpstr);
  2665. }
  2666. inline HICON AtlLoadSysIcon(LPCTSTR lpIconName)
  2667. {
  2668. ATLASSERT(lpIconName == IDI_APPLICATION ||
  2669. lpIconName == IDI_ASTERISK ||
  2670. lpIconName == IDI_EXCLAMATION ||
  2671. lpIconName == IDI_HAND ||
  2672. lpIconName == IDI_QUESTION ||
  2673. lpIconName == IDI_WINLOGO);
  2674. return ::LoadIcon(NULL, lpIconName);
  2675. }
  2676. inline HBITMAP AtlLoadBitmapImage(_U_STRINGorID bitmap, UINT fuLoad = LR_DEFAULTCOLOR)
  2677. {
  2678. return (HBITMAP)::LoadImage(_Module.GetResourceInstance(), bitmap.m_lpstr, IMAGE_BITMAP, 0, 0, fuLoad);
  2679. }
  2680. inline HCURSOR AtlLoadCursorImage(_U_STRINGorID cursor, UINT fuLoad = LR_DEFAULTCOLOR | LR_DEFAULTSIZE, int cxDesired = 0, int cyDesired = 0)
  2681. {
  2682. return (HCURSOR)::LoadImage(_Module.GetResourceInstance(), cursor.m_lpstr, IMAGE_CURSOR, cxDesired, cyDesired, fuLoad);
  2683. }
  2684. inline HICON AtlLoadIconImage(_U_STRINGorID icon, UINT fuLoad = LR_DEFAULTCOLOR | LR_DEFAULTSIZE, int cxDesired = 0, int cyDesired = 0)
  2685. {
  2686. return (HICON)::LoadImage(_Module.GetResourceInstance(), icon.m_lpstr, IMAGE_ICON, cxDesired, cyDesired, fuLoad);
  2687. }
  2688. #ifdef OEMRESOURCE
  2689. inline HBITMAP AtlLoadSysBitmapImage(WORD wBitmapID, UINT fuLoad = LR_DEFAULTCOLOR)
  2690. {
  2691. ATLASSERT(wBitmapID >= 32734 && wBitmapID <= 32767);
  2692. ATLASSERT((fuLoad & LR_LOADFROMFILE) == 0); // this one doesn't load from a file
  2693. return (HBITMAP)::LoadImage(NULL, MAKEINTRESOURCE(wBitmapID), IMAGE_BITMAP, 0, 0, fuLoad);
  2694. }
  2695. #endif //OEMRESOURCE
  2696. inline HCURSOR AtlLoadSysCursorImage(_U_STRINGorID cursor, UINT fuLoad = LR_DEFAULTCOLOR | LR_DEFAULTSIZE, int cxDesired = 0, int cyDesired = 0)
  2697. {
  2698. #ifdef _DEBUG
  2699. WORD wID = (WORD)cursor.m_lpstr;
  2700. ATLASSERT((wID >= 32512 && wID <= 32516) || (wID >= 32640 && wID <= 32648) || (wID == 32650) || (wID == 32651));
  2701. ATLASSERT((fuLoad & LR_LOADFROMFILE) == 0); // this one doesn't load from a file
  2702. #endif //_DEBUG
  2703. return (HCURSOR)::LoadImage(NULL, cursor.m_lpstr, IMAGE_CURSOR, cxDesired, cyDesired, fuLoad);
  2704. }
  2705. inline HICON AtlLoadSysIconImage(_U_STRINGorID icon, UINT fuLoad = LR_DEFAULTCOLOR | LR_DEFAULTSIZE, int cxDesired = 0, int cyDesired = 0)
  2706. {
  2707. #ifdef _DEBUG
  2708. WORD wID = (WORD)icon.m_lpstr;
  2709. ATLASSERT(wID >= 32512 && wID <= 32517);
  2710. ATLASSERT((fuLoad & LR_LOADFROMFILE) == 0); // this one doesn't load from a file
  2711. #endif //_DEBUG
  2712. return (HICON)::LoadImage(NULL, icon.m_lpstr, IMAGE_ICON, cxDesired, cyDesired, fuLoad);
  2713. }
  2714. inline int AtlLoadString(UINT uID, LPTSTR lpBuffer, int nBufferMax)
  2715. {
  2716. return ::LoadString(_Module.GetResourceInstance(), uID, lpBuffer, nBufferMax);
  2717. }
  2718. inline bool AtlLoadString(UINT uID, BSTR& bstrText)
  2719. {
  2720. USES_CONVERSION;
  2721. ATLASSERT(bstrText == NULL);
  2722. LPTSTR lpstrText = NULL;
  2723. int nRes = 0;
  2724. for(int nLen = 256; ; nLen *= 2)
  2725. {
  2726. ATLTRY(lpstrText = new TCHAR[nLen]);
  2727. if(lpstrText == NULL)
  2728. break;
  2729. nRes = ::LoadString(_Module.GetResourceInstance(), uID, lpstrText, nLen);
  2730. if(nRes < nLen - 1)
  2731. break;
  2732. delete [] lpstrText;
  2733. lpstrText = NULL;
  2734. }
  2735. if(lpstrText != NULL)
  2736. {
  2737. if(nRes != 0)
  2738. bstrText = ::SysAllocString(T2OLE(lpstrText));
  2739. delete [] lpstrText;
  2740. }
  2741. return (bstrText != NULL) ? true : false;
  2742. }
  2743. /////////////////////////////////////////////////////////////////////////////
  2744. // Global functions for stock GDI objects
  2745. inline HPEN AtlGetStockPen(int nPen)
  2746. {
  2747. #if (_WIN32_WINNT >= 0x0500)
  2748. ATLASSERT(nPen == WHITE_PEN || nPen == BLACK_PEN || nPen == NULL_PEN || nPen == DC_PEN);
  2749. #else
  2750. ATLASSERT(nPen == WHITE_PEN || nPen == BLACK_PEN || nPen == NULL_PEN);
  2751. #endif //!(_WIN32_WINNT >= 0x0500)
  2752. return (HPEN)::GetStockObject(nPen);
  2753. }
  2754. inline HBRUSH AtlGetStockBrush(int nBrush)
  2755. {
  2756. #if (_WIN32_WINNT >= 0x0500)
  2757. ATLASSERT((nBrush >= WHITE_BRUSH && nBrush <= HOLLOW_BRUSH) || nBrush == DC_BRUSH);
  2758. #else
  2759. ATLASSERT(nBrush >= WHITE_BRUSH && nBrush <= HOLLOW_BRUSH);
  2760. #endif //!(_WIN32_WINNT >= 0x0500)
  2761. return (HBRUSH)::GetStockObject(nBrush);
  2762. }
  2763. inline HFONT AtlGetStockFont(int nFont)
  2764. {
  2765. ATLASSERT((nFont >= OEM_FIXED_FONT && nFont <= SYSTEM_FIXED_FONT) || nFont == DEFAULT_GUI_FONT);
  2766. return (HFONT)::GetStockObject(nFont);
  2767. }
  2768. inline HPALETTE AtlGetStockPalette(int nPalette)
  2769. {
  2770. ATLASSERT(nPalette == DEFAULT_PALETTE); // the only one supported
  2771. return (HPALETTE)::GetStockObject(nPalette);
  2772. }
  2773. /////////////////////////////////////////////////////////////////////////////
  2774. // Global function for compacting a path by replacing parts with ellipsis
  2775. // helper for multi-byte character sets
  2776. inline bool _IsDBCSTrailByte(LPCTSTR lpstr, int nChar)
  2777. {
  2778. #ifndef _UNICODE
  2779. for(int i = nChar; i > 0; i--)
  2780. {
  2781. if(!::IsDBCSLeadByte(lpstr[i - 1]))
  2782. break;
  2783. }
  2784. return ((nChar > 0) && (((nChar - i) & 1) != 0));
  2785. #else //_UNICODE
  2786. lpstr; nChar;
  2787. return false;
  2788. #endif //_UNICODE
  2789. }
  2790. inline bool AtlCompactPath(LPTSTR lpstrOut, LPCTSTR lpstrIn, int cchLen)
  2791. {
  2792. ATLASSERT(lpstrOut != NULL);
  2793. ATLASSERT(lpstrIn != NULL);
  2794. ATLASSERT(cchLen > 0);
  2795. LPCTSTR szEllipsis = _T("...");
  2796. const int cchEndEllipsis = 3;
  2797. const int cchMidEllipsis = 4;
  2798. if(lstrlen(lpstrIn) + 1 < cchLen)
  2799. return (lstrcpy(lpstrOut, lpstrIn) != NULL);
  2800. // check if the separator is a slash or a backslash
  2801. TCHAR chSlash = _T('\\');
  2802. for(LPTSTR lpstr = (LPTSTR)lpstrIn; *lpstr != 0; lpstr = ::CharNext(lpstr))
  2803. {
  2804. if((*lpstr == _T('/')) || (*lpstr == _T('\\')))
  2805. chSlash = *lpstr;
  2806. }
  2807. // find the filename portion of the path
  2808. LPCTSTR lpstrFileName = lpstrIn;
  2809. for(LPCTSTR pPath = lpstrIn; *pPath; pPath = ::CharNext(pPath))
  2810. {
  2811. if((pPath[0] == _T('\\') || pPath[0] == _T(':') || pPath[0] == _T('/'))
  2812. && pPath[1] && pPath[1] != _T('\\') && pPath[1] != _T('/'))
  2813. lpstrFileName = pPath + 1;
  2814. }
  2815. int cchFileName = lstrlen(lpstrFileName);
  2816. // handle just the filename without a path
  2817. if(lpstrFileName == lpstrIn && cchLen > cchEndEllipsis)
  2818. {
  2819. bool bRet = (lstrcpyn(lpstrOut, lpstrIn, cchLen - cchEndEllipsis) != NULL);
  2820. if(bRet)
  2821. {
  2822. #ifndef _UNICODE
  2823. if(_IsDBCSTrailByte(lpstrIn, cchLen - cchEndEllipsis))
  2824. lpstrOut[cchLen - cchEndEllipsis - 1] = 0;
  2825. #endif //_UNICODE
  2826. bRet = (lstrcat(lpstrOut, szEllipsis) != NULL);
  2827. }
  2828. return bRet;
  2829. }
  2830. // handle just ellipsis
  2831. if((cchLen < (cchMidEllipsis + cchEndEllipsis)))
  2832. {
  2833. for(int i = 0; i < cchLen - 1; i++)
  2834. lpstrOut[i] = ((i + 1) == cchMidEllipsis) ? chSlash : _T('.');
  2835. lpstrOut[i] = 0;
  2836. return true;
  2837. }
  2838. // calc how much we have to copy
  2839. int cchToCopy = cchLen - (cchMidEllipsis + cchFileName);
  2840. if(cchToCopy < 0)
  2841. cchToCopy = 0;
  2842. #ifndef _UNICODE
  2843. if(cchToCopy > 0 && _IsDBCSTrailByte(lpstrIn, cchToCopy))
  2844. cchToCopy--;
  2845. #endif //_UNICODE
  2846. bool bRet = (lstrcpyn(lpstrOut, lpstrIn, cchToCopy) != NULL);
  2847. if(!bRet)
  2848. return false;
  2849. // add ellipsis
  2850. bRet = (lstrcat(lpstrOut, szEllipsis) != NULL);
  2851. if(!bRet)
  2852. return false;
  2853. TCHAR szSlash[2] = { chSlash, 0 };
  2854. bRet = (lstrcat(lpstrOut, szSlash) != NULL);
  2855. if(!bRet)
  2856. return false;
  2857. // add filename (and ellipsis, if needed)
  2858. if(cchLen > (cchMidEllipsis + cchFileName))
  2859. {
  2860. bRet = (lstrcat(lpstrOut, lpstrFileName) != NULL);
  2861. }
  2862. else
  2863. {
  2864. cchToCopy = cchLen - cchMidEllipsis - cchEndEllipsis;
  2865. #ifndef _UNICODE
  2866. if(cchToCopy > 0 && _IsDBCSTrailByte(lpstrFileName, cchToCopy))
  2867. cchToCopy--;
  2868. #endif //_UNICODE
  2869. bRet = (lstrcpyn(&lpstrOut[cchMidEllipsis], lpstrFileName, cchToCopy) != NULL);
  2870. if(bRet)
  2871. bRet = (lstrcat(lpstrOut, szEllipsis) != NULL);
  2872. }
  2873. return bRet;
  2874. }
  2875. }; //namespace WTL
  2876. #endif // __ATLMISC_H__