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.

557 lines
16 KiB

  1. //+---------------------------------------------------------------------------
  2. // Copyright (C) 1991-1994, Microsoft Corporation.
  3. //
  4. // File: assert.cpp
  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. // 7-Oct-94 BruceFo Ripped out all kernel, non-FLAT,
  13. // DLL-specific, non-Win32 functionality.
  14. // Now it's basically "print to the
  15. // debugger" code.
  16. // 20-Oct-95 EricB Set component debug level in the
  17. // registry.
  18. //
  19. //----------------------------------------------------------------------------
  20. #include <objbase.h>
  21. #include <basetyps.h>
  22. #include <tchar.h>
  23. #include <shlwapi.h> // wvnsprintf
  24. #if DBG==1
  25. #define new DEBUG_NEW
  26. #include "admindbg.h"
  27. #include "malloc.h" // alloca
  28. #include "stddbg.h" // VERIFY
  29. #include "macros.h" // ARRAYLEN
  30. #include "strsafe.h" // StringCchPrintf
  31. //
  32. // Globals
  33. //
  34. ULONG AdminAssertLevel = ASSRT_MESSAGE | ASSRT_BREAK | ASSRT_POPUP;
  35. //
  36. // Forward declaration of local functions
  37. //
  38. LPSTR AnsiPathFindFileName(LPSTR pPath);
  39. void smprintf(ULONG ulCompMask, LPTSTR pszComp, LPTSTR ppszfmt, va_list pargs);
  40. int w4dprintf(LPTSTR format, ...);
  41. int w4smprintf(LPTSTR format, va_list arglist);
  42. //+---------------------------------------------------------------------------
  43. //
  44. // Function: w4dprintf
  45. //
  46. // Synopsis: Calls w4smprintf to output a formatted message.
  47. //
  48. //----------------------------------------------------------------------------
  49. int w4dprintf(LPTSTR format, ...)
  50. {
  51. int ret;
  52. va_list va;
  53. va_start(va, format);
  54. ret = w4smprintf(format, va);
  55. va_end(va);
  56. return ret;
  57. }
  58. //+---------------------------------------------------------------------------
  59. //
  60. // Function: w4smprintf
  61. //
  62. // Synopsis: Calls OutputDebugStringA to output a formatted message.
  63. //
  64. //----------------------------------------------------------------------------
  65. int w4smprintf(LPTSTR format, va_list arglist)
  66. {
  67. TCHAR szMessageBuf[500]; // this is the message buffer
  68. int ret;
  69. ret = wvnsprintf(szMessageBuf, 500, format, arglist);
  70. OutputDebugString(szMessageBuf);
  71. return ret;
  72. }
  73. //+------------------------------------------------------------
  74. // Function: smprintf
  75. //
  76. // Synopsis: Prints debug output using a pointer to the
  77. // variable information. Used primarily by the
  78. // xxDebugOut macros
  79. //
  80. // Arguements:
  81. // ulCompMask -- Component level mask used to determine
  82. // output ability
  83. // pszComp -- String const of component prefix.
  84. // ppszfmt -- Pointer to output format and data
  85. //
  86. //-------------------------------------------------------------
  87. void smprintf(ULONG ulCompMask, LPTSTR pszComp, LPTSTR ppszfmt, va_list pargs)
  88. {
  89. if ((ulCompMask & DEB_FORCE) == DEB_FORCE ||
  90. (ulCompMask | (DEB_ERROR | DEB_WARN)))
  91. {
  92. DWORD tid = GetCurrentThreadId();
  93. DWORD pid = GetCurrentProcessId();
  94. if (((DEB_ERROR | DEB_WARN) & (DEB_DBGOUT | DEB_STDOUT)) != DEB_STDOUT)
  95. {
  96. if (! (ulCompMask & DEB_NOCOMPNAME))
  97. {
  98. w4dprintf(_T("%x.%03x> %s: "), pid, tid, pszComp);
  99. }
  100. w4smprintf(ppszfmt, pargs);
  101. }
  102. }
  103. }
  104. //+----------------------------------------------------------------------------
  105. //
  106. // Admin debuggging library inititalization.
  107. //
  108. // To set a non-default debug info level outside of the debugger, create the
  109. // below registry key and in it create a value whose name is the component's
  110. // debugging tag name (the "comp" parameter to the DECLARE_INFOLEVEL macro) and
  111. // whose data is the desired infolevel in REG_DWORD format.
  112. //-----------------------------------------------------------------------------
  113. #define CURRENT_VERSION_KEY _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion")
  114. #define ADMINDEBUGKEY _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\AdminDebug")
  115. #define ADMINDEBUG _T("AdminDebug")
  116. //+----------------------------------------------------------------------------
  117. // Function: CheckInit
  118. //
  119. // Synopsis: Performs debugging library initialization
  120. // including reading the registry for the desired infolevel
  121. //
  122. //-----------------------------------------------------------------------------
  123. void CheckInit(LPTSTR pInfoLevelString, ULONG * pulInfoLevel)
  124. {
  125. HKEY hKey;
  126. LONG lRet;
  127. DWORD dwSize;
  128. lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, ADMINDEBUGKEY, 0,
  129. KEY_ALL_ACCESS, &hKey);
  130. if (lRet == ERROR_FILE_NOT_FOUND)
  131. {
  132. HKEY hkCV;
  133. lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, CURRENT_VERSION_KEY, 0,
  134. KEY_ALL_ACCESS, &hkCV);
  135. if (lRet == ERROR_SUCCESS)
  136. {
  137. lRet = RegCreateKeyEx(hkCV, ADMINDEBUG, 0, _T(""),
  138. REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL);
  139. RegCloseKey(hkCV);
  140. }
  141. }
  142. if (lRet == ERROR_SUCCESS)
  143. {
  144. dwSize = sizeof(ULONG);
  145. lRet = RegQueryValueEx(hKey, pInfoLevelString, NULL, NULL,
  146. (LPBYTE)pulInfoLevel, &dwSize);
  147. if (lRet != ERROR_SUCCESS)
  148. {
  149. *pulInfoLevel = (DEB_ERROR | DEB_WARN);
  150. lRet = RegSetValueEx(hKey, pInfoLevelString, 0, REG_DWORD,
  151. (CONST BYTE *)pulInfoLevel, sizeof(ULONG));
  152. }
  153. RegCloseKey(hKey);
  154. }
  155. }
  156. // Returns a pointer to the last component of a path string.
  157. //
  158. // in:
  159. // path name, either fully qualified or not
  160. //
  161. // returns:
  162. // pointer into the path where the path is. if none is found
  163. // returns a poiter to the start of the path
  164. //
  165. // c:\foo\bar -> bar
  166. // c:\foo -> foo
  167. // c:\foo\ -> c:\foo\ (REVIEW: is this case busted?)
  168. // c:\ -> c:\ (REVIEW: this case is strange)
  169. // c: -> c:
  170. // foo -> foo
  171. LPSTR AnsiPathFindFileName(LPSTR pPath)
  172. {
  173. LPSTR pT;
  174. for (pT = pPath; *pPath; pPath = CharNextA(pPath)) {
  175. if ((pPath[0] == '\\' || pPath[0] == ':')
  176. && pPath[1] && (pPath[1] != '\\'))
  177. pT = pPath + 1;
  178. }
  179. return (LPSTR)pT; // const -> non const
  180. }
  181. /////////////////////////////////////////////////////////////////////////////
  182. /////////////////////////////////////////////////////////////////////////////
  183. ////////////// ASSERT CODE //////////////////////////////////////////////
  184. /////////////////////////////////////////////////////////////////////////////
  185. /////////////////////////////////////////////////////////////////////////////
  186. //+------------------------------------------------------------
  187. // Function: PopUpError
  188. //
  189. // Synopsis: Displays a dialog box using provided text,
  190. // and presents the user with the option to
  191. // continue or cancel.
  192. //
  193. // Arguments:
  194. // szMsg -- The string to display in main body of dialog
  195. // iLine -- Line number of file in error
  196. // szFile -- Filename of file in error
  197. //
  198. // Returns:
  199. // IDCANCEL -- User selected the CANCEL button
  200. // IDOK -- User selected the OK button
  201. //-------------------------------------------------------------
  202. int PopUpError(LPTSTR szMsg, int iLine, LPSTR szFile)
  203. {
  204. //
  205. // Create caption
  206. //
  207. static TCHAR szAssertCaption[128];
  208. //
  209. // get process
  210. //
  211. static CHAR szModuleName[128];
  212. LPSTR pszModuleName;
  213. if (GetModuleFileNameA(NULL, szModuleName, 128))
  214. {
  215. pszModuleName = szModuleName;
  216. }
  217. else
  218. {
  219. pszModuleName = "Unknown";
  220. }
  221. LPSTR pProcess = AnsiPathFindFileName(pszModuleName);
  222. // 591438-2002/04/05 JonN removed wsprintf
  223. // "%hs" is short-string
  224. VERIFY( SUCCEEDED( StringCchPrintf(szAssertCaption,
  225. ARRAYLEN(szAssertCaption),
  226. _T("%hs: Assertion Failed"),
  227. pProcess) ) );
  228. //
  229. // Create details.
  230. //
  231. TCHAR szDetails[1024];
  232. DWORD tid = GetCurrentThreadId();
  233. DWORD pid = GetCurrentProcessId();
  234. // 591438-2002/04/05 JonN removed wsprintf
  235. VERIFY( SUCCEEDED( StringCchPrintf(
  236. szDetails,
  237. ARRAYLEN(szDetails),
  238. _T(" Assertion:\t %s\n\n") \
  239. _T(" File: \t\t %hs\n") \
  240. _T(" Line: \t\t %d\n\n") \
  241. _T(" Module: \t %hs\n") \
  242. _T(" Thread ID:\t %d.%d\n"),
  243. szMsg, szFile, iLine, pszModuleName, pid, tid) ) );
  244. int id = MessageBox(NULL,
  245. szDetails,
  246. szAssertCaption,
  247. MB_SETFOREGROUND
  248. | MB_DEFAULT_DESKTOP_ONLY
  249. | MB_TASKMODAL
  250. | MB_ICONEXCLAMATION
  251. | MB_OKCANCEL);
  252. //
  253. // If id == 0, then an error occurred. There are two possibilities
  254. // that can cause the error: Access Denied, which means that this
  255. // process does not have access to the default desktop, and everything
  256. // else (usually out of memory).
  257. //
  258. if (0 == id)
  259. {
  260. if (GetLastError() == ERROR_ACCESS_DENIED)
  261. {
  262. //
  263. // Retry this one with the SERVICE_NOTIFICATION flag on. That
  264. // should get us to the right desktop.
  265. //
  266. id = MessageBox(NULL,
  267. szMsg,
  268. szAssertCaption,
  269. MB_SETFOREGROUND
  270. | MB_TASKMODAL
  271. | MB_ICONEXCLAMATION
  272. | MB_OKCANCEL);
  273. }
  274. }
  275. return id;
  276. }
  277. //+---------------------------------------------------------------------------
  278. //
  279. // Function: _asdprintf
  280. //
  281. // Synopsis: Calls smprintf to output a formatted message.
  282. //
  283. // History: 18-Oct-91 vich Created
  284. //
  285. //----------------------------------------------------------------------------
  286. inline void _asdprintf(LPTSTR pszfmt, ...)
  287. {
  288. va_list va;
  289. va_start(va, pszfmt);
  290. smprintf(DEB_FORCE, _T("Assert"), pszfmt, va);
  291. va_end(va);
  292. }
  293. //+---------------------------------------------------------------------------
  294. //
  295. // Function: AdminAssertEx, private
  296. //
  297. // Synopsis: Display assertion information
  298. //
  299. // Effects: Called when an assertion is hit.
  300. //
  301. //----------------------------------------------------------------------------
  302. void AdminAssertEx(LPSTR szFile, int iLine, LPTSTR szMessage)
  303. {
  304. if (AdminAssertLevel & ASSRT_MESSAGE)
  305. {
  306. DWORD tid = GetCurrentThreadId();
  307. LPSTR pszFileName = AnsiPathFindFileName(szFile);
  308. _asdprintf(_T("%s <%hs, l %u, thread %d>\n"),
  309. szMessage, pszFileName, iLine, tid);
  310. }
  311. if (AdminAssertLevel & ASSRT_POPUP)
  312. {
  313. int id = PopUpError(szMessage,iLine,szFile);
  314. if (id == IDCANCEL)
  315. {
  316. DebugBreak();
  317. }
  318. }
  319. else if (AdminAssertLevel & ASSRT_BREAK)
  320. {
  321. DebugBreak();
  322. }
  323. }
  324. //____________________________________________________________________________
  325. //____________________________________________________________________________
  326. //________________ _________________________________________
  327. //________________ class CDbg _________________________________________
  328. //________________ _________________________________________
  329. //____________________________________________________________________________
  330. //____________________________________________________________________________
  331. CDbg::CDbg(LPTSTR str)
  332. :
  333. m_InfoLevelString(str),
  334. m_InfoLevel(DEB_ERROR | DEB_WARN)
  335. {
  336. CheckInit(m_InfoLevelString, &m_InfoLevel);
  337. }
  338. void CDbg::Trace(LPSTR pszfmt, ...)
  339. {
  340. #ifdef UNICODE
  341. size_t convert = strlen(pszfmt) + 1;
  342. LPTSTR ptcfmt = (LPWSTR)alloca(convert * sizeof(WCHAR));
  343. ptcfmt[0] = '\0';
  344. (void) MultiByteToWideChar(CP_ACP, 0, pszfmt, -1, ptcfmt, (int) convert);
  345. #else
  346. LPTSTR ptcfmt = pszfmt;
  347. #endif
  348. if (m_InfoLevel & DEB_TRACE)
  349. {
  350. va_list va;
  351. va_start (va, pszfmt);
  352. smprintf(DEB_TRACE, m_InfoLevelString, ptcfmt, va);
  353. va_end(va);
  354. }
  355. }
  356. void CDbg::Trace(LPWSTR pwszfmt, ...)
  357. {
  358. #ifndef UNICODE
  359. // NTRAID#NTBUG9-590026-2002/03/29 JonN I am not confident in this
  360. // translation code, since the MBCS string will often have more
  361. // characters than the UNICODE string. However, this code is
  362. // restricted to non-UNICODE snapins so it isn't too relevant.
  363. size_t convert = wcslen(pwszfmt) + 1;
  364. LPTSTR ptcfmt = (LPSTR)alloca(convert * sizeof(CHAR));
  365. ptcfmt[0] = '\0';
  366. (void) WideCharToMultiByte(CP_ACP, 0, pwszfmt, -1, ptcfmt, (int) convert, NULL, NULL);
  367. #else
  368. LPTSTR ptcfmt = pwszfmt;
  369. #endif
  370. if (m_InfoLevel & DEB_TRACE)
  371. {
  372. va_list va;
  373. va_start (va, pwszfmt);
  374. smprintf(DEB_TRACE, m_InfoLevelString, ptcfmt, va);
  375. va_end(va);
  376. }
  377. }
  378. void CDbg::DebugOut(ULONG fDebugMask, LPSTR pszfmt, ...)
  379. {
  380. #ifdef UNICODE
  381. size_t convert = strlen(pszfmt) + 1;
  382. LPTSTR ptcfmt = (LPWSTR)alloca(convert * sizeof(WCHAR));
  383. ptcfmt[0] = '\0';
  384. (void) MultiByteToWideChar(CP_ACP, 0, pszfmt, -1, ptcfmt, (int) convert);
  385. #else
  386. LPTSTR ptcfmt = pszfmt;
  387. #endif
  388. if (m_InfoLevel & fDebugMask)
  389. {
  390. va_list va;
  391. va_start (va, pszfmt);
  392. smprintf(DEB_TRACE, m_InfoLevelString, ptcfmt, va);
  393. va_end(va);
  394. }
  395. }
  396. void CDbg::DebugOut(ULONG fDebugMask, LPWSTR pwszfmt, ...)
  397. {
  398. #ifndef UNICODE
  399. int convert = wcslen(pwszfmt) + 1;
  400. LPTSTR ptcfmt = (LPSTR)alloca(convert * sizeof(CHAR));
  401. ptcfmt[0] = '\0';
  402. (void) WideCharToMultiByte(CP_ACP, 0, pwszfmt, -1, ptcfmt, convert, NULL, NULL);
  403. #else
  404. LPTSTR ptcfmt = pwszfmt;
  405. #endif
  406. if (m_InfoLevel & fDebugMask)
  407. {
  408. va_list va;
  409. va_start (va, pwszfmt);
  410. smprintf(DEB_TRACE, m_InfoLevelString, ptcfmt, va);
  411. va_end(va);
  412. }
  413. }
  414. void CDbg::DebugErrorX(LPSTR file, ULONG line, LONG err)
  415. {
  416. if (m_InfoLevel & DEB_ERROR)
  417. {
  418. file = AnsiPathFindFileName(file);
  419. this->DebugOut(DEB_ERROR, "error<0x%08x> %hs, l %u\n",
  420. err, file, line);
  421. }
  422. }
  423. void CDbg::DebugErrorL(LPSTR file, ULONG line, LONG err)
  424. {
  425. if (m_InfoLevel & DEB_ERROR)
  426. {
  427. file = AnsiPathFindFileName(file);
  428. this->DebugOut(DEB_ERROR, "error<%uL> %hs, l %u\n", err, file, line);
  429. }
  430. }
  431. void CDbg::DebugMsg(LPSTR file, ULONG line, LPSTR msg)
  432. {
  433. file = AnsiPathFindFileName(file);
  434. this->DebugOut(DEB_FORCE, "asrt %hs, l %u, <%s>\n", file, line, msg);
  435. }
  436. void CDbg::DebugMsg(LPSTR file, ULONG line, LPWSTR msg)
  437. {
  438. file = AnsiPathFindFileName(file);
  439. this->DebugOut(DEB_FORCE, _T("asrt %hs, l %u, <%s>\n"), file, line, msg);
  440. }
  441. void CDbg::AssertEx(LPSTR pszFile, int iLine, LPTSTR pszMsg)
  442. {
  443. #if 0
  444. LPTSTR ptcMsg = NULL;
  445. #ifdef UNICODE
  446. int convert = strlen(pszMsg) + 1;
  447. ptcMsg = (LPWSTR)alloca(convert * sizeof(WCHAR));
  448. ptcMsg[0] = '\0';
  449. (void) MultiByteToWideChar(CP_ACP, 0, pszMsg, -1, ptcMsg, convert);
  450. #else
  451. ptcMsg = pszMsg;
  452. #endif
  453. AdminAssertEx(pszFile, iLine, ptcMsg);
  454. #endif //0
  455. AdminAssertEx(pszFile, iLine, pszMsg);
  456. }
  457. #endif // DBG==1