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.

352 lines
8.7 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. wsprintfA(szOutput, "0x%x: 0x%x: %s\r\n", GetCurrentProcessId(), GetCurrentThreadId(), szTmp);
  127. OutputDebugStringA(szOutput);
  128. //
  129. // Attempt to log output
  130. //
  131. CHAR szFileName[MAX_PATH + 1];
  132. DWORD dwBytes;
  133. GetSystemDirectoryA(szFileName, MAX_PATH);
  134. lstrcatA(szFileName, "\\CMTRACE.TXT");
  135. HANDLE hFile = CreateFileA(szFileName,
  136. GENERIC_WRITE,
  137. FILE_SHARE_WRITE,
  138. NULL,
  139. OPEN_EXISTING,
  140. FILE_ATTRIBUTE_NORMAL,
  141. NULL);
  142. if (hFile != INVALID_HANDLE_VALUE)
  143. {
  144. if (INVALID_SET_FILE_POINTER != SetFilePointer(hFile, 0, 0, FILE_END))
  145. {
  146. WriteFile(hFile, szOutput, sizeof(CHAR)*lstrlen(szOutput), &dwBytes, NULL);
  147. }
  148. CloseHandle(hFile);
  149. }
  150. }
  151. void MyDbgAssertW(const char *pszFile, unsigned nLine, WCHAR *pszMsg)
  152. {
  153. CHAR szOutput[1024];
  154. wsprintfA(szOutput, "%s(%u) - %S", pszFile, nLine, pszMsg);
  155. MyDbgPrintfA(szOutput);
  156. //
  157. // Prompt user
  158. //
  159. wsprintfA(szOutput, "%s(%u) - %S\n( Press Retry to debug )", pszFile, nLine, pszMsg);
  160. int nCode = IDIGNORE;
  161. static long dwAssertCount = -1; // Avoid another assert while the messagebox is up
  162. //
  163. // If there is no Assertion meesagebox, popup one
  164. //
  165. if (InterlockedIncrement(&dwAssertCount) == 0)
  166. {
  167. nCode = MessageBoxExA(NULL, szOutput, "Assertion Failed",
  168. MB_SYSTEMMODAL | MB_ICONHAND | MB_ABORTRETRYIGNORE, LANG_USER_DEFAULT);
  169. }
  170. InterlockedDecrement(&dwAssertCount);
  171. if (nCode == IDIGNORE)
  172. {
  173. return; // ignore
  174. }
  175. else if (nCode == IDRETRY)
  176. {
  177. // break into the debugger (or Dr Watson log)
  178. #ifdef _X86_
  179. _asm { int 3 };
  180. #else
  181. DebugBreak();
  182. #endif
  183. return; // ignore and continue in debugger to diagnose problem
  184. }
  185. // else fall through and call Abort
  186. ExitProcess((DWORD)-1);
  187. }
  188. #endif //DEBUG
  189. //
  190. // Included to make MyDbgPrintfW work on win9x. Please note that it steps through the string
  191. // byte by byte (doesn't deal with MBCS chars) but since this is really called on Format strings
  192. // this shouldn't be a problem.
  193. //
  194. void InvertPercentSAndPercentC(LPSTR pszFormat)
  195. {
  196. if (pszFormat)
  197. {
  198. LPSTR pszTmp = pszFormat;
  199. BOOL bPrevCharPercent = FALSE;
  200. while(*pszTmp)
  201. {
  202. switch (*pszTmp)
  203. {
  204. case '%':
  205. //
  206. // if we have %% then we must ignore the percent, otherwise save it.
  207. //
  208. bPrevCharPercent = !bPrevCharPercent;
  209. break;
  210. case 'S':
  211. if (bPrevCharPercent)
  212. {
  213. *pszTmp = 's';
  214. }
  215. break;
  216. case 's':
  217. if (bPrevCharPercent)
  218. {
  219. *pszTmp = 'S';
  220. }
  221. break;
  222. case 'C':
  223. if (bPrevCharPercent)
  224. {
  225. *pszTmp = 'c';
  226. }
  227. break;
  228. case 'c':
  229. if (bPrevCharPercent)
  230. {
  231. *pszTmp = 'C';
  232. }
  233. break;
  234. default:
  235. //
  236. // don't fool ourselves by always keeping this set.
  237. //
  238. bPrevCharPercent = FALSE;
  239. break;
  240. }
  241. pszTmp++;
  242. }
  243. }
  244. }
  245. //
  246. // This function takes Unicode input strings (potentially in the va_list as well)
  247. // and uses the fact that wvsprintfA will print Unicode strings into an Ansi
  248. // output string if the special char %S is used instead of %s. Thus we will convert
  249. // the input parameter string and then replace all the %s chars with %S chars (and vice versa).
  250. // This will allow us to call wvsprintfA since wvsprintfW isn't available on win9x.
  251. //
  252. int WINAPI wvsprintfWtoAWrapper(OUT LPSTR pszAnsiOut, IN LPCWSTR pszwFmt, IN va_list arglist)
  253. {
  254. int iRet = 0;
  255. LPSTR pszAnsiFormat = NULL;
  256. if ((NULL != pszAnsiOut) && (NULL != pszwFmt) && (L'\0' != pszwFmt[0]))
  257. {
  258. //
  259. // Convert pszwFmt to Ansi
  260. //
  261. DWORD dwSize = WideCharToMultiByte(CP_ACP, 0, pszwFmt, -1, pszAnsiFormat, 0, NULL, NULL);
  262. if (0 != dwSize)
  263. {
  264. pszAnsiFormat = (LPSTR)LocalAlloc(LPTR, dwSize*sizeof(CHAR));
  265. if (pszAnsiFormat)
  266. {
  267. if (WideCharToMultiByte(CP_ACP, 0, pszwFmt, -1, pszAnsiFormat, dwSize, NULL, NULL))
  268. {
  269. //
  270. // Now change the little s's and c's to their capital equivalent and vice versa
  271. //
  272. InvertPercentSAndPercentC(pszAnsiFormat);
  273. //
  274. // Finally construct the string
  275. //
  276. iRet = wvsprintfA(pszAnsiOut, pszAnsiFormat, arglist);
  277. }
  278. }
  279. }
  280. }
  281. LocalFree(pszAnsiFormat);
  282. return iRet;
  283. }
  284. #ifdef __cplusplus
  285. }
  286. #endif