Source code of Windows XP (NT5)
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.

497 lines
9.8 KiB

  1. //
  2. // TSTR - represents a writable position in a string.
  3. //
  4. // Has methods to safely append to the string. Will not overrun buffer,
  5. // truncates if reaches the end.
  6. //
  7. //
  8. // Sample usage:
  9. //
  10. // void SomeFunc( TSTR & str )
  11. // {
  12. // int i = 42;
  13. // str << TEXT("Value is: ") << i;
  14. // }
  15. //
  16. // Can be used with TCHAR*-style APIs, by using the ptr(), left() and
  17. // advance() members. ptr() returns pointer to current write position,
  18. // left() returns number of chars left, and advance() updates the write
  19. // position.
  20. //
  21. // void MyGetWindowText( StrWrPos & str )
  22. // {
  23. // int len = GetWindowText( hWnd, str.ptr(), str.left() );
  24. // str.advance( len );
  25. // }
  26. //
  27. // This makes sure that the text will not be truncated
  28. // void MyGetWindowText( StrWrPos & str )
  29. // {
  30. // str.anticipate( GetWindowTextLength( hWnd );
  31. // int len = GetWindowText( hWnd, str.ptr(), str.left() );
  32. // str.advance( len );
  33. // }
  34. //
  35. // Sample usage:
  36. //
  37. // void Func( TSTR & str );
  38. //
  39. // TSTR s(128);
  40. // s << TEXT("Text added: [");
  41. // Func( s ); // add more text to string
  42. // s << TEXT("]");
  43. //
  44. // SetWindowText( hwnd, s );
  45. //
  46. //
  47. // WriteHex - helper class to output hex values:
  48. //
  49. // Sample usage:
  50. //
  51. // str << TEXT("Value is:") << WriteHex( hwnd, 8 );
  52. //
  53. // Can optionally specify number of digits to output. (result will be
  54. // 0-padded.)
  55. //
  56. //
  57. // WriteError - helper class to output COM error values:
  58. //
  59. // Sample usage:
  60. //
  61. // hr = ProcessData();
  62. // if( hr != S_OK )
  63. // {
  64. // str << WriteError( hr, TEXT("in ProcessData()");
  65. // LogError( str.str() );
  66. // }
  67. //
  68. #ifndef _TSTR_H_
  69. #define _TSTR_H_
  70. #if ! defined( _BASETSD_H_ ) || defined( NEED_BASETSD_DEFINES )
  71. // These allow us to compile with the pre-Win64 SDK (eg. using visual studio)
  72. typedef unsigned long UINT_PTR;
  73. typedef DWORD DWORD_PTR;
  74. #define PtrToInt (int)
  75. #endif
  76. #define LONG_TEXT_LENGTH 40
  77. #include <oaidl.h>
  78. #include <crtdbg.h>
  79. #include <string>
  80. typedef std::basic_string<TCHAR> tstring;
  81. typedef std::string ASTR; // save these names for where we expand
  82. typedef std::wstring WSTR; // the usage of this stuff to include them
  83. class TSTR : public tstring
  84. {
  85. // this is only used for ptr, left and advance functions.
  86. ULONG m_lTheRealSize;
  87. public:
  88. TSTR() : m_lTheRealSize(-1) { }
  89. TSTR(const TCHAR *s) : tstring(s, static_cast<size_type>(lstrlen(s))), m_lTheRealSize(-1) { }
  90. TSTR(const TCHAR *s, size_type n) : tstring(s, n), m_lTheRealSize(-1) { }
  91. TSTR(const tstring& rhs) : tstring(rhs), m_lTheRealSize(-1) { }
  92. TSTR(const tstring& rhs, size_type pos, size_type n) : tstring(rhs, pos, n), m_lTheRealSize(-1) { }
  93. TSTR(size_type n, TCHAR c) : tstring(n, c), m_lTheRealSize(-1) { }
  94. TSTR(size_type n) : tstring(), m_lTheRealSize(-1) { reserve( n + 1 ); }
  95. TSTR(const_iterator first, const_iterator last) : tstring(first, last), m_lTheRealSize(-1) { }
  96. operator const TCHAR * ()
  97. {
  98. return c_str();
  99. }
  100. TCHAR * ptr()
  101. {
  102. _ASSERT(m_lTheRealSize == -1);
  103. m_lTheRealSize = size();
  104. TCHAR *pEnd = &(*end());
  105. resize(capacity());
  106. return pEnd;
  107. }
  108. unsigned int left()
  109. {
  110. unsigned int left;
  111. if (m_lTheRealSize == -1)
  112. left = ( capacity() - size() ) - 1;
  113. else
  114. left = ( capacity() - m_lTheRealSize ) - 1;
  115. return left;
  116. }
  117. void advance( unsigned int c )
  118. {
  119. _ASSERT(m_lTheRealSize != -1); // ptr has not been called so we should not need to advance
  120. if (m_lTheRealSize != -1)
  121. {
  122. at( m_lTheRealSize + c ) = NULL; // make sure this stays null terminated
  123. resize(m_lTheRealSize + c);
  124. m_lTheRealSize = -1;
  125. }
  126. }
  127. void reset()
  128. {
  129. resize(0);
  130. m_lTheRealSize = -1;
  131. }
  132. void anticipate( unsigned int c )
  133. {
  134. if ( c > 0 )
  135. {
  136. unsigned int cSize;
  137. if ( m_lTheRealSize == -1 )
  138. cSize = size();
  139. else
  140. cSize = m_lTheRealSize;
  141. const unsigned int i = capacity() - cSize;
  142. if ( i < c )
  143. reserve( cSize + c + 1 );
  144. }
  145. }
  146. };
  147. inline
  148. TSTR & operator << ( TSTR & str, const TCHAR * obj )
  149. {
  150. if ( obj )
  151. str.append( obj );
  152. return str;
  153. }
  154. inline
  155. TSTR & operator << ( TSTR & str, TCHAR obj )
  156. {
  157. str.append( &obj, 1 );
  158. return str;
  159. }
  160. inline
  161. TSTR & operator << ( TSTR & str, long obj )
  162. {
  163. TCHAR sz[LONG_TEXT_LENGTH];
  164. #ifdef UNICODE
  165. str.append(_ltow( obj, sz, 10 ));
  166. return str;
  167. #else
  168. str.append(_ltoa( obj, sz, 10 ));
  169. return str;
  170. #endif
  171. }
  172. inline
  173. TSTR & operator << ( TSTR & str, unsigned long obj )
  174. {
  175. TCHAR sz[LONG_TEXT_LENGTH];
  176. #ifdef UNICODE
  177. str.append(_ultow( obj, sz, 10 ));
  178. return str;
  179. #else
  180. str.append(_ultoa( obj, sz, 10 ));
  181. return str;
  182. #endif
  183. }
  184. inline
  185. TSTR & operator << ( TSTR & str, int obj )
  186. {
  187. TCHAR sz[LONG_TEXT_LENGTH];
  188. #ifdef UNICODE
  189. str.append(_itow( obj, sz, 10 ));
  190. return str;
  191. #else
  192. str.append(_itoa( obj, sz, 10 ));
  193. return str;
  194. #endif
  195. }
  196. inline
  197. TSTR & operator << ( TSTR & str, unsigned int obj )
  198. {
  199. TCHAR sz[LONG_TEXT_LENGTH];
  200. #ifdef UNICODE
  201. str.append(_ultow( static_cast<unsigned long>(obj), sz, 10 ));
  202. return str;
  203. #else
  204. str.append(_ultoa( static_cast<unsigned long>(obj), sz, 10 ));
  205. return str;
  206. #endif
  207. }
  208. #ifndef UNICODE
  209. inline
  210. TSTR & operator << ( TSTR & str, const WCHAR * obj )
  211. {
  212. if ( obj )
  213. {
  214. str.anticipate( wcslen( obj ) + 1 );
  215. int len = WideCharToMultiByte( CP_ACP, 0, obj, -1, str.ptr(), str.left(), NULL, NULL );
  216. // Len, in this case, includes the terminating NUL - so subtract it, if
  217. // we got one...
  218. if( len > 0 )
  219. len--;
  220. str.advance( len );
  221. }
  222. return str;
  223. }
  224. #endif
  225. //
  226. // WriteHex - helper class to output hex values:
  227. //
  228. // See top of file for usage notes.
  229. //
  230. class WriteHex
  231. {
  232. DWORD_PTR m_dw;
  233. int m_Digits;
  234. public:
  235. // If Digits not specified, uses only as many as needed.
  236. WriteHex( DWORD dw, int Digits = -1 ) : m_dw( dw ), m_Digits( Digits ) { }
  237. // For pointer, pads if necessary to get std. ptr size.
  238. // (sizeof(ptr)*2, since 2 digits per byte in ptr).
  239. WriteHex( const void * pv, int Digits = sizeof(void*)*2 ) : m_dw( (DWORD_PTR)pv ), m_Digits( Digits ) { }
  240. void Write( TSTR & str ) const
  241. {
  242. static const TCHAR * HexChars = TEXT("0123456789ABCDEF");
  243. //str << TEXT("0x");
  244. int Digit;
  245. if( m_Digits == -1 )
  246. {
  247. // Work out number of digits...
  248. Digit = 0;
  249. DWORD test = m_dw;
  250. while( test )
  251. {
  252. Digit++;
  253. test >>= 4;
  254. }
  255. // Special case for 0 - still want one digit.
  256. if( Digit == 0 )
  257. Digit = 1;
  258. }
  259. else
  260. Digit = m_Digits;
  261. while( Digit )
  262. {
  263. Digit--;
  264. str << HexChars[ ( m_dw >> (Digit * 4) ) & 0x0F ];
  265. }
  266. }
  267. };
  268. inline
  269. TSTR & operator << ( TSTR & s, const WriteHex & obj )
  270. {
  271. obj.Write( s );
  272. return s;
  273. }
  274. //
  275. // WriteError - helper class to output COM error values:
  276. //
  277. // See top of file for usage notes.
  278. //
  279. class WriteError
  280. {
  281. HRESULT m_hr;
  282. LPCTSTR m_pWhere;
  283. public:
  284. WriteError( HRESULT hr, LPCTSTR pWhere = NULL )
  285. : m_hr( hr ),
  286. m_pWhere( pWhere )
  287. { }
  288. void Write( TSTR & str ) const
  289. {
  290. str << TEXT("[Error");
  291. if( m_pWhere )
  292. str << TEXT(" ") << m_pWhere;
  293. str << TEXT(": hr=0x") << WriteHex( m_hr ) << TEXT(" - ");
  294. if( m_hr == S_FALSE )
  295. {
  296. str << TEXT("S_FALSE");
  297. }
  298. else
  299. {
  300. int len = FormatMessage(
  301. FORMAT_MESSAGE_FROM_SYSTEM,
  302. NULL,
  303. m_hr,
  304. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  305. str.ptr(),
  306. str.left(),
  307. NULL );
  308. if( len > 2 )
  309. len -= 2; // Ignore trailing /r/n that FmtMsg() adds...
  310. str.advance( len );
  311. }
  312. str << TEXT("]");
  313. }
  314. };
  315. inline
  316. TSTR & operator << ( TSTR & s, const WriteError & obj )
  317. {
  318. obj.Write( s );
  319. return s;
  320. }
  321. inline
  322. TSTR & operator << ( TSTR & s, const GUID & guid )
  323. {
  324. s << TEXT("{") << WriteHex( guid.Data1, 8 ) // DWORD
  325. << TEXT("-") << WriteHex( guid.Data2, 4 ) // WORD
  326. << TEXT("-") << WriteHex( guid.Data3, 4 ) // WORD
  327. << TEXT("-")
  328. << WriteHex( guid.Data4[ 0 ], 2 )
  329. << WriteHex( guid.Data4[ 1 ], 2 )
  330. << TEXT("-");
  331. for( int i = 2 ; i < 8 ; i++ )
  332. {
  333. s << WriteHex( guid.Data4[ i ], 2 ); // BYTE
  334. }
  335. s << TEXT("}");
  336. return s;
  337. }
  338. inline
  339. TSTR & operator << ( TSTR & s, const VARIANT & var )
  340. {
  341. s << TEXT("[");
  342. switch( var.vt )
  343. {
  344. case VT_EMPTY:
  345. {
  346. s << TEXT("VT_EMPTY");
  347. break;
  348. }
  349. case VT_I4:
  350. {
  351. s << TEXT("VT_I4=0x");
  352. s << WriteHex( var.lVal );
  353. break;
  354. }
  355. case VT_I2:
  356. {
  357. s << TEXT("VT_I2=0x");
  358. s << WriteHex( var.iVal );
  359. break;
  360. }
  361. case VT_BOOL:
  362. {
  363. s << TEXT("VT_BOOL=");
  364. if( var.boolVal == VARIANT_TRUE )
  365. s << TEXT("TRUE");
  366. else if( var.boolVal == VARIANT_FALSE )
  367. s << TEXT("FALSE");
  368. else
  369. s << TEXT("?") << var.boolVal;
  370. break;
  371. }
  372. case VT_R4:
  373. {
  374. float fltval = var.fltVal;
  375. int x = (int)(fltval * 100);
  376. s << TEXT("VT_R4=") << x/100 << TEXT(".")
  377. << x/10 % 10
  378. << x % 10;
  379. break;
  380. }
  381. case VT_BSTR:
  382. {
  383. s << TEXT("VT_BSTR=\"") << var.bstrVal << TEXT("\"");
  384. break;
  385. }
  386. case VT_UNKNOWN:
  387. {
  388. s << TEXT("VT_UNKNOWN=0x") << WriteHex( var.punkVal, 8 );
  389. break;
  390. }
  391. case VT_DISPATCH:
  392. {
  393. s << TEXT("VT_DISPATCH=0x") << WriteHex( var.pdispVal, 8 );
  394. break;
  395. }
  396. default:
  397. {
  398. s << TEXT("VT_? ") << (long)var.vt;
  399. break;
  400. }
  401. }
  402. s << TEXT("]");
  403. return s;
  404. }
  405. inline
  406. TSTR & operator << ( TSTR & s, const POINT & pt )
  407. {
  408. s << TEXT("{x:") << pt.x
  409. << TEXT(" y:") << pt.y
  410. << TEXT("}");
  411. return s;
  412. }
  413. inline
  414. TSTR & operator << ( TSTR & s, const RECT & rc )
  415. {
  416. s << TEXT("{l:") << rc.left
  417. << TEXT(" t:") << rc.top
  418. << TEXT(" r:") << rc.right
  419. << TEXT(" b:") << rc.bottom
  420. << TEXT("}");
  421. return s;
  422. }
  423. #endif // _TSTR_H_