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.

548 lines
15 KiB

  1. /***
  2. *DbgRpt.c - Debug Cluster Reporting Functions
  3. *
  4. * Copyright (c) 1988-1998, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *
  8. *******************************************************************************/
  9. #include <malloc.h>
  10. #include <mbstring.h>
  11. #include <stdarg.h>
  12. #include <stdlib.h>
  13. #include <stdio.h>
  14. #include <signal.h>
  15. #include <string.h>
  16. #include <windows.h>
  17. #define CLRTL_INCLUDE_DEBUG_REPORTING
  18. #include "ClRtlDbg.h"
  19. #include <strsafe.h>
  20. #define _ClRtlInterlockedIncrement InterlockedIncrement
  21. #define _ClRtlInterlockedDecrement InterlockedDecrement
  22. /*---------------------------------------------------------------------------
  23. *
  24. * Debug Reporting
  25. *
  26. --------------------------------------------------------------------------*/
  27. static int ClRtlMessageWindow(
  28. int,
  29. const char *,
  30. const char *,
  31. const char *,
  32. const char *
  33. );
  34. static int __clrtlMessageBoxA(
  35. LPCSTR lpText,
  36. LPCSTR lpCaption,
  37. UINT uType
  38. );
  39. extern "C"
  40. {
  41. _CLRTL_REPORT_HOOK _pfnReportHook;
  42. long _clrtlAssertBusy = -1;
  43. int _ClRtlDbgMode[_CLRTLDBG_ERRCNT] = {
  44. _CLRTLDBG_MODE_DEBUG,
  45. _CLRTLDBG_MODE_DEBUG | _CLRTLDBG_MODE_WNDW,
  46. _CLRTLDBG_MODE_DEBUG | _CLRTLDBG_MODE_WNDW
  47. };
  48. _HFILE _ClRtlDbgFile[_CLRTLDBG_ERRCNT] = {
  49. _CLRTLDBG_INVALID_HFILE,
  50. _CLRTLDBG_INVALID_HFILE,
  51. _CLRTLDBG_INVALID_HFILE
  52. };
  53. }
  54. static const char * _ClRtlDbgModeMsg[_CLRTLDBG_ERRCNT] = { "Warning", "Error", "Assertion Failed" };
  55. /***
  56. *void _ClRtlDebugBreak - call OS-specific debug function
  57. *
  58. *Purpose:
  59. * call OS-specific debug function
  60. *
  61. *Entry:
  62. *
  63. *Exit:
  64. *
  65. *Exceptions:
  66. *
  67. *******************************************************************************/
  68. #undef _ClRtlDbgBreak
  69. extern "C" void _cdecl _ClRtlDbgBreak(
  70. void
  71. )
  72. {
  73. DebugBreak();
  74. } //*** _ClRtlDbgBreak()
  75. /***
  76. *int _ClRtlSetReportMode - set the reporting mode for a given report type
  77. *
  78. *Purpose:
  79. * set the reporting mode for a given report type
  80. *
  81. *Entry:
  82. * int nRptType - the report type
  83. * int fMode - new mode for given report type
  84. *
  85. *Exit:
  86. * previous mode for given report type
  87. *
  88. *Exceptions:
  89. *
  90. *******************************************************************************/
  91. extern "C" int __cdecl _ClRtlSetReportMode(
  92. int nRptType,
  93. int fMode
  94. )
  95. {
  96. int oldMode;
  97. if (nRptType < 0 || nRptType >= _CLRTLDBG_ERRCNT)
  98. return -1;
  99. if (fMode == _CLRTLDBG_REPORT_MODE)
  100. return _ClRtlDbgMode[nRptType];
  101. /* verify flags values */
  102. if (fMode & ~(_CLRTLDBG_MODE_FILE | _CLRTLDBG_MODE_DEBUG | _CLRTLDBG_MODE_WNDW))
  103. return -1;
  104. oldMode = _ClRtlDbgMode[nRptType];
  105. _ClRtlDbgMode[nRptType] = fMode;
  106. return oldMode;
  107. } //*** _ClRtlSetReportMode()
  108. /***
  109. *int _ClRtlSetReportFile - set the reporting file for a given report type
  110. *
  111. *Purpose:
  112. * set the reporting file for a given report type
  113. *
  114. *Entry:
  115. * int nRptType - the report type
  116. * _HFILE hFile - new file for given report type
  117. *
  118. *Exit:
  119. * previous file for given report type
  120. *
  121. *Exceptions:
  122. *
  123. *******************************************************************************/
  124. extern "C" _HFILE __cdecl _ClRtlSetReportFile(
  125. int nRptType,
  126. _HFILE hFile
  127. )
  128. {
  129. _HFILE oldFile;
  130. if (nRptType < 0 || nRptType >= _CLRTLDBG_ERRCNT)
  131. return _CLRTLDBG_HFILE_ERROR;
  132. if (hFile == _CLRTLDBG_REPORT_FILE)
  133. return _ClRtlDbgFile[nRptType];
  134. oldFile = _ClRtlDbgFile[nRptType];
  135. if (_CLRTLDBG_FILE_STDOUT == hFile)
  136. _ClRtlDbgFile[nRptType] = GetStdHandle(STD_OUTPUT_HANDLE);
  137. else if (_CLRTLDBG_FILE_STDERR == hFile)
  138. _ClRtlDbgFile[nRptType] = GetStdHandle(STD_ERROR_HANDLE);
  139. else
  140. _ClRtlDbgFile[nRptType] = hFile;
  141. return oldFile;
  142. } //*** _ClRtlSetReportFile()
  143. /***
  144. *_CLRTL_REPORT_HOOK _ClRtlSetReportHook() - set client report hook
  145. *
  146. *Purpose:
  147. * set client report hook
  148. *
  149. *Entry:
  150. * _CLRTL_REPORT_HOOK pfnNewHook - new report hook
  151. *
  152. *Exit:
  153. * return previous hook
  154. *
  155. *Exceptions:
  156. *
  157. *******************************************************************************/
  158. extern "C" _CLRTL_REPORT_HOOK __cdecl _ClRtlSetReportHook(
  159. _CLRTL_REPORT_HOOK pfnNewHook
  160. )
  161. {
  162. _CLRTL_REPORT_HOOK pfnOldHook = _pfnReportHook;
  163. _pfnReportHook = pfnNewHook;
  164. return pfnOldHook;
  165. } //*** _ClRtlSetReportHook()
  166. #define MAXLINELEN 64
  167. #define MAX_MSG 512
  168. #define TOOLONGMSG "_ClRtlDbgReport: String too long or IO Error"
  169. /***
  170. *int _ClRtlDbgReport() - primary reporting function
  171. *
  172. *Purpose:
  173. * Display a message window with the following format.
  174. *
  175. * ================= Microsft Visual C++ Debug Library ================
  176. *
  177. * {Warning! | Error! | Assertion Failed!}
  178. *
  179. * Program: c:\test\mytest\foo.exe
  180. * [Module: c:\test\mytest\bar.dll]
  181. * [File: c:\test\mytest\bar.c]
  182. * [Line: 69]
  183. *
  184. * {<warning or error message> | Expression: <expression>}
  185. *
  186. * [For information on how your program can cause an assertion
  187. * failure, see the Visual C++ documentation on asserts]
  188. *
  189. * (Press Retry to debug the application)
  190. *
  191. * ===================================================================
  192. *
  193. *Entry:
  194. * int nRptType - report type
  195. * const char * szFile - file name
  196. * int nLine - line number
  197. * const char * szModule - module name
  198. * const char * szFormat - format string
  199. * ... - var args
  200. *
  201. *Exit:
  202. * if (MessageBox)
  203. * {
  204. * Abort -> aborts
  205. * Retry -> return TRUE
  206. * Ignore-> return FALSE
  207. * }
  208. * else
  209. * return FALSE
  210. *
  211. *Exceptions:
  212. *
  213. *******************************************************************************/
  214. extern "C" int __cdecl _ClRtlDbgReport(
  215. int nRptType,
  216. const char * szFile,
  217. int nLine,
  218. const char * szModule,
  219. const char * szFormat,
  220. ...
  221. )
  222. {
  223. int retval;
  224. va_list arglist;
  225. char szLineMessage[MAX_MSG] = {0};
  226. char szOutMessage[MAX_MSG] = {0};
  227. char szUserMessage[MAX_MSG] = {0};
  228. #define ASSERTINTRO1 "Assertion failed: "
  229. #define ASSERTINTRO2 "Assertion failed!"
  230. va_start(arglist, szFormat);
  231. if (nRptType < 0 || nRptType >= _CLRTLDBG_ERRCNT)
  232. return -1;
  233. /*
  234. * handle the (hopefully rare) case of
  235. *
  236. * 1) ASSERT while already dealing with an ASSERT
  237. * or
  238. * 2) two threads asserting at the same time
  239. */
  240. if (_CLRTLDBG_ASSERT == nRptType && _ClRtlInterlockedIncrement(&_clrtlAssertBusy) > 0)
  241. {
  242. /* use only 'safe' functions -- must not assert in here! */
  243. static int (APIENTRY *pfnwsprintfA)(LPSTR, LPCSTR, ...) = NULL;
  244. if (NULL == pfnwsprintfA)
  245. {
  246. HINSTANCE hlib = LoadLibraryA("user32.dll");
  247. if (NULL == hlib || NULL == (pfnwsprintfA =
  248. (int (APIENTRY *)(LPSTR, LPCSTR, ...))
  249. GetProcAddress(hlib, "wsprintfA")))
  250. return -1;
  251. }
  252. (*pfnwsprintfA)( szOutMessage,
  253. "Second Chance Assertion Failed: File %s, Line %d\n",
  254. szFile, nLine);
  255. OutputDebugStringA(szOutMessage);
  256. _ClRtlInterlockedDecrement(&_clrtlAssertBusy);
  257. _ClRtlDbgBreak();
  258. return -1;
  259. }
  260. szUserMessage[ MAX_MSG - 1 ] = 0;
  261. if (szFormat && StringCbVPrintfA( szUserMessage,
  262. MAX_MSG-max(sizeof(ASSERTINTRO1),sizeof(ASSERTINTRO2))-1,
  263. szFormat,
  264. arglist) != S_OK ) {
  265. PCHAR dot;
  266. dot = szUserMessage + MAX_MSG - 4;
  267. StringCbCopyA( dot, 4, "..." );
  268. }
  269. if (_CLRTLDBG_ASSERT == nRptType) {
  270. if ( szFormat == 0 ) {
  271. StringCbCopyA( szLineMessage, MAX_MSG, ASSERTINTRO1 );
  272. }
  273. else {
  274. StringCbCopyA( szLineMessage, MAX_MSG, ASSERTINTRO2 );
  275. }
  276. }
  277. StringCbCatA( szLineMessage, MAX_MSG, szUserMessage );
  278. if (_CLRTLDBG_ASSERT == nRptType)
  279. {
  280. if (_ClRtlDbgMode[nRptType] & _CLRTLDBG_MODE_FILE) {
  281. StringCbCatA( szLineMessage, MAX_MSG, "\r" );
  282. }
  283. StringCbCatA( szLineMessage, MAX_MSG, "\n" );
  284. }
  285. if (szFile)
  286. {
  287. if ( StringCbPrintfA(szOutMessage, MAX_MSG, "%s(%d) : %s",
  288. szFile, nLine, szLineMessage) != S_OK )
  289. StringCbCopyA( szOutMessage, MAX_MSG, TOOLONGMSG );
  290. }
  291. else {
  292. StringCbCopyA( szOutMessage, MAX_MSG, szLineMessage );
  293. }
  294. /* user hook may handle report */
  295. if (_pfnReportHook && (*_pfnReportHook)(nRptType, szOutMessage, &retval))
  296. {
  297. if (_CLRTLDBG_ASSERT == nRptType)
  298. _ClRtlInterlockedDecrement(&_clrtlAssertBusy);
  299. return retval;
  300. }
  301. if (_ClRtlDbgMode[nRptType] & _CLRTLDBG_MODE_FILE)
  302. {
  303. if (_ClRtlDbgFile[nRptType] != _CLRTLDBG_INVALID_HFILE)
  304. {
  305. DWORD written;
  306. WriteFile(_ClRtlDbgFile[nRptType], szOutMessage, strlen(szOutMessage), &written, NULL);
  307. }
  308. }
  309. if (_ClRtlDbgMode[nRptType] & _CLRTLDBG_MODE_DEBUG)
  310. {
  311. OutputDebugStringA(szOutMessage);
  312. }
  313. if (_ClRtlDbgMode[nRptType] & _CLRTLDBG_MODE_WNDW)
  314. {
  315. char szLine[20];
  316. retval = ClRtlMessageWindow(nRptType, szFile, nLine ? _itoa(nLine, szLine, 10) : NULL, szModule, szUserMessage);
  317. if (_CLRTLDBG_ASSERT == nRptType)
  318. _ClRtlInterlockedDecrement(&_clrtlAssertBusy);
  319. return retval;
  320. }
  321. if (_CLRTLDBG_ASSERT == nRptType)
  322. _ClRtlInterlockedDecrement(&_clrtlAssertBusy);
  323. /* ignore */
  324. return FALSE;
  325. } //*** _ClRtlDbgReport()
  326. /***
  327. *static int ClRtlMessageWindow() - report to a message window
  328. *
  329. *Purpose:
  330. * put report into message window, allow user to choose action to take
  331. *
  332. *Entry:
  333. * int nRptType - report type
  334. * const char * szFile - file name
  335. * const char * szLine - line number
  336. * const char * szModule - module name
  337. * const char * szUserMessage - user message
  338. *
  339. *Exit:
  340. * if (MessageBox)
  341. * {
  342. * Abort -> aborts
  343. * Retry -> return TRUE
  344. * Ignore-> return FALSE
  345. * }
  346. * else
  347. * return FALSE
  348. *
  349. *Exceptions:
  350. *
  351. *******************************************************************************/
  352. static int ClRtlMessageWindow(
  353. int nRptType,
  354. const char * szFile,
  355. const char * szLine,
  356. const char * szModule,
  357. const char * szUserMessage
  358. )
  359. {
  360. int nCode;
  361. char *szShortProgName;
  362. char *szShortModuleName;
  363. char szExeName[MAX_PATH];
  364. char szOutMessage[MAX_MSG];
  365. _CLRTL_ASSERTE(szUserMessage != NULL);
  366. /* Shorten program name */
  367. if (!GetModuleFileNameA(NULL, szExeName, MAX_PATH))
  368. StringCbCopyA(szExeName, MAX_PATH, "<program name unknown>");
  369. szShortProgName = szExeName;
  370. if (strlen(szShortProgName) > MAXLINELEN)
  371. {
  372. szShortProgName += MAXLINELEN - 4;
  373. StringCbCopyA( szShortProgName, 4, "..." );
  374. }
  375. /* Shorten module name */
  376. szShortModuleName = (char *) szModule;
  377. if (szShortModuleName && strlen(szShortModuleName) > MAXLINELEN)
  378. {
  379. szShortModuleName += MAXLINELEN - 4;
  380. StringCbCopyA( szShortModuleName, 4, "..." );
  381. }
  382. if ( StringCbPrintfA( szOutMessage, MAX_MSG,
  383. "Debug %s!\n\nProgram: %s%s%s%s%s%s%s%s%s%s%s"
  384. "\n\n(Press Retry to debug the application)",
  385. _ClRtlDbgModeMsg[nRptType],
  386. szShortProgName,
  387. szShortModuleName ? "\nModule: " : "",
  388. szShortModuleName ? szShortModuleName : "",
  389. szFile ? "\nFile: " : "",
  390. szFile ? szFile : "",
  391. szLine ? "\nLine: " : "",
  392. szLine ? szLine : "",
  393. szUserMessage[0] ? "\n\n" : "",
  394. szUserMessage[0] && _CLRTLDBG_ASSERT == nRptType ? "Expression: " : "",
  395. szUserMessage[0] ? szUserMessage : "",
  396. 0 /*_CLRTLDBG_ASSERT == nRptType*/ ? // Don't display this text, it's superfluous
  397. "\n\nFor information on how your program can cause an assertion"
  398. "\nfailure, see the Visual C++ documentation on asserts."
  399. : "") != S_OK )
  400. StringCbCopyA( szOutMessage, MAX_MSG, TOOLONGMSG );
  401. /* Report the warning/error */
  402. nCode = __clrtlMessageBoxA(
  403. szOutMessage,
  404. "Microsoft Visual C++ Debug Library",
  405. MB_TASKMODAL|MB_ICONHAND|MB_ABORTRETRYIGNORE|MB_SETFOREGROUND);
  406. /* Abort: abort the program */
  407. if (IDABORT == nCode)
  408. {
  409. /* raise abort signal */
  410. raise(SIGABRT);
  411. /* We usually won't get here, but it's possible that
  412. SIGABRT was ignored. So exit the program anyway. */
  413. _exit(3);
  414. }
  415. /* Retry: return 1 to call the debugger */
  416. if (IDRETRY == nCode)
  417. return 1;
  418. /* Ignore: continue execution */
  419. return 0;
  420. } //*** ClRtlMessageWindow()
  421. /***
  422. *__clrtlMessageBoxA - call MessageBoxA dynamically.
  423. *
  424. *Purpose:
  425. * Avoid static link with user32.dll. Only load it when actually needed.
  426. *
  427. *Entry:
  428. * see MessageBoxA docs.
  429. *
  430. *Exit:
  431. * see MessageBoxA docs.
  432. *
  433. *Exceptions:
  434. *
  435. *******************************************************************************/
  436. static int __clrtlMessageBoxA(
  437. LPCSTR lpText,
  438. LPCSTR lpCaption,
  439. UINT uType
  440. )
  441. {
  442. static int (APIENTRY *pfnMessageBoxA)(HWND, LPCSTR, LPCSTR, UINT) = NULL;
  443. static HWND (APIENTRY *pfnGetActiveWindow)(void) = NULL;
  444. static HWND (APIENTRY *pfnGetLastActivePopup)(HWND) = NULL;
  445. HWND hWndParent = NULL;
  446. if (NULL == pfnMessageBoxA)
  447. {
  448. HINSTANCE hlib = LoadLibraryA("user32.dll");
  449. if (NULL == hlib || NULL == (pfnMessageBoxA =
  450. (int (APIENTRY *)(HWND, LPCSTR, LPCSTR, UINT))
  451. GetProcAddress(hlib, "MessageBoxA")))
  452. return 0;
  453. pfnGetActiveWindow = (HWND (APIENTRY *)(void))
  454. GetProcAddress(hlib, "GetActiveWindow");
  455. pfnGetLastActivePopup = (HWND (APIENTRY *)(HWND))
  456. GetProcAddress(hlib, "GetLastActivePopup");
  457. }
  458. if (pfnGetActiveWindow)
  459. hWndParent = (*pfnGetActiveWindow)();
  460. if (hWndParent != NULL && pfnGetLastActivePopup)
  461. hWndParent = (*pfnGetLastActivePopup)(hWndParent);
  462. return (*pfnMessageBoxA)(hWndParent, lpText, lpCaption, uType);
  463. } //*** __clrtlMessageBoxA()