XTrace.h 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. // XTrace.h Version 1.1
  2. //
  3. // Author: Paul Mclachlan
  4. //
  5. // Modified by: Hans Dietrich
  6. // hdietrich2@hotmail.com
  7. //
  8. // Version 1.1: added Unicode support
  9. // added optional thread id to output string
  10. // added option to enable/disable full path
  11. // added TRACERECT macro
  12. // changed name to avoid conflicts with Paul's class.
  13. //
  14. // This code was taken from article by Paul Mclachlan, "Getting around
  15. // the need for a vararg #define just to automatically use __FILE__ and
  16. // __LINE__ in a TRACE macro". For original article, see
  17. // http://www.codeproject.com/useritems/location_trace.asp
  18. //
  19. // XTrace.h is a drop-in replacement for MFC's TRACE facility. It has no
  20. // dependency on MFC. It is thread-safe and uses no globals or statics.
  21. //
  22. // It optionally adds source module/line number and thread id to each line
  23. // of TRACE output. To control these features, use the following defines:
  24. //
  25. // XTRACE_SHOW_FULLPATH
  26. // XTRACE_SHOW_THREAD_ID
  27. //
  28. // XTrace.h also provides the TRACERECT macro, which outputs the contents
  29. // of a RECT struct. In Release builds, no output will be produced.
  30. //
  31. ///////////////////////////////////////////////////////////////////////////////
  32. #ifndef XTRACE_H
  33. #define XTRACE_H
  34. #include <stdarg.h>
  35. #include <stdio.h>
  36. #include <windows.h>
  37. #include <tchar.h>
  38. #pragma warning(push)
  39. #pragma warning(disable : 4127) // conditional expression is constant
  40. #ifndef INVALID_SET_FILE_POINTER
  41. #define INVALID_SET_FILE_POINTER ((DWORD)-1)
  42. #endif
  43. #define XTRACE_SHOW_FULLPATH FALSE // FALSE = only show base name of file
  44. #define XTRACE_SHOW_THREAD_ID TRUE // TRUE = include thread id in output
  45. #define XTRACE_FILE FALSE // TRUE = output to file
  46. class xtracing_output_debug_string
  47. {
  48. public:
  49. xtracing_output_debug_string(LPCTSTR lpszFile, int line) :
  50. m_file(lpszFile),
  51. m_line(line)
  52. {
  53. }
  54. void operator() (LPCTSTR lpszFormat, ...)
  55. {
  56. va_list va;
  57. va_start(va, lpszFormat);
  58. TCHAR buf1[BUFFER_SIZE];
  59. TCHAR buf2[BUFFER_SIZE];
  60. // add the __FILE__ and __LINE__ to the front
  61. LPCTSTR cp = (LPCTSTR) m_file;
  62. if (!XTRACE_SHOW_FULLPATH)
  63. {
  64. cp = _tcsrchr(m_file, _T('\\'));
  65. if (cp)
  66. cp++;
  67. }
  68. if (XTRACE_SHOW_THREAD_ID)
  69. {
  70. if (_sntprintf(buf1, BUFFER_SIZE-1, _T("%s(%d) : [%X] %s"),
  71. cp, m_line, GetCurrentThreadId(), lpszFormat) < 0)
  72. buf1[BUFFER_SIZE-1] = _T('\0');
  73. }
  74. else
  75. {
  76. if (_sntprintf(buf1, BUFFER_SIZE-1, _T("%s(%d) : %s"),
  77. cp, m_line, lpszFormat) < 0)
  78. buf1[BUFFER_SIZE-1] = _T('\0');
  79. }
  80. // format the message as requested
  81. if (_vsntprintf(buf2, BUFFER_SIZE-1, buf1, va) < 0)
  82. buf2[BUFFER_SIZE-1] = _T('\0');
  83. va_end(va);
  84. if (XTRACE_FILE)
  85. {
  86. TCHAR szPathName[MAX_PATH*2] = { 0 };
  87. ::GetModuleFileName(NULL, szPathName, sizeof(szPathName)/sizeof(TCHAR)-2);
  88. TCHAR *cp = _tcsrchr(szPathName, _T('\\'));
  89. if (cp != NULL)
  90. *(cp+1) = _T('\0');
  91. _tcscat(szPathName, _T("\\_trace.log"));
  92. HANDLE hFile = ::CreateFile(szPathName, GENERIC_WRITE, FILE_SHARE_WRITE,
  93. NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  94. if (hFile != INVALID_HANDLE_VALUE)
  95. {
  96. DWORD dwRC = ::SetFilePointer(hFile, // handle to file
  97. 0, // bytes to move pointer
  98. NULL, // bytes to move pointer
  99. FILE_END); // starting point
  100. if (dwRC != INVALID_SET_FILE_POINTER)
  101. {
  102. DWORD dwWritten = 0;
  103. ::WriteFile(hFile, // handle to file
  104. buf2, // data buffer
  105. _tcslen(buf2)*sizeof(TCHAR), // number of bytes to write
  106. &dwWritten, // number of bytes written
  107. NULL); // overlapped buffer
  108. }
  109. ::CloseHandle(hFile);
  110. }
  111. }
  112. else
  113. {
  114. // write it out
  115. OutputDebugString(buf2);
  116. }
  117. }
  118. private:
  119. LPCTSTR m_file;
  120. int m_line;
  121. enum { BUFFER_SIZE = 4096 };
  122. };
  123. class xtracing_entry_output_debug_string
  124. {
  125. public:
  126. xtracing_entry_output_debug_string(LPCTSTR lpszFile, int line) :
  127. m_file(lpszFile),
  128. m_line(line)
  129. {
  130. }
  131. ~xtracing_entry_output_debug_string()
  132. {
  133. TCHAR buf3[BUFFER_SIZE*3];
  134. _stprintf(buf3, _T("====== exiting scope: %s"), buf2);
  135. OutputDebugString(buf3);
  136. }
  137. void operator() (LPCTSTR lpszFormat, ...)
  138. {
  139. va_list va;
  140. va_start(va, lpszFormat);
  141. TCHAR buf1[BUFFER_SIZE];
  142. // add the __FILE__ and __LINE__ to the front
  143. LPCTSTR cp = (LPCTSTR) m_file;
  144. if (!XTRACE_SHOW_FULLPATH)
  145. {
  146. cp = _tcsrchr(m_file, _T('\\'));
  147. if (cp)
  148. cp++;
  149. }
  150. if (XTRACE_SHOW_THREAD_ID)
  151. {
  152. if (_sntprintf(buf1, BUFFER_SIZE-1, _T("%s(%d) : [%X] ====== %s"),
  153. cp, m_line, GetCurrentThreadId(), lpszFormat) < 0)
  154. buf1[BUFFER_SIZE-1] = _T('\0');
  155. }
  156. else
  157. {
  158. if (_sntprintf(buf1, BUFFER_SIZE-1, _T("%s(%d) : ====== %s"),
  159. cp, m_line, lpszFormat) < 0)
  160. buf1[BUFFER_SIZE-1] = _T('\0');
  161. }
  162. // format the message as requested
  163. if (_vsntprintf(buf2, BUFFER_SIZE-1, buf1, va) < 0)
  164. buf2[BUFFER_SIZE-1] = _T('\0');
  165. va_end(va);
  166. if (XTRACE_FILE)
  167. {
  168. TCHAR szPathName[MAX_PATH*2] = { 0 };
  169. ::GetModuleFileName(NULL, szPathName, sizeof(szPathName)/sizeof(TCHAR)-2);
  170. TCHAR *cp = _tcsrchr(szPathName, _T('\\'));
  171. if (cp != NULL)
  172. *(cp+1) = _T('\0');
  173. _tcscat(szPathName, _T("\\_trace.log"));
  174. HANDLE hFile = ::CreateFile(szPathName, GENERIC_WRITE, FILE_SHARE_WRITE,
  175. NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  176. if (hFile != INVALID_HANDLE_VALUE)
  177. {
  178. DWORD dwRC = ::SetFilePointer(hFile, // handle to file
  179. 0, // bytes to move pointer
  180. NULL, // bytes to move pointer
  181. FILE_END); // starting point
  182. if (dwRC != INVALID_SET_FILE_POINTER)
  183. {
  184. DWORD dwWritten = 0;
  185. ::WriteFile(hFile, // handle to file
  186. buf2, // data buffer
  187. _tcslen(buf2)*sizeof(TCHAR), // number of bytes to write
  188. &dwWritten, // number of bytes written
  189. NULL); // overlapped buffer
  190. }
  191. ::CloseHandle(hFile);
  192. }
  193. }
  194. else
  195. {
  196. // write it out
  197. OutputDebugString(buf2);
  198. }
  199. }
  200. private:
  201. LPCTSTR m_file;
  202. int m_line;
  203. enum { BUFFER_SIZE = 4096 };
  204. TCHAR buf2[BUFFER_SIZE*2];
  205. };
  206. #undef TRACE
  207. #undef TRACE0
  208. #undef TRACE1
  209. #undef TRACE2
  210. #define _DEBUGnow
  211. #ifdef _DEBUG
  212. #define TRACE (xtracing_output_debug_string(_T(__FILE__), __LINE__ ))
  213. #define TRACEENTRY (xtracing_output_debug_string(_T(__FILE__), __LINE__ ))
  214. #define TRACEERROR (xtracing_output_debug_string(_T(__FILE__), __LINE__ ))
  215. #define TRACE0 TRACE
  216. #define TRACE1 TRACE
  217. #define TRACE2 TRACE
  218. #else
  219. #ifndef __noop
  220. #if _MSC_VER < 1300
  221. #define __noop ((void)0)
  222. #endif
  223. #endif
  224. #define TRACE __noop
  225. #define TRACEERROR __noop
  226. #define TRACE0 __noop
  227. #define TRACE1 __noop
  228. #define TRACE2 __noop
  229. #endif
  230. #define TRACEHILO(d) \
  231. WORD ___hi = HIWORD(d); WORD ___lo = LOWORD(d); \
  232. TRACE(_T(#d) _T(": HIWORD = %u LOWORD = %u\n"), ___hi, ___lo)
  233. #define TRACESIZE(s) TRACE(_T(#s) _T(": cx = %d cy = %d\n"), \
  234. (s).cx, (s).cy)
  235. #define TRACEPOINT(p) TRACE(_T(#p) _T(": x = %d y = %d\n"), \
  236. (p).x, (p).y)
  237. #define TRACERECT(r) TRACE(_T(#r) _T(": left = %d top = %d right = %d bottom = %d\n"), \
  238. (r).left, (r).top, (r).right, (r).bottom)
  239. #pragma warning(pop)
  240. #endif //XTRACE_H