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.

363 lines
11 KiB

  1. //+---------------------------------------------------------------------------
  2. // Copyright (C) 1991-1994, Microsoft Corporation.
  3. //
  4. // File: assert.cxx
  5. //
  6. // Contents: Debugging output routines
  7. //
  8. // History: 23-Jul-91 KyleP Created.
  9. // 09-Oct-91 KevinRo Major changes and comments added
  10. // 18-Oct-91 vich moved debug print routines out
  11. // 10-Jun-92 BryanT Switched to w4crt.h instead of wchar.h
  12. // 30-Sep-93 KyleP DEVL obsolete
  13. // 7-Oct-94 BruceFo Ripped out all kernel, non-FLAT,
  14. // DLL-specific, non-Win32 functionality.
  15. // Now it's basically "print to the
  16. // debugger" code.
  17. // 30-Dec-95 BruceFo More cleanup, make suitable for DFS
  18. // project. Get rid of Win4 naming.
  19. //
  20. //----------------------------------------------------------------------------
  21. #if DBG == 1
  22. #include <windows.h>
  23. #include <stdio.h>
  24. #include <stdarg.h>
  25. #include "debug.h"
  26. //////////////////////////////////////////////////////////////////////////////
  27. // global variables. These could be local, but we want debuggers to be able
  28. // to get at them. Use extern "C" to make them easier to find.
  29. extern "C"
  30. {
  31. unsigned long DebugInfoLevel = DEF_INFOLEVEL;
  32. unsigned long DebugInfoMask = 0xffffffff;
  33. unsigned long DebugAssertLevel = ASSRT_MESSAGE | ASSRT_BREAK | ASSRT_POPUP;
  34. }
  35. //////////////////////////////////////////////////////////////////////////////
  36. // local variables
  37. static BOOL s_fCritSecInit = FALSE;
  38. static BOOL s_fInfoLevelInit = FALSE;
  39. static CRITICAL_SECTION s_csDebugPrint;
  40. static CRITICAL_SECTION s_csMessageBuf;
  41. static char g_szMessageBuf[2000]; // this is the message buffer
  42. //////////////////////////////////////////////////////////////////////////////
  43. // local functions
  44. static int DebugInternalvprintf(const char *format, va_list arglist);
  45. static int DebugInternalprintf(const char *format, ...);
  46. static void DebugAssertInternalprintf(char const *pszfmt, ...);
  47. static int PopUpError(char const* pszMsg, int iLine, char const* pszFile);
  48. //////////////////////////////////////////////////////////////////////////////
  49. static int DebugInternalvprintf(const char* format, va_list arglist)
  50. {
  51. int ret;
  52. EnterCriticalSection(&s_csMessageBuf);
  53. ret = vsprintf(g_szMessageBuf, format, arglist);
  54. OutputDebugStringA(g_szMessageBuf);
  55. LeaveCriticalSection(&s_csMessageBuf);
  56. return ret;
  57. }
  58. static int DebugInternalprintf(const char* format, ...)
  59. {
  60. int ret;
  61. va_list va;
  62. va_start(va, format);
  63. ret = DebugInternalvprintf(format, va);
  64. va_end(va);
  65. return ret;
  66. }
  67. static void DebugAssertInternalprintf(char const *pszfmt, ...)
  68. {
  69. va_list va;
  70. va_start(va, pszfmt);
  71. Debugvprintf(DEB_FORCE, "Assert", pszfmt, va);
  72. va_end(va);
  73. }
  74. //+---------------------------------------------------------------------------
  75. //
  76. // Function: DebugAssertEx, private
  77. //
  78. // Synopsis: Display assertion information
  79. //
  80. // Effects: Called when an assertion is hit.
  81. //
  82. //----------------------------------------------------------------------------
  83. void DEBUGAPI
  84. DebugAssertEx(
  85. char const * szFile,
  86. int iLine,
  87. char const * szMessage)
  88. {
  89. if (DebugAssertLevel & ASSRT_MESSAGE)
  90. {
  91. DWORD tid = GetCurrentThreadId();
  92. DebugAssertInternalprintf("%s File: %s Line: %u, thread id %d\n",
  93. szMessage, szFile, iLine, tid);
  94. }
  95. if (DebugAssertLevel & ASSRT_POPUP)
  96. {
  97. int id = PopUpError(szMessage,iLine,szFile);
  98. if (id == IDCANCEL)
  99. {
  100. DebugBreak();
  101. }
  102. }
  103. else if (DebugAssertLevel & ASSRT_BREAK)
  104. {
  105. DebugBreak();
  106. }
  107. }
  108. //+------------------------------------------------------------
  109. // Function: DebugSetInfoLevel
  110. // Synopsis: Sets the global info level for debugging output
  111. // Returns: Old info level
  112. //-------------------------------------------------------------
  113. unsigned long DEBUGAPI
  114. DebugSetInfoLevel(
  115. unsigned long ulNewLevel)
  116. {
  117. unsigned long ul = DebugInfoLevel;
  118. DebugInfoLevel = ulNewLevel;
  119. return ul;
  120. }
  121. //+------------------------------------------------------------
  122. // Function: DebugSetInfoMask
  123. // Synopsis: Sets the global info mask for debugging output
  124. // Returns: Old info mask
  125. //-------------------------------------------------------------
  126. unsigned long DEBUGAPI
  127. DebugSetInfoMask(
  128. unsigned long ulNewMask)
  129. {
  130. unsigned long ul = DebugInfoMask;
  131. DebugInfoMask = ulNewMask;
  132. return ul;
  133. }
  134. //+------------------------------------------------------------
  135. // Function: DebugSetAssertLevel
  136. // Synopsis: Sets the global assert level for debugging output
  137. // Returns: Old assert level
  138. //-------------------------------------------------------------
  139. unsigned long DEBUGAPI
  140. DebugSetAssertLevel(
  141. unsigned long ulNewLevel)
  142. {
  143. unsigned long ul = DebugAssertLevel;
  144. DebugAssertLevel = ulNewLevel;
  145. return ul;
  146. }
  147. //+------------------------------------------------------------
  148. // Function: PopUpError
  149. //
  150. // Synopsis: Displays a dialog box using provided text,
  151. // and presents the user with the option to
  152. // continue or cancel.
  153. //
  154. // Arguments:
  155. // szMsg -- The string to display in main body of dialog
  156. // iLine -- Line number of file in error
  157. // szFile -- Filename of file in error
  158. //
  159. // Returns:
  160. // IDCANCEL -- User selected the CANCEL button
  161. // IDOK -- User selected the OK button
  162. //-------------------------------------------------------------
  163. static int PopUpError(char const* szMsg, int iLine, char const* szFile)
  164. {
  165. int id;
  166. static char szAssertCaption[128];
  167. static char szModuleName[128];
  168. DWORD tid = GetCurrentThreadId();
  169. DWORD pid = GetCurrentProcessId();
  170. char* pszModuleName;
  171. if (GetModuleFileNameA(NULL, szModuleName, 128))
  172. {
  173. pszModuleName = strrchr(szModuleName, '\\');
  174. if (!pszModuleName)
  175. {
  176. pszModuleName = szModuleName;
  177. }
  178. else
  179. {
  180. pszModuleName++;
  181. }
  182. }
  183. else
  184. {
  185. pszModuleName = "Unknown";
  186. }
  187. sprintf(szAssertCaption,"Process: %s File: %s line %u, thread id %d.%d",
  188. pszModuleName, szFile, iLine, pid, tid);
  189. id = MessageBoxA(NULL,
  190. szMsg,
  191. szAssertCaption,
  192. MB_SETFOREGROUND
  193. | MB_DEFAULT_DESKTOP_ONLY
  194. | MB_TASKMODAL
  195. | MB_ICONEXCLAMATION
  196. | MB_OKCANCEL);
  197. //
  198. // If id == 0, then an error occurred. There are two possibilities
  199. // that can cause the error: Access Denied, which means that this
  200. // process does not have access to the default desktop, and everything
  201. // else (usually out of memory).
  202. //
  203. if (0 == id)
  204. {
  205. if (GetLastError() == ERROR_ACCESS_DENIED)
  206. {
  207. //
  208. // Retry this one with the SERVICE_NOTIFICATION flag on. That
  209. // should get us to the right desktop.
  210. //
  211. id = MessageBoxA(NULL,
  212. szMsg,
  213. szAssertCaption,
  214. MB_SETFOREGROUND
  215. | MB_SERVICE_NOTIFICATION
  216. | MB_TASKMODAL
  217. | MB_ICONEXCLAMATION
  218. | MB_OKCANCEL);
  219. }
  220. }
  221. return id;
  222. }
  223. //+------------------------------------------------------------
  224. // Function: Debugvprintf
  225. //
  226. // Synopsis: Prints debug output using a pointer to the
  227. // variable information. Used primarily by the
  228. // xxDebugOut macros
  229. //
  230. // Arguements:
  231. // ulCompMask -- Component level mask used to determine
  232. // output ability
  233. // pszComp -- String const of component prefix.
  234. // ppszfmt -- Pointer to output format and data
  235. //
  236. //-------------------------------------------------------------
  237. void DEBUGAPI
  238. Debugvprintf(
  239. unsigned long ulCompMask,
  240. char const * pszComp,
  241. char const * ppszfmt,
  242. va_list pargs)
  243. {
  244. if ((ulCompMask & DEB_FORCE) == DEB_FORCE ||
  245. ((ulCompMask | DebugInfoLevel) & DebugInfoMask))
  246. {
  247. EnterCriticalSection(&s_csDebugPrint);
  248. DWORD tid = GetCurrentThreadId();
  249. DWORD pid = GetCurrentProcessId();
  250. if ((DebugInfoLevel & (DEB_DBGOUT | DEB_STDOUT)) != DEB_STDOUT)
  251. {
  252. if (! (ulCompMask & DEB_NOCOMPNAME))
  253. {
  254. DebugInternalprintf("%d.%03d> %s: ", pid, tid, pszComp);
  255. }
  256. DebugInternalvprintf(ppszfmt, pargs);
  257. }
  258. if (DebugInfoLevel & DEB_STDOUT)
  259. {
  260. if (! (ulCompMask & DEB_NOCOMPNAME))
  261. {
  262. printf("%d.%03d> %s: ", pid, tid, pszComp);
  263. }
  264. vprintf(ppszfmt, pargs);
  265. }
  266. LeaveCriticalSection(&s_csDebugPrint);
  267. }
  268. }
  269. //+----------------------------------------------------------------------------
  270. //
  271. // Debuggging library inititalization.
  272. //
  273. // To set a non-default debug info level outside of the debugger, create the
  274. // below registry key and in it create a value whose name is the component's
  275. // debugging tag name (the "comp" parameter to the DECLARE_INFOLEVEL macro) and
  276. // whose data is the desired infolevel in REG_DWORD format.
  277. //-----------------------------------------------------------------------------
  278. #define DEBUGKEY "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Debug"
  279. //+----------------------------------------------------------------------------
  280. // Function: DebugCheckInit
  281. //
  282. // Synopsis: Performs debugging library initialization
  283. // including reading the registry for the desired infolevel
  284. //
  285. //-----------------------------------------------------------------------------
  286. void DEBUGAPI
  287. DebugCheckInit(char * pInfoLevelString, unsigned long * pulInfoLevel)
  288. {
  289. if (s_fInfoLevelInit) return;
  290. if (!s_fCritSecInit) DebugInitialize();
  291. HKEY hKey;
  292. LONG lRet = RegOpenKeyExA(HKEY_LOCAL_MACHINE, DEBUGKEY, 0, KEY_READ, &hKey);
  293. if (lRet == ERROR_SUCCESS)
  294. {
  295. DWORD dwSize = sizeof(unsigned long);
  296. lRet = RegQueryValueExA(hKey, pInfoLevelString, NULL, NULL,
  297. (LPBYTE)pulInfoLevel, &dwSize);
  298. if (lRet != ERROR_SUCCESS)
  299. {
  300. *pulInfoLevel = DEF_INFOLEVEL;
  301. }
  302. RegCloseKey(hKey);
  303. }
  304. s_fInfoLevelInit = TRUE;
  305. }
  306. //+----------------------------------------------------------------------------
  307. // Function: DebugInitialize
  308. //
  309. // Synopsis: Performs debugging library initialization
  310. //
  311. //-----------------------------------------------------------------------------
  312. void DebugInitialize(void)
  313. {
  314. if (s_fCritSecInit) return;
  315. InitializeCriticalSection(&s_csMessageBuf);
  316. InitializeCriticalSection(&s_csDebugPrint);
  317. s_fCritSecInit = TRUE;
  318. }
  319. #endif // DBG == 1