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.

367 lines
9.6 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // File: cmdebug.cpp
  4. //
  5. // Module: CMDEBUG.LIB
  6. //
  7. // Synopsis: This source file contains the debugging routines common to all
  8. // of the CM components.
  9. //
  10. // Copyright (c) 1998-1999 Microsoft Corporation
  11. //
  12. // Author: nickball Created 02/04/98
  13. //
  14. //+----------------------------------------------------------------------------
  15. #ifdef __cplusplus
  16. extern "C" {
  17. #endif
  18. #include <windows.h>
  19. #ifdef DEBUG
  20. #include <stddef.h>
  21. #include <stdlib.h>
  22. #include <stdio.h>
  23. #include "cmdebug.h"
  24. //
  25. // Ansi Versions
  26. //
  27. void MyDbgPrintfA(const char *pszFmt, ...)
  28. {
  29. va_list valArgs;
  30. char szTmp[512];
  31. CHAR szOutput[512];
  32. va_start(valArgs, pszFmt);
  33. wvsprintfA(szTmp, pszFmt, valArgs);
  34. va_end(valArgs);
  35. wsprintfA(szOutput, "0x%x: 0x%x: %s\r\n", GetCurrentProcessId(), GetCurrentThreadId(), szTmp);
  36. OutputDebugStringA(szOutput);
  37. //
  38. // Attempt to log output
  39. //
  40. CHAR szFileName[MAX_PATH + 1];
  41. DWORD dwBytes;
  42. GetSystemDirectoryA(szFileName, MAX_PATH);
  43. lstrcatA(szFileName, "\\CMTRACE.TXT");
  44. HANDLE hFile = CreateFileA(szFileName,
  45. GENERIC_WRITE,
  46. FILE_SHARE_WRITE,
  47. NULL,
  48. OPEN_EXISTING,
  49. FILE_ATTRIBUTE_NORMAL,
  50. NULL);
  51. if (hFile != INVALID_HANDLE_VALUE)
  52. {
  53. if (INVALID_SET_FILE_POINTER != SetFilePointer(hFile, 0, 0, FILE_END))
  54. {
  55. WriteFile(hFile, szOutput, sizeof(CHAR)*lstrlenA(szOutput), &dwBytes, NULL);
  56. }
  57. CloseHandle(hFile);
  58. }
  59. }
  60. void MyDbgAssertA(const char *pszFile, unsigned nLine, const char *pszMsg)
  61. {
  62. char szOutput[1024];
  63. wsprintfA(szOutput, "%s(%u) - %s", pszFile, nLine, pszMsg);
  64. MyDbgPrintfA(szOutput);
  65. //
  66. // Prompt user
  67. //
  68. wsprintfA(szOutput, "%s(%u) - %s\n( Press Retry to debug )", pszFile, nLine, pszMsg);
  69. int nCode = IDIGNORE;
  70. static long dwAssertCount = -1; // Avoid another assert while the messagebox is up
  71. //
  72. // If there is no Assertion meesagebox, popup one
  73. //
  74. if (InterlockedIncrement(&dwAssertCount) == 0)
  75. {
  76. nCode = MessageBoxExA(NULL, szOutput, "Assertion Failed",
  77. MB_SYSTEMMODAL | MB_ICONHAND | MB_ABORTRETRYIGNORE, LANG_USER_DEFAULT);
  78. }
  79. InterlockedDecrement(&dwAssertCount);
  80. if (nCode == IDIGNORE)
  81. {
  82. return; // ignore
  83. }
  84. else if (nCode == IDRETRY)
  85. {
  86. // break into the debugger (or Dr Watson log)
  87. #ifdef _X86_
  88. _asm { int 3 };
  89. #else
  90. DebugBreak();
  91. #endif
  92. return; // ignore and continue in debugger to diagnose problem
  93. }
  94. else if (0 == nCode)
  95. {
  96. //
  97. // MessageBoxEx Failed. Lets call GLE
  98. //
  99. DWORD dwError = GetLastError();
  100. //
  101. // Fall through and exit process anyway
  102. //
  103. }
  104. // else fall through and call Abort
  105. ExitProcess((DWORD)-1);
  106. }
  107. //
  108. // Unicode Versions
  109. //
  110. void MyDbgPrintfW(const WCHAR *pszFmt, ...)
  111. {
  112. va_list valArgs;
  113. CHAR szOutput[512];
  114. CHAR szTmp[512];
  115. va_start(valArgs, pszFmt);
  116. int iRet = wvsprintfWtoAWrapper(szTmp, pszFmt, valArgs);
  117. va_end(valArgs);
  118. if (0 == iRet)
  119. {
  120. //
  121. // We weren't able to write the Unicode string as expected. Lets
  122. // try just putting a failure string in the szTmp buffer instead.
  123. //
  124. lstrcpyA(szTmp, "MyDbgPrintfW -- wvsprintfWtoAWrapper failed. Unsure of original message, please investigate.");
  125. }
  126. #if defined(DEBUG_TRACETIME)
  127. static const CHAR c_szaFmtTime[] = "[%02dh%02d:%02d.%03d]";
  128. CHAR szTime[15] = ""; // NOTE: the size of this must be in sync with the string above
  129. SYSTEMTIME stLocal;
  130. GetLocalTime(&stLocal);
  131. wsprintfA (szTime, c_szaFmtTime,
  132. stLocal.wHour,
  133. stLocal.wMinute,
  134. stLocal.wSecond,
  135. stLocal.wMilliseconds);
  136. wsprintfA(szOutput, "%s 0x%x: 0x%x: %s\r\n", szTime, GetCurrentProcessId(), GetCurrentThreadId(), szTmp);
  137. #else
  138. wsprintfA(szOutput, "0x%x: 0x%x: %s\r\n", GetCurrentProcessId(), GetCurrentThreadId(), szTmp);
  139. #endif
  140. OutputDebugStringA(szOutput);
  141. //
  142. // Attempt to log output
  143. //
  144. CHAR szFileName[MAX_PATH + 1];
  145. DWORD dwBytes;
  146. GetSystemDirectoryA(szFileName, MAX_PATH);
  147. lstrcatA(szFileName, "\\CMTRACE.TXT");
  148. HANDLE hFile = CreateFileA(szFileName,
  149. GENERIC_WRITE,
  150. FILE_SHARE_WRITE,
  151. NULL,
  152. OPEN_EXISTING,
  153. FILE_ATTRIBUTE_NORMAL,
  154. NULL);
  155. if (hFile != INVALID_HANDLE_VALUE)
  156. {
  157. if (INVALID_SET_FILE_POINTER != SetFilePointer(hFile, 0, 0, FILE_END))
  158. {
  159. WriteFile(hFile, szOutput, sizeof(CHAR)*lstrlen(szOutput), &dwBytes, NULL);
  160. }
  161. CloseHandle(hFile);
  162. }
  163. }
  164. void MyDbgAssertW(const char *pszFile, unsigned nLine, WCHAR *pszMsg)
  165. {
  166. CHAR szOutput[1024];
  167. wsprintfA(szOutput, "%s(%u) - %S", pszFile, nLine, pszMsg);
  168. MyDbgPrintfA(szOutput);
  169. //
  170. // Prompt user
  171. //
  172. wsprintfA(szOutput, "%s(%u) - %S\n( Press Retry to debug )", pszFile, nLine, pszMsg);
  173. int nCode = IDIGNORE;
  174. static long dwAssertCount = -1; // Avoid another assert while the messagebox is up
  175. //
  176. // If there is no Assertion meesagebox, popup one
  177. //
  178. if (InterlockedIncrement(&dwAssertCount) == 0)
  179. {
  180. nCode = MessageBoxExA(NULL, szOutput, "Assertion Failed",
  181. MB_SYSTEMMODAL | MB_ICONHAND | MB_ABORTRETRYIGNORE, LANG_USER_DEFAULT);
  182. }
  183. InterlockedDecrement(&dwAssertCount);
  184. if (nCode == IDIGNORE)
  185. {
  186. return; // ignore
  187. }
  188. else if (nCode == IDRETRY)
  189. {
  190. // break into the debugger (or Dr Watson log)
  191. #ifdef _X86_
  192. _asm { int 3 };
  193. #else
  194. DebugBreak();
  195. #endif
  196. return; // ignore and continue in debugger to diagnose problem
  197. }
  198. // else fall through and call Abort
  199. ExitProcess((DWORD)-1);
  200. }
  201. #endif //DEBUG
  202. //
  203. // Included to make MyDbgPrintfW work on win9x. Please note that it steps through the string
  204. // byte by byte (doesn't deal with MBCS chars) but since this is really called on Format strings
  205. // this shouldn't be a problem.
  206. //
  207. void InvertPercentSAndPercentC(LPSTR pszFormat)
  208. {
  209. if (pszFormat)
  210. {
  211. LPSTR pszTmp = pszFormat;
  212. BOOL bPrevCharPercent = FALSE;
  213. while(*pszTmp)
  214. {
  215. switch (*pszTmp)
  216. {
  217. case '%':
  218. //
  219. // if we have %% then we must ignore the percent, otherwise save it.
  220. //
  221. bPrevCharPercent = !bPrevCharPercent;
  222. break;
  223. case 'S':
  224. if (bPrevCharPercent)
  225. {
  226. *pszTmp = 's';
  227. }
  228. break;
  229. case 's':
  230. if (bPrevCharPercent)
  231. {
  232. *pszTmp = 'S';
  233. }
  234. break;
  235. case 'C':
  236. if (bPrevCharPercent)
  237. {
  238. *pszTmp = 'c';
  239. }
  240. break;
  241. case 'c':
  242. if (bPrevCharPercent)
  243. {
  244. *pszTmp = 'C';
  245. }
  246. break;
  247. default:
  248. //
  249. // don't fool ourselves by always keeping this set.
  250. //
  251. bPrevCharPercent = FALSE;
  252. break;
  253. }
  254. pszTmp++;
  255. }
  256. }
  257. }
  258. //
  259. // This function takes Unicode input strings (potentially in the va_list as well)
  260. // and uses the fact that wvsprintfA will print Unicode strings into an Ansi
  261. // output string if the special char %S is used instead of %s. Thus we will convert
  262. // the input parameter string and then replace all the %s chars with %S chars (and vice versa).
  263. // This will allow us to call wvsprintfA since wvsprintfW isn't available on win9x.
  264. //
  265. int WINAPI wvsprintfWtoAWrapper(OUT LPSTR pszAnsiOut, IN LPCWSTR pszwFmt, IN va_list arglist)
  266. {
  267. int iRet = 0;
  268. LPSTR pszAnsiFormat = NULL;
  269. if ((NULL != pszAnsiOut) && (NULL != pszwFmt) && (L'\0' != pszwFmt[0]))
  270. {
  271. //
  272. // Convert pszwFmt to Ansi
  273. //
  274. DWORD dwSize = WideCharToMultiByte(CP_ACP, 0, pszwFmt, -1, pszAnsiFormat, 0, NULL, NULL);
  275. if (0 != dwSize)
  276. {
  277. pszAnsiFormat = (LPSTR)LocalAlloc(LPTR, dwSize*sizeof(CHAR));
  278. if (pszAnsiFormat)
  279. {
  280. if (WideCharToMultiByte(CP_ACP, 0, pszwFmt, -1, pszAnsiFormat, dwSize, NULL, NULL))
  281. {
  282. //
  283. // Now change the little s's and c's to their capital equivalent and vice versa
  284. //
  285. InvertPercentSAndPercentC(pszAnsiFormat);
  286. //
  287. // Finally construct the string
  288. //
  289. iRet = wvsprintfA(pszAnsiOut, pszAnsiFormat, arglist);
  290. }
  291. }
  292. }
  293. }
  294. LocalFree(pszAnsiFormat);
  295. return iRet;
  296. }
  297. #ifdef __cplusplus
  298. }
  299. #endif