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.

1450 lines
47 KiB

  1. /*
  2. * DEBUG.CPP
  3. *
  4. * Purpose:
  5. * RICHEDIT debugging support--commented out in ship builds
  6. *
  7. * History: <nl>
  8. * 7/29/98 KeithCu Wrote it stealing much from Rich Arneson's code
  9. *
  10. * Copyright (c) 1995-1998, Microsoft Corporation. All rights reserved.
  11. */
  12. #include "_common.h"
  13. //Module is empty if this is a retail build.
  14. #if defined(DEBUG) || defined(_RELEASE_ASSERTS_)
  15. #ifdef NOFULLDEBUG
  16. PFNASSERTHOOK pfnAssert = NULL; //Assert hook function
  17. #else
  18. DWORD dwDebugOptions = 0; //Debug option flags
  19. PFNASSERTHOOK pfnAssert = NULL; //Assert hook function
  20. PFNTRACEHOOK pfnTrace = NULL; //Trace hook function
  21. // Static variables
  22. static HINSTANCE ghMod; //Dll module handle
  23. static DWORD TlsIndex; //Debug output indent level
  24. static HANDLE hLogFile = NULL; //Log file handle
  25. static BOOL fIgnoreAsserts = FALSE; //Ignore all asserts if true
  26. static CRITICAL_SECTION csLog; //Critical section for log file i/o
  27. static CRITICAL_SECTION csAssert; //Critical section for asserts
  28. static HANDLE hEventAssert1 = NULL; //Event for assert syncing
  29. static HANDLE hEventAssert2 = NULL; //Event for assert syncing
  30. static HWND hwndAssert = NULL; //Assert dialog window handle
  31. static HANDLE hAssertThrd = NULL; //Assert thread handle
  32. static char szAssert[MAXDEBUGSTRLEN]; //Assert message buffer
  33. static int idAssert = -1; //Assert button pressed by user
  34. DWORD WINAPI AssertThread(LPVOID lParam); //Assert thread entry point
  35. static BOOL fDllDetach = FALSE; //True if we are in dll detach
  36. //Strings for subsystem element of message
  37. static char* TrcSubsys [] =
  38. {
  39. "",
  40. "Display",
  41. "Wrapper",
  42. "Edit",
  43. "TextServices",
  44. "TOM",
  45. "OLE Object Support",
  46. "Store",
  47. "Selection",
  48. "WinHost",
  49. "DataXfer",
  50. "MultiUndo",
  51. "Range",
  52. "Util",
  53. "Notification Mgr.",
  54. "RTF Reader",
  55. "RTF Writer",
  56. "Printing",
  57. "East Asia",
  58. "Font"
  59. };
  60. //Strings for severity element of message
  61. static char* TrcSeverity [] =
  62. {
  63. "",
  64. "WARNING",
  65. "ERROR",
  66. "ASSERT",
  67. "INFO",
  68. "MEMORY"
  69. };
  70. //Strings for scope element of message
  71. static char* TrcScope [] =
  72. {
  73. "",
  74. "External",
  75. "Internal"
  76. };
  77. //Structure for lookup tables
  78. typedef struct
  79. {
  80. DWORD dwKey;
  81. char * sz;
  82. } TabElem;
  83. //Lookup table for CTrace param strings
  84. static TabElem TrcParamTab [] =
  85. {
  86. //Richedit Messages
  87. {(DWORD)EM_GETLIMITTEXT, "EM_GETLIMITTEXT"},
  88. {(DWORD)EM_POSFROMCHAR, "EM_POSFROMCHAR"},
  89. {(DWORD)EM_CHARFROMPOS, "EM_CHARFROMPOS"},
  90. {(DWORD)EM_SCROLLCARET, "EM_SCROLLCARET"},
  91. {(DWORD)EM_CANPASTE, "EM_CANPASTE"},
  92. {(DWORD)EM_DISPLAYBAND, "EM_DISPLAYBAND"},
  93. {(DWORD)EM_EXGETSEL, "EM_EXGETSEL"},
  94. {(DWORD)EM_EXLIMITTEXT, "EM_EXLIMITTEXT"},
  95. {(DWORD)EM_EXLINEFROMCHAR, "EM_EXLINEFROMCHAR"},
  96. {(DWORD)EM_EXSETSEL, "EM_EXSETSEL"},
  97. {(DWORD)EM_FINDTEXT, "EM_FINDTEXT"},
  98. {(DWORD)EM_FORMATRANGE, "EM_FORMATRANGE"},
  99. {(DWORD)EM_GETCHARFORMAT, "EM_GETCHARFORMAT"},
  100. {(DWORD)EM_GETEVENTMASK, "EM_GETEVENTMASK"},
  101. {(DWORD)EM_GETOLEINTERFACE, "EM_GETOLEINTERFACE"},
  102. {(DWORD)EM_GETPARAFORMAT, "EM_GETPARAFORMAT"},
  103. {(DWORD)EM_GETSELTEXT, "EM_GETSELTEXT"},
  104. {(DWORD)EM_HIDESELECTION, "EM_HIDESELECTION"},
  105. {(DWORD)EM_PASTESPECIAL, "EM_PASTESPECIAL"},
  106. {(DWORD)EM_REQUESTRESIZE, "EM_REQUESTRESIZE"},
  107. {(DWORD)EM_SELECTIONTYPE, "EM_SELECTIONTYPE"},
  108. {(DWORD)EM_SETBKGNDCOLOR, "EM_SETBKGNDCOLOR"},
  109. {(DWORD)EM_SETCHARFORMAT, "EM_SETCHARFORMAT"},
  110. {(DWORD)EM_SETEVENTMASK, "EM_SETEVENTMASK"},
  111. {(DWORD)EM_SETOLECALLBACK, "EM_SETOLECALLBACK"},
  112. {(DWORD)EM_SETPARAFORMAT, "EM_SETPARAFORMAT"},
  113. {(DWORD)EM_SETTARGETDEVICE, "EM_SETTARGETDEVICE"},
  114. {(DWORD)EM_STREAMIN, "EM_STREAMIN"},
  115. {(DWORD)EM_STREAMOUT, "EM_STREAMOUT"},
  116. {(DWORD)EM_GETTEXTRANGE, "EM_GETTEXTRANGE"},
  117. {(DWORD)EM_FINDWORDBREAK, "EM_FINDWORDBREAK"},
  118. {(DWORD)EM_SETOPTIONS, "EM_SETOPTIONS"},
  119. {(DWORD)EM_GETOPTIONS, "EM_GETOPTIONS"},
  120. {(DWORD)EM_FINDTEXTEX, "EM_FINDTEXTEX"},
  121. {(DWORD)EM_GETWORDBREAKPROCEX, "EM_GETWORDBREAKPROCEX"},
  122. {(DWORD)EM_SETWORDBREAKPROCEX, "EM_SETWORDBREAKPROCEX"},
  123. {(DWORD)EM_SETUNDOLIMIT, "EM_SETUNDOLIMIT"},
  124. {(DWORD)EM_REDO, "EM_REDO"},
  125. {(DWORD)EM_CANREDO, "EM_CANREDO"},
  126. {(DWORD)EM_SETPUNCTUATION, "EM_SETPUNCTUATION"},
  127. {(DWORD)EM_GETPUNCTUATION, "EM_GETPUNCTUATION"},
  128. {(DWORD)EM_SETWORDWRAPMODE, "EM_SETWORDWRAPMODE"},
  129. {(DWORD)EM_GETWORDWRAPMODE, "EM_GETWORDWRAPMODE"},
  130. {(DWORD)EM_SETIMECOLOR, "EM_SETIMECOLOR"},
  131. {(DWORD)EM_GETIMECOLOR, "EM_GETIMECOLOR"},
  132. {(DWORD)EM_SETIMEOPTIONS, "EM_SETIMEOPTIONS"},
  133. {(DWORD)EM_GETIMEOPTIONS, "EM_GETIMEOPTIONS"},
  134. {(DWORD)EN_MSGFILTER, "EN_MSGFILTER"},
  135. {(DWORD)EN_REQUESTRESIZE, "EN_REQUESTRESIZE"},
  136. {(DWORD)EN_SELCHANGE, "EN_SELCHANGE"},
  137. {(DWORD)EN_DROPFILES, "EN_DROPFILES"},
  138. {(DWORD)EN_PROTECTED, "EN_PROTECTED"},
  139. {(DWORD)EN_CORRECTTEXT, "EN_CORRECTTEXT"},
  140. {(DWORD)EN_STOPNOUNDO, "EN_STOPNOUNDO"},
  141. {(DWORD)EN_IMECHANGE, "EN_IMECHANGE"},
  142. {(DWORD)EN_SAVECLIPBOARD, "EN_SAVECLIPBOARD"},
  143. {(DWORD)EN_OLEOPFAILED, "EN_OLEOPFAILED"},
  144. //Window Messages
  145. {(DWORD)WM_NULL, "WM_NULL"},
  146. {(DWORD)WM_CREATE, "WM_CREATE"},
  147. {(DWORD)WM_DESTROY, "WM_DESTROY"},
  148. {(DWORD)WM_MOVE, "WM_MOVE"},
  149. {(DWORD)WM_SIZE, "WM_SIZE"},
  150. {(DWORD)WM_ACTIVATE, "WM_ACTIVATE"},
  151. {(DWORD)WM_SETFOCUS, "WM_SETFOCUS"},
  152. {(DWORD)WM_KILLFOCUS, "WM_KILLFOCUS"},
  153. {(DWORD)WM_ENABLE, "WM_ENABLE"},
  154. {(DWORD)WM_SETREDRAW, "WM_SETREDRAW"},
  155. {(DWORD)WM_SETTEXT, "WM_SETTEXT"},
  156. {(DWORD)WM_GETTEXT, "WM_GETTEXT"},
  157. {(DWORD)WM_GETTEXTLENGTH, "WM_GETTEXTLENGTH"},
  158. {(DWORD)WM_PAINT, "WM_PAINT"},
  159. {(DWORD)WM_CLOSE, "WM_CLOSE"},
  160. {(DWORD)WM_QUERYENDSESSION, "WM_QUERYENDSESSION"},
  161. {(DWORD)WM_QUIT, "WM_QUIT"},
  162. {(DWORD)WM_QUERYOPEN, "WM_QUERYOPEN"},
  163. {(DWORD)WM_ERASEBKGND, "WM_ERASEBKGND"},
  164. {(DWORD)WM_SYSCOLORCHANGE, "WM_SYSCOLORCHANGE"},
  165. {(DWORD)WM_ENDSESSION, "WM_ENDSESSION"},
  166. {(DWORD)WM_SHOWWINDOW, "WM_SHOWWINDOW"},
  167. {(DWORD)WM_WININICHANGE, "WM_WININICHANGE"},
  168. {(DWORD)WM_SETTINGCHANGE, "WM_SETTINGCHANGE"},
  169. {(DWORD)WM_DEVMODECHANGE, "WM_DEVMODECHANGE"},
  170. {(DWORD)WM_ACTIVATEAPP, "WM_ACTIVATEAPP"},
  171. {(DWORD)WM_FONTCHANGE, "WM_FONTCHANGE"},
  172. {(DWORD)WM_TIMECHANGE, "WM_TIMECHANGE"},
  173. {(DWORD)WM_CANCELMODE, "WM_CANCELMODE"},
  174. {(DWORD)WM_SETCURSOR, "WM_SETCURSOR"},
  175. {(DWORD)WM_MOUSEACTIVATE, "WM_MOUSEACTIVATE"},
  176. {(DWORD)WM_CHILDACTIVATE, "WM_CHILDACTIVATE"},
  177. {(DWORD)WM_QUEUESYNC, "WM_QUEUESYNC"},
  178. {(DWORD)WM_GETMINMAXINFO, "WM_GETMINMAXINFO"},
  179. {(DWORD)WM_PAINTICON, "WM_PAINTICON"},
  180. {(DWORD)WM_ICONERASEBKGND, "WM_ICONERASEBKGND"},
  181. {(DWORD)WM_NEXTDLGCTL, "WM_NEXTDLGCTL"},
  182. {(DWORD)WM_SPOOLERSTATUS, "WM_SPOOLERSTATUS"},
  183. {(DWORD)WM_DRAWITEM, "WM_DRAWITEM"},
  184. {(DWORD)WM_MEASUREITEM, "WM_MEASUREITEM"},
  185. {(DWORD)WM_DELETEITEM, "WM_DELETEITEM"},
  186. {(DWORD)WM_VKEYTOITEM, "WM_VKEYTOITEM"},
  187. {(DWORD)WM_CHARTOITEM, "WM_CHARTOITEM"},
  188. {(DWORD)WM_SETFONT, "WM_SETFONT"},
  189. {(DWORD)WM_GETFONT, "WM_GETFONT"},
  190. {(DWORD)WM_SETHOTKEY, "WM_SETHOTKEY"},
  191. {(DWORD)WM_GETHOTKEY, "WM_GETHOTKEY"},
  192. {(DWORD)WM_QUERYDRAGICON, "WM_QUERYDRAGICON"},
  193. {(DWORD)WM_COMPAREITEM, "WM_COMPAREITEM"},
  194. {(DWORD)WM_COMPACTING, "WM_COMPACTING"},
  195. {(DWORD)WM_COMMNOTIFY, "WM_COMMNOTIFY"},
  196. {(DWORD)WM_WINDOWPOSCHANGING, "WM_WINDOWPOSCHANGING"},
  197. {(DWORD)WM_WINDOWPOSCHANGED, "WM_WINDOWPOSCHANGED"},
  198. {(DWORD)WM_POWER, "WM_POWER"},
  199. {(DWORD)WM_COPYDATA, "WM_COPYDATA"},
  200. {(DWORD)WM_CANCELJOURNAL, "WM_CANCELJOURNAL"},
  201. {(DWORD)WM_NOTIFY, "WM_NOTIFY"},
  202. {(DWORD)WM_INPUTLANGCHANGEREQUEST, "WM_INPUTLANGCHANGEREQUEST"},
  203. {(DWORD)WM_INPUTLANGCHANGE, "WM_INPUTLANGCHANGE"},
  204. {(DWORD)WM_TCARD, "WM_TCARD"},
  205. {(DWORD)WM_HELP, "WM_HELP"},
  206. {(DWORD)WM_USERCHANGED, "WM_USERCHANGED"},
  207. {(DWORD)WM_NOTIFYFORMAT, "WM_NOTIFYFORMAT"},
  208. {(DWORD)WM_CONTEXTMENU, "WM_CONTEXTMENU"},
  209. {(DWORD)WM_STYLECHANGING, "WM_STYLECHANGING"},
  210. {(DWORD)WM_STYLECHANGED, "WM_STYLECHANGED"},
  211. {(DWORD)WM_DISPLAYCHANGE, "WM_DISPLAYCHANGE"},
  212. {(DWORD)WM_GETICON, "WM_GETICON"},
  213. {(DWORD)WM_SETICON, "WM_SETICON"},
  214. {(DWORD)WM_NCCREATE, "WM_NCCREATE"},
  215. {(DWORD)WM_NCDESTROY, "WM_NCDESTROY"},
  216. {(DWORD)WM_NCCALCSIZE, "WM_NCCALCSIZE"},
  217. {(DWORD)WM_NCHITTEST, "WM_NCHITTEST"},
  218. {(DWORD)WM_NCPAINT, "WM_NCPAINT"},
  219. {(DWORD)WM_NCACTIVATE, "WM_NCACTIVATE"},
  220. {(DWORD)WM_GETDLGCODE, "WM_GETDLGCODE"},
  221. {(DWORD)WM_NCMOUSEMOVE, "WM_NCMOUSEMOVE"},
  222. {(DWORD)WM_NCLBUTTONDOWN, "WM_NCLBUTTONDOWN"},
  223. {(DWORD)WM_NCLBUTTONUP, "WM_NCLBUTTONUP"},
  224. {(DWORD)WM_NCLBUTTONDBLCLK, "WM_NCLBUTTONDBLCLK"},
  225. {(DWORD)WM_NCRBUTTONDOWN, "WM_NCRBUTTONDOWN"},
  226. {(DWORD)WM_NCRBUTTONUP, "WM_NCRBUTTONUP"},
  227. {(DWORD)WM_NCRBUTTONDBLCLK, "WM_NCRBUTTONDBLCLK"},
  228. {(DWORD)WM_NCMBUTTONDOWN, "WM_NCMBUTTONDOWN"},
  229. {(DWORD)WM_NCMBUTTONUP, "WM_NCMBUTTONUP"},
  230. {(DWORD)WM_NCMBUTTONDBLCLK, "WM_NCMBUTTONDBLCLK"},
  231. {(DWORD)WM_KEYFIRST, "WM_KEYFIRST"},
  232. {(DWORD)WM_KEYDOWN, "WM_KEYDOWN"},
  233. {(DWORD)WM_KEYUP, "WM_KEYUP"},
  234. {(DWORD)WM_CHAR, "WM_CHAR"},
  235. {(DWORD)WM_DEADCHAR, "WM_DEADCHAR"},
  236. {(DWORD)WM_SYSKEYDOWN, "WM_SYSKEYDOWN"},
  237. {(DWORD)WM_SYSKEYUP, "WM_SYSKEYUP"},
  238. {(DWORD)WM_SYSCHAR, "WM_SYSCHAR"},
  239. {(DWORD)WM_SYSDEADCHAR, "WM_SYSDEADCHAR"},
  240. {(DWORD)WM_KEYLAST, "WM_KEYLAST"},
  241. {(DWORD)WM_IME_STARTCOMPOSITION, "WM_IME_STARTCOMPOSITION"},
  242. {(DWORD)WM_IME_ENDCOMPOSITION, "WM_IME_ENDCOMPOSITION"},
  243. {(DWORD)WM_IME_COMPOSITION, "WM_IME_COMPOSITION"},
  244. {(DWORD)WM_IME_KEYLAST, "WM_IME_KEYLAST"},
  245. {(DWORD)WM_INITDIALOG, "WM_INITDIALOG"},
  246. {(DWORD)WM_COMMAND, "WM_COMMAND"},
  247. {(DWORD)WM_SYSCOMMAND, "WM_SYSCOMMAND"},
  248. {(DWORD)WM_TIMER, "WM_TIMER"},
  249. {(DWORD)WM_HSCROLL, "WM_HSCROLL"},
  250. {(DWORD)WM_VSCROLL, "WM_VSCROLL"},
  251. {(DWORD)WM_INITMENU, "WM_INITMENU"},
  252. {(DWORD)WM_INITMENUPOPUP, "WM_INITMENUPOPUP"},
  253. {(DWORD)WM_MENUSELECT, "WM_MENUSELECT"},
  254. {(DWORD)WM_MENUCHAR, "WM_MENUCHAR"},
  255. {(DWORD)WM_ENTERIDLE, "WM_ENTERIDLE"},
  256. {(DWORD)WM_CTLCOLORMSGBOX, "WM_CTLCOLORMSGBOX"},
  257. {(DWORD)WM_CTLCOLOREDIT, "WM_CTLCOLOREDIT"},
  258. {(DWORD)WM_CTLCOLORLISTBOX, "WM_CTLCOLORLISTBOX"},
  259. {(DWORD)WM_CTLCOLORBTN, "WM_CTLCOLORBTN"},
  260. {(DWORD)WM_CTLCOLORDLG, "WM_CTLCOLORDLG"},
  261. {(DWORD)WM_CTLCOLORSCROLLBAR, "WM_CTLCOLORSCROLLBAR"},
  262. {(DWORD)WM_CTLCOLORSTATIC, "WM_CTLCOLORSTATIC"},
  263. {(DWORD)WM_MOUSEFIRST, "WM_MOUSEFIRST"},
  264. {(DWORD)WM_MOUSEMOVE, "WM_MOUSEMOVE"},
  265. {(DWORD)WM_LBUTTONDOWN, "WM_LBUTTONDOWN"},
  266. {(DWORD)WM_LBUTTONUP, "WM_LBUTTONUP"},
  267. {(DWORD)WM_LBUTTONDBLCLK, "WM_LBUTTONDBLCLK"},
  268. {(DWORD)WM_RBUTTONDOWN, "WM_RBUTTONDOWN"},
  269. {(DWORD)WM_RBUTTONUP, "WM_RBUTTONUP"},
  270. {(DWORD)WM_RBUTTONDBLCLK, "WM_RBUTTONDBLCLK"},
  271. {(DWORD)WM_MBUTTONDOWN, "WM_MBUTTONDOWN"},
  272. {(DWORD)WM_MBUTTONUP, "WM_MBUTTONUP"},
  273. {(DWORD)WM_MBUTTONDBLCLK, "WM_MBUTTONDBLCLK"},
  274. {(DWORD)WM_MOUSELAST, "WM_MOUSELAST"},
  275. {(DWORD)WM_PARENTNOTIFY, "WM_PARENTNOTIFY"},
  276. {(DWORD)WM_ENTERMENULOOP, "WM_ENTERMENULOOP"},
  277. {(DWORD)WM_EXITMENULOOP, "WM_EXITMENULOOP"},
  278. {(DWORD)WM_NEXTMENU, "WM_NEXTMENU"},
  279. {(DWORD)WM_SIZING, "WM_SIZING"},
  280. {(DWORD)WM_CAPTURECHANGED, "WM_CAPTURECHANGED"},
  281. {(DWORD)WM_MOVING, "WM_MOVING"},
  282. {(DWORD)WM_POWERBROADCAST, "WM_POWERBROADCAST"},
  283. {(DWORD)WM_DEVICECHANGE, "WM_DEVICECHANGE"},
  284. {(DWORD)WM_IME_SETCONTEXT, "WM_IME_SETCONTEXT"},
  285. {(DWORD)WM_IME_NOTIFY, "WM_IME_NOTIFY"},
  286. {(DWORD)WM_IME_CONTROL, "WM_IME_CONTROL"},
  287. {(DWORD)WM_IME_COMPOSITIONFULL, "WM_IME_COMPOSITIONFULL"},
  288. {(DWORD)WM_IME_SELECT, "WM_IME_SELECT"},
  289. {(DWORD)WM_IME_CHAR, "WM_IME_CHAR"},
  290. {(DWORD)WM_IME_KEYDOWN, "WM_IME_KEYDOWN"},
  291. {(DWORD)WM_IME_KEYUP, "WM_IME_KEYUP"},
  292. {(DWORD)WM_MDICREATE, "WM_MDICREATE"},
  293. {(DWORD)WM_MDIDESTROY, "WM_MDIDESTROY"},
  294. {(DWORD)WM_MDIACTIVATE, "WM_MDIACTIVATE"},
  295. {(DWORD)WM_MDIRESTORE, "WM_MDIRESTORE"},
  296. {(DWORD)WM_MDINEXT, "WM_MDINEXT"},
  297. {(DWORD)WM_MDIMAXIMIZE, "WM_MDIMAXIMIZE"},
  298. {(DWORD)WM_MDITILE, "WM_MDITILE"},
  299. {(DWORD)WM_MDICASCADE, "WM_MDICASCADE"},
  300. {(DWORD)WM_MDIICONARRANGE, "WM_MDIICONARRANGE"},
  301. {(DWORD)WM_MDIGETACTIVE, "WM_MDIGETACTIVE"},
  302. {(DWORD)WM_MDISETMENU, "WM_MDISETMENU"},
  303. {(DWORD)WM_ENTERSIZEMOVE, "WM_ENTERSIZEMOVE"},
  304. {(DWORD)WM_EXITSIZEMOVE, "WM_EXITSIZEMOVE"},
  305. {(DWORD)WM_DROPFILES, "WM_DROPFILES"},
  306. {(DWORD)WM_MDIREFRESHMENU, "WM_MDIREFRESHMENU"},
  307. {(DWORD)WM_CUT, "WM_CUT"},
  308. {(DWORD)WM_COPY, "WM_COPY"},
  309. {(DWORD)WM_PASTE, "WM_PASTE"},
  310. {(DWORD)WM_CLEAR, "WM_CLEAR"},
  311. {(DWORD)WM_UNDO, "WM_UNDO"},
  312. {(DWORD)WM_RENDERFORMAT, "WM_RENDERFORMAT"},
  313. {(DWORD)WM_RENDERALLFORMATS, "WM_RENDERALLFORMATS"},
  314. {(DWORD)WM_DESTROYCLIPBOARD, "WM_DESTROYCLIPBOARD"},
  315. {(DWORD)WM_DRAWCLIPBOARD, "WM_DRAWCLIPBOARD"},
  316. {(DWORD)WM_PAINTCLIPBOARD, "WM_PAINTCLIPBOARD"},
  317. {(DWORD)WM_VSCROLLCLIPBOARD, "WM_VSCROLLCLIPBOARD"},
  318. {(DWORD)WM_SIZECLIPBOARD, "WM_SIZECLIPBOARD"},
  319. {(DWORD)WM_ASKCBFORMATNAME, "WM_ASKCBFORMATNAME"},
  320. {(DWORD)WM_CHANGECBCHAIN, "WM_CHANGECBCHAIN"},
  321. {(DWORD)WM_HSCROLLCLIPBOARD, "WM_HSCROLLCLIPBOARD"},
  322. {(DWORD)WM_QUERYNEWPALETTE, "WM_QUERYNEWPALETTE"},
  323. {(DWORD)WM_PALETTEISCHANGING, "WM_PALETTEISCHANGING"},
  324. {(DWORD)WM_PALETTECHANGED, "WM_PALETTECHANGED"},
  325. {(DWORD)WM_HOTKEY, "WM_HOTKEY"},
  326. {(DWORD)WM_PRINT, "WM_PRINT"},
  327. {(DWORD)WM_PRINTCLIENT, "WM_PRINTCLIENT"},
  328. {(DWORD)WM_HANDHELDFIRST, "WM_HANDHELDFIRST"},
  329. {(DWORD)WM_HANDHELDLAST, "WM_HANDHELDLAST"},
  330. {(DWORD)WM_AFXFIRST, "WM_AFXFIRST"},
  331. {(DWORD)WM_AFXLAST, "WM_AFXLAST"},
  332. {(DWORD)WM_PENWINFIRST, "WM_PENWINFIRST"},
  333. {(DWORD)WM_PENWINLAST, "WM_PENWINLAST"},
  334. {(DWORD)WM_APP, "WM_APP"}
  335. };
  336. // release + asserts build has no memory checking
  337. #ifndef _RELEASE_ASSERTS_
  338. void DlgDisplayVrgmst(HWND hListMemory)
  339. {
  340. char szTemp[300];
  341. int cbTotal = 0;
  342. for(int imst = 0; vrgmst[imst].szFile != 0; imst++)
  343. {
  344. cbTotal += vrgmst[imst].cbAlloc;
  345. wsprintfA(szTemp, "%6.d %s", vrgmst[imst].cbAlloc, vrgmst[imst].szFile);
  346. SendMessage(hListMemory, LB_ADDSTRING, 0, (LPARAM) szTemp);
  347. }
  348. wsprintfA(szTemp, "%6.d %s", cbTotal, "--- Total ---");
  349. SendMessage(hListMemory, LB_ADDSTRING, 0, (LPARAM) szTemp);
  350. }
  351. HFONT hf = 0;
  352. INT_PTR CALLBACK FDlgRicheditDebugCentral(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam)
  353. {
  354. HWND hListMemory;
  355. switch (message)
  356. {
  357. case WM_INITDIALOG:
  358. hListMemory = GetDlgItem(hdlg, IDC_MEMORY_STATISTICS);
  359. LOGFONTA lf;
  360. ZeroMemory(&lf, sizeof(lf));
  361. lf.lfHeight = 14;
  362. memcpy(lf.lfFaceName, "Courier New", 12);
  363. hf = CreateFontIndirectA(&lf);
  364. SendMessage(hListMemory, WM_SETFONT, (WPARAM)hf, FALSE);
  365. UpdateMst();
  366. DlgDisplayVrgmst(hListMemory);
  367. return FALSE;
  368. case WM_COMMAND:
  369. switch (wParam)
  370. {
  371. case IDOK:
  372. EndDialog(hdlg, IDOK);
  373. return TRUE;
  374. case IDCANCEL:
  375. EndDialog(hdlg, IDCANCEL);
  376. return TRUE;
  377. }
  378. break;
  379. }
  380. return FALSE;
  381. }
  382. void RicheditDebugCentral(void)
  383. {
  384. DialogBoxA(hinstRE, MAKEINTRESOURCEA(IDD_DEBUG), NULL, FDlgRicheditDebugCentral);
  385. DeleteObject(hf);
  386. }
  387. #endif //!_RELEASE_ASSERTS_
  388. /*
  389. * DebugMain
  390. *
  391. * @mfunc
  392. * Dll entry point. See Win32 SDK documentation for details.
  393. * hDLL - handle of DLL
  394. * dwReason - indicates why DLL called
  395. * lpReserved - reserved
  396. *
  397. * @rdesc
  398. * TRUE (always)
  399. *
  400. */
  401. BOOL WINAPI DebugMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
  402. {
  403. switch (dwReason)
  404. {
  405. case DLL_PROCESS_ATTACH:
  406. {
  407. //
  408. // DLL is attaching to the address space of the current process.
  409. //
  410. ghMod = hDLL;
  411. TlsIndex = TlsAlloc();
  412. TlsSetValue(TlsIndex, (LPVOID)-1);
  413. InitializeCriticalSection(&csLog);
  414. InitializeCriticalSection(&csAssert);
  415. //Create a separate thread to handle asserts.
  416. //We use events to halt the the asserting thread
  417. //during an assert, and to halt the assert thread the rest of
  418. //the time. Note that these are autoreset events.
  419. hEventAssert1= CreateEventA(NULL, FALSE, FALSE, NULL);
  420. hEventAssert2= CreateEventA(NULL, FALSE, FALSE, NULL);
  421. INITDEBUGSERVICES(OPTUSEDEFAULTS, NULL, NULL);
  422. break;
  423. }
  424. case DLL_THREAD_ATTACH:
  425. {
  426. //
  427. // A new thread is being created in the current process.
  428. //
  429. TlsSetValue(TlsIndex, (LPVOID)-1);
  430. break;
  431. }
  432. case DLL_THREAD_DETACH:
  433. {
  434. //
  435. // A thread is exiting cleanly.
  436. //
  437. break;
  438. }
  439. case DLL_PROCESS_DETACH:
  440. {
  441. //
  442. // The calling process is detaching the DLL from its address space.
  443. //
  444. fDllDetach = TRUE;
  445. //Clean up after ourselves.
  446. TlsFree(TlsIndex);
  447. SETLOGGING(FALSE);
  448. //Clean up the assert thread stuff.
  449. if (NULL != hAssertThrd)
  450. TerminateThread(hAssertThrd, 0);
  451. if (NULL != hEventAssert1)
  452. CloseHandle(hEventAssert1);
  453. if (NULL != hEventAssert2)
  454. CloseHandle(hEventAssert2);
  455. DeleteCriticalSection(&csLog);
  456. DeleteCriticalSection(&csAssert);
  457. break;
  458. }
  459. }
  460. return TRUE;
  461. }
  462. //This is not in release asserts build
  463. #ifndef _RELEASE_ASSERTS_
  464. /*
  465. * SetLogging
  466. *
  467. * @mfunc
  468. * This function starts and stops logging of output from
  469. * the debug services. If logging is being started, it
  470. * creates a new file for logging (path and name specified
  471. * in win.ini). fStartLog is TRUE and logging is already
  472. * on, or fStartLog is FALSE and logging is off, this
  473. * nothing happens.
  474. *
  475. * fStartLog - TRUE to start logging, FALSE to stop logging.
  476. *
  477. */
  478. void WINAPI SetLogging(BOOL fStartLog)
  479. {
  480. //Don't start logging if it's already on.
  481. if (fStartLog && !fLogging)
  482. {
  483. char szLogFile[MAX_PATH];
  484. //Set option flag telling everyone we're on
  485. dwDebugOptions |= OPTLOGGINGON;
  486. //Get file name
  487. GetProfileStringA("RICHEDIT DEBUG", "LOGFILE", "", szLogFile, MAX_PATH);
  488. //Create new file
  489. hLogFile = CreateFileA(szLogFile, GENERIC_READ | GENERIC_WRITE,
  490. FILE_SHARE_READ | FILE_SHARE_WRITE,
  491. NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  492. //If we didn't succed creating the file, reset flags and tell user.
  493. if (INVALID_HANDLE_VALUE == hLogFile)
  494. {
  495. dwDebugOptions &= ~OPTLOGGINGON;
  496. MessageBoxA(NULL, "Unable to open log file.", "Richedit Debug", MB_OK);
  497. }
  498. }
  499. //Don't stop logging if it's not on.
  500. else if (!fStartLog && fLogging)
  501. {
  502. //Set option flag telling everyone we're off, and close file.
  503. dwDebugOptions &= ~OPTLOGGINGON;
  504. CloseHandle(hLogFile);
  505. }
  506. }
  507. #endif //!_RELEASE_ASSERTS_
  508. /*
  509. * InitDebugServices
  510. *
  511. * @mfunc
  512. * This function initializes the options for the debug
  513. * services. If this function is not called, all optional
  514. * debug services are left off by default.
  515. * If OPTUSEDEFAULTS is specified for dwOpts, options are
  516. * loaded from win.ini, otherwise the caller specified
  517. * options are set. If the caller wishes to specify options
  518. * they must specify all options they want turned on. Any
  519. * options not explicitly specified will be turned off.
  520. * The function also takes a pointer to an assert hook
  521. * function and a trace hook function.
  522. *
  523. * dwOpts - Debug options to be set.
  524. * pfnAssertHook - Pointer to assert hook function (NULL if none).
  525. * pfnTraceHook - Pointer to trace hook function (NULL if none).
  526. *
  527. */
  528. DllExport void WINAPI InitDebugServices(DWORD dwOpts,
  529. PFNASSERTHOOK pfnAssertHook, PFNTRACEHOOK pfnTraceHook)
  530. {
  531. // Check to see if OPTUSEDEFAULTS was specified. If so, get
  532. // values from win.ini. Otherwise, set options to values
  533. // specified by caller.
  534. if (dwOpts & OPTUSEDEFAULTS)
  535. {
  536. SETLOGGING(GetProfileIntA("RICHEDIT DEBUG", "LOGGING", 0));
  537. SETVERBOSE(GetProfileIntA("RICHEDIT DEBUG", "VERBOSE", 0));
  538. SETINFO(GetProfileIntA("RICHEDIT DEBUG", "INFO", 0));
  539. SETMEMORY(GetProfileIntA("RICHEDIT DEBUG", "MEMORY", 0));
  540. SETTRACING(GetProfileIntA("RICHEDIT DEBUG", "TRACE", 0));
  541. SETTRACEEXT(GetProfileIntA("RICHEDIT DEBUG", "TRACEEXT", 0));
  542. SETOPT(OPTTRACEDISP, GetProfileIntA("RICHEDIT DEBUG", "TRACEDISP", 0));
  543. SETOPT(OPTTRACEWRAP, GetProfileIntA("RICHEDIT DEBUG", "TRACEWRAP", 0));
  544. SETOPT(OPTTRACEEDIT, GetProfileIntA("RICHEDIT DEBUG", "TRACEEDIT", 0));
  545. SETOPT(OPTTRACETS, GetProfileIntA("RICHEDIT DEBUG", "TRACETS", 0));
  546. SETOPT(OPTTRACETOM, GetProfileIntA("RICHEDIT DEBUG", "TRACETOM", 0));
  547. SETOPT(OPTTRACEOLE, GetProfileIntA("RICHEDIT DEBUG", "TRACEOLE", 0));
  548. SETOPT(OPTTRACEBACK, GetProfileIntA("RICHEDIT DEBUG", "TRACEBACK", 0));
  549. SETOPT(OPTTRACESEL, GetProfileIntA("RICHEDIT DEBUG", "TRACESEL", 0));
  550. SETOPT(OPTTRACEHOST, GetProfileIntA("RICHEDIT DEBUG", "TRACEHOST", 0));
  551. SETOPT(OPTTRACEDTE, GetProfileIntA("RICHEDIT DEBUG", "TRACEDTE", 0));
  552. SETOPT(OPTTRACEUNDO, GetProfileIntA("RICHEDIT DEBUG", "TRACEUNDO", 0));
  553. SETOPT(OPTTRACERANG, GetProfileIntA("RICHEDIT DEBUG", "TRACERANG", 0));
  554. SETOPT(OPTTRACEUTIL, GetProfileIntA("RICHEDIT DEBUG", "TRACEUTIL", 0));
  555. SETOPT(OPTTRACENOTM, GetProfileIntA("RICHEDIT DEBUG", "TRACENOTM", 0));
  556. SETOPT(OPTTRACERTFR, GetProfileIntA("RICHEDIT DEBUG", "TRACERTFR", 0));
  557. SETOPT(OPTTRACERTFW, GetProfileIntA("RICHEDIT DEBUG", "TRACERTFW", 0));
  558. SETOPT(OPTTRACEPRT, GetProfileIntA("RICHEDIT DEBUG", "TRACEPRT", 0));
  559. SETOPT(OPTTRACEFE, GetProfileIntA("RICHEDIT DEBUG", "TRACEFE", 0));
  560. SETOPT(OPTTRACEFONT, GetProfileIntA("RICHEDIT DEBUG", "TRACEFONT", 0));
  561. }
  562. else
  563. {
  564. //Set up logging before we set dwDebugOptions because
  565. //SetLogging will not turn logging on if the flag
  566. //indicates it is already on.
  567. SETLOGGING(dwOpts & OPTLOGGINGON);
  568. dwDebugOptions = dwOpts;
  569. }
  570. SETASSERTFN(pfnAssertHook);
  571. SETTRACEFN(pfnTraceHook);
  572. }
  573. /*
  574. * AssertProc
  575. *
  576. * @mfunc
  577. * This is the dialog proc for the assert message.
  578. / *
  579. * lParam - The string to display in the dialog.
  580. *
  581. */
  582. INT_PTR CALLBACK AssertProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
  583. {
  584. switch (message)
  585. {
  586. case WM_INITDIALOG:
  587. {
  588. RECT rcDlg, rcDesk;
  589. GetWindowRect(hwndDlg, &rcDlg);
  590. GetWindowRect(GetDesktopWindow(), &rcDesk);
  591. SetWindowPos(hwndDlg, HWND_TOP,
  592. ((rcDesk.right - rcDesk.left ) - (rcDlg.right - rcDlg.left))/2,
  593. ((rcDesk.bottom - rcDesk.top ) - (rcDlg.bottom - rcDlg.top))/2,
  594. 0, 0, SWP_NOSIZE);
  595. if (NULL != lParam)
  596. SetDlgItemTextA(hwndDlg, IDC_MSG, (LPSTR)lParam);
  597. //Sometimes we don't always end up on top. I don't know why.
  598. SetForegroundWindow(hwndDlg);
  599. }
  600. break;
  601. case WM_COMMAND:
  602. //Kill dialog and return button id that was pressed.
  603. EndDialog(hwndDlg, LOWORD(wParam));
  604. break;
  605. default:
  606. return FALSE;
  607. }
  608. return TRUE;
  609. }
  610. /*
  611. * AssertThread
  612. *
  613. * @mfunc
  614. * This is the entry point for the thread created for the
  615. * assert dialog.
  616. *
  617. * lParam - Data passed to thread...not used.
  618. *
  619. * @rdesc
  620. * Should not return. It will be explicitly terminated.
  621. *
  622. */
  623. DWORD WINAPI AssertThread(LPVOID lParam)
  624. {
  625. //This should run until it is explicitly terminated in
  626. //process detach.
  627. while(TRUE)
  628. {
  629. //We go into a wait state until the event is signaled,
  630. //which means we are handling an assert.
  631. WaitForSingleObject(hEventAssert1, INFINITE);
  632. idAssert = DialogBoxParamA(ghMod, MAKEINTRESOURCEA(IDD_ASSERT),
  633. NULL, AssertProc, (LPARAM)szAssert);
  634. //The asserting thread will be waiting on this event so
  635. //set it to allow the asserting thread continue.
  636. SetEvent(hEventAssert2);
  637. }
  638. return 0;
  639. }
  640. /*
  641. * AssertSzFn
  642. *
  643. * @mfunc
  644. * Display a message for the user and give the
  645. * option to abort, ignore, or ignore all.
  646. * Selecting ignore all causes all asserts to be
  647. * ignored from that time forward. It cannot be
  648. * reset. If the assert dialog cannot be created
  649. * A message box is used. The message box has one
  650. * button (OK) which will cause an abort.
  651. *
  652. * szFile - the file the warning occured in.
  653. * iLine - the line number the warning occured at.
  654. * szUserMsg - User define message string
  655. *
  656. */
  657. void AssertSzFn(LPSTR szUserMsg, LPSTR szFile, int iLine)
  658. {
  659. char szModuleName[MAX_PATH];
  660. char * pszModuleName;
  661. DWORD pid;
  662. DWORD tid;
  663. DWORD dwAssertTID;
  664. //Check to see if an assert hook has been set. If it has, call
  665. //it with pointers to all our parameters (they can be modified
  666. //this way if desired). If the hook returns false, return.
  667. //Otherwise, continue with our assert with the potentially
  668. //modified parameters.
  669. if (NULL != pfnAssert)
  670. if (!pfnAssert(szUserMsg, szFile, &iLine))
  671. return;
  672. if( NULL == hAssertThrd )
  673. {
  674. if( NULL != hEventAssert1 && NULL != hEventAssert2)
  675. {
  676. hAssertThrd = CreateThread(NULL, 0, AssertThread,
  677. NULL, 0, &dwAssertTID);
  678. }
  679. }
  680. //This critical section will prevent us from being entered simultaneously
  681. //by multiple threads. This alone will not prevent reentrance by our own thread
  682. //once the assert dialog is up. Under normal circumstances a special thread
  683. //exists to run the assert dialog and Event objects are used to halt this
  684. //thread while the assert dialog is up (see WaitForSingleObject
  685. //further down). If the assert thread does not exist, a MessageBox is used
  686. //and we can be reentered (this is a fallback position and there's
  687. //not much we can do about it).
  688. EnterCriticalSection(&csAssert);
  689. pid = GetCurrentProcessId();
  690. tid = GetCurrentThreadId();
  691. //Get the module name to include in assert message.
  692. if (GetModuleFileNameA(NULL, szModuleName, MAX_PATH))
  693. {
  694. pszModuleName = strrchr(szModuleName, '\\');
  695. if (!pszModuleName)
  696. {
  697. pszModuleName = szModuleName;
  698. }
  699. else
  700. {
  701. pszModuleName++;
  702. }
  703. }
  704. else
  705. {
  706. pszModuleName = "Unknown";
  707. }
  708. //Send a message to the debug output and build a string for the
  709. //assert dialog. The string depends on whether the user provided
  710. //a message.
  711. if (NULL != szUserMsg)
  712. {
  713. TRACEASSERTSZ(szUserMsg, szFile, iLine);
  714. sprintf(szAssert,
  715. "PROCESS: %s, PID: %d, TID: %d\nFILE: %s (%d)\n%s\n",
  716. pszModuleName, pid, tid, szFile, iLine, szUserMsg);
  717. }
  718. else
  719. {
  720. TRACEASSERT(szFile, iLine);
  721. sprintf(szAssert,
  722. "PROCESS: %s, PID: %d, TID: %d\nFILE: %s (%d)\n",
  723. pszModuleName, pid, tid, szFile, iLine);
  724. }
  725. //If the user did not disable asserts on a previous assert,
  726. //put up a dialog with the assert message.
  727. if (!fIgnoreAsserts)
  728. {
  729. idAssert = -1;
  730. //If we are in the middle of process detach, the assert thread
  731. //will not execute so pop the dialog here ourselves. Presumably there
  732. //is little change of reentrancy at this point. If we are not
  733. //in process detach, let the assert thread handle the assert.
  734. if (fDllDetach)
  735. {
  736. idAssert = DialogBoxParamA(ghMod, MAKEINTRESOURCEA(IDD_ASSERT),
  737. NULL, AssertProc, (LPARAM)szAssert);
  738. }
  739. else
  740. {
  741. SetEvent(hEventAssert1);
  742. WaitForSingleObject(hEventAssert2, INFINITE);
  743. }
  744. //The assert thread doesn't exist or the dialogbox create failed so
  745. //use a message box instead. In this case, since we
  746. //are obviously having problems, we are only going to
  747. //give the user one choice...abort.
  748. if (-1 == idAssert)
  749. {
  750. idAssert = MessageBoxA(NULL,
  751. szAssert,
  752. "Richedit Assert - (retry will be ignored)",
  753. MB_SETFOREGROUND | MB_TASKMODAL |
  754. MB_ICONEXCLAMATION | MB_ABORTRETRYIGNORE);
  755. //
  756. // If id == 0, then an error occurred. There are two possibilities
  757. // that can cause the error: Access Denied, which means that this
  758. // process does not have access to the default desktop, and everything
  759. // else (usually out of memory).
  760. //
  761. if (!idAssert)
  762. {
  763. if (GetLastError() == ERROR_ACCESS_DENIED)
  764. {
  765. //
  766. // Retry this one with the SERVICE_NOTIFICATION flag on. That
  767. // should get us to the right desktop.
  768. //
  769. idAssert = MessageBoxA( NULL,
  770. szAssert,
  771. "Richedit Assert - (retry will be ignored)",
  772. MB_SETFOREGROUND | MB_TASKMODAL | MB_ICONEXCLAMATION |
  773. MB_ABORTRETRYIGNORE);
  774. }
  775. }
  776. }
  777. if (idAssert == ID_IGNOREALL)
  778. {
  779. fIgnoreAsserts = TRUE;
  780. }
  781. if (idAssert == IDABORT )
  782. {
  783. //This will cause a break when debugging, and
  784. //an exception leading to termination otherwise.
  785. DebugBreak();
  786. return;
  787. }
  788. }
  789. LeaveCriticalSection(&csAssert);
  790. }
  791. /*
  792. * TabLookup
  793. *
  794. * @mfunc
  795. * This function searches an array of TabElem
  796. * structures looking for an entry whose key
  797. * matches the one we were given. If found, it
  798. * copies the string associated with the key into
  799. * the supplied buffer.
  800. *
  801. * Table - TabElem pointer to start of array.
  802. * TabSize - Size of array in bytes.
  803. * dwKey - Key to match.
  804. * szBuf - Buffer to hold string (assumed MAXDEBUGSTRLEN in size).
  805. *
  806. * @rdesc
  807. * FALSE if key not found, TRUE if found.
  808. *
  809. */
  810. BOOL TabLookup(TabElem * Table, UINT TabSize, DWORD dwKey, LPSTR szBuf)
  811. {
  812. BOOL fRet = FALSE;
  813. UINT cTab, index;
  814. cTab = TabSize/sizeof(TabElem);
  815. for (index = 0; index < cTab; index++)
  816. {
  817. if (Table[index].dwKey == dwKey)
  818. break;
  819. }
  820. if (index < cTab)
  821. {
  822. lstrcpyA(szBuf, Table[index].sz);
  823. fRet = TRUE;
  824. }
  825. return fRet;
  826. }
  827. /*
  828. * GetHResultSz
  829. *
  830. * @mfunc
  831. * This function fills a buffer with a string associated
  832. * with a given HRESULT. This string can then be used
  833. * in the output from TraceMsg.
  834. *
  835. * hr - HRESULT on which the string will be based.
  836. * szBuf - Buffer to hold string (MAXDEBUGSTRLEN in size).
  837. *
  838. */
  839. void GetHResultSz(HRESULT hr, LPSTR szBuf)
  840. {
  841. // Build string based on FormatMessageA
  842. if (!FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, (DWORD)hr,
  843. MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
  844. szBuf, MAXDEBUGSTRLEN, NULL))
  845. {
  846. // Build default string
  847. sprintf(szBuf, "hr = %d: Unrecognized HRESULT.", hr);
  848. }
  849. else
  850. {
  851. int cch;
  852. char * pch;
  853. //Need to get rid of the CRLF from FormatMessageA.
  854. pch = szBuf;
  855. cch = strlen(szBuf);
  856. pch += (cch - 2);
  857. *pch = '\0';
  858. }
  859. }
  860. /*
  861. * GetParamSz
  862. *
  863. * @mfunc
  864. * This function fills a buffer with a string associated
  865. * with a param from the text message handler.
  866. * This string can then be used in the output from
  867. * TraceMsg.
  868. *
  869. * dwParam - param on which the string will be based.
  870. * szBuf - Buffer to hold string (MAXDEBUGSTRLEN in size).
  871. */
  872. void GetParamSz(DWORD dwParam, LPSTR szBuf)
  873. {
  874. char szTemp[MAXDEBUGSTRLEN];
  875. if (!TabLookup(TrcParamTab, sizeof(TrcParamTab), (DWORD)dwParam, szTemp))
  876. {
  877. sprintf(szBuf, "PARAM = %d: Unrecognized PARAM.", dwParam);
  878. }
  879. else
  880. {
  881. sprintf(szBuf, "PARAM: %s", szTemp);
  882. }
  883. }
  884. /*
  885. * GetDefaultSz
  886. *
  887. * @mfunc
  888. * This function fills a buffer with a string associated
  889. * with either the value from GetLastError, or with a
  890. * default string. This string can then be used in the
  891. * output from TraceMsg.
  892. *
  893. * dwError - Value from GetLastError.
  894. * szBuf - Buffer to hold string (MAXDEBUGSTRLEN in size).
  895. *
  896. */
  897. void GetDefaultSz(DWORD dwError, LPSTR szBuf)
  898. {
  899. //Check to see if we have an error value
  900. if (dwError)
  901. {
  902. // Build string based on FormatMessageA
  903. if (!FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,
  904. MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
  905. szBuf, MAXDEBUGSTRLEN, NULL))
  906. {
  907. // Build default string
  908. lstrcpyA(szBuf, "Reason unknown.");
  909. }
  910. else
  911. {
  912. int cch;
  913. char * pch;
  914. //Need to get rid of the CRLF from FormatMessageA.
  915. pch = szBuf;
  916. cch = strlen(szBuf);
  917. pch += (cch - 2);
  918. *pch = '\0';
  919. }
  920. }
  921. else
  922. {
  923. // Build default string
  924. lstrcpyA(szBuf, "Reason unknown.");
  925. }
  926. }
  927. //The following are not used by the release with asserts build
  928. #ifndef _RELEASE_ASSERTS_
  929. /*
  930. * GetDataSz
  931. *
  932. * @mfunc
  933. * This function fills a buffer with a string representing
  934. * data passed to TraceMsg in one of it's DWORDS data
  935. * parameters. This string can then be used in the
  936. * output from TraceMsg.
  937. *
  938. * uDataType - This is the type of data we are dealing with.
  939. * dwData - This is the data itself.
  940. * szBuf - Buffer to hold string (MAXDEBUGSTRLEN in size).
  941. *
  942. */
  943. void GetDataSz(UINT uDataType, DWORD dwData, LPSTR szBuf)
  944. {
  945. switch (uDataType)
  946. {
  947. // Data is an HRESULT
  948. case TRCDATAHRESULT:
  949. GetHResultSz((HRESULT)dwData, szBuf);
  950. break;
  951. // Data is a string (copy to szBuf and pass it through)
  952. case TRCDATASTRING:
  953. lstrcpyA(szBuf, (LPSTR)(DWORD_PTR)dwData);
  954. break;
  955. // Data is a parameter value
  956. case TRCDATAPARAM:
  957. GetParamSz(dwData, szBuf);
  958. break;
  959. // Get string based on GetLastError
  960. case TRCDATADEFAULT:
  961. default:
  962. GetDefaultSz(dwData, szBuf);
  963. break;
  964. }
  965. }
  966. /*
  967. * LogDebugString
  968. *
  969. * @mfunc
  970. * This function writes a string to the log file. The file must
  971. * be opened already and hLogFile must contain the handle.
  972. *
  973. * szDebugMsg - String to write to log file.
  974. *
  975. */
  976. void LogDebugString(LPSTR szDebugMsg)
  977. {
  978. if ((NULL != hLogFile) && (INVALID_HANDLE_VALUE != hLogFile))
  979. {
  980. DWORD dwMsgBytes, dwBytes;
  981. dwMsgBytes = strlen(szDebugMsg)*sizeof(char);
  982. //Prevent other threads from trying to write at same time.
  983. EnterCriticalSection(&csLog);
  984. SetFilePointer(hLogFile, 0, NULL, FILE_END);
  985. WriteFile (hLogFile, szDebugMsg, dwMsgBytes, &dwBytes, NULL);
  986. LeaveCriticalSection(&csLog);
  987. }
  988. }
  989. /*
  990. * TraceMsg
  991. *
  992. * @mfunc
  993. * This is the central message generating facility for
  994. * the debug tools. All messages to the debug output
  995. * or log file are generated here. This function takes
  996. * a DWORD (dwFlags) that consists of packed values that determine
  997. * the kind of message to generated. It takes two DWORD
  998. * data parameters that can contain several different
  999. * types of data (string, HRESULT, etc.) These are interpreted
  1000. * using dwFlags. It also takes the file and line associated with
  1001. * the point in the source where it was called.
  1002. *
  1003. * dwFlags - Packed values tell us how to generate the message.
  1004. * dwData1 - The first of two data parameters.
  1005. * dwData2 - The second of two data parameters.
  1006. * szFile - File name we were called from.
  1007. * iLine - Line number we were called from.
  1008. *
  1009. */
  1010. void TraceMsg(DWORD dwFlags, DWORD dwData1, DWORD dwData2,
  1011. LPSTR szFile, int iLine)
  1012. {
  1013. //The following three buffers are used to build our message.
  1014. char szTemp[MAXDEBUGSTRLEN];
  1015. char szTemp2[MAXDEBUGSTRLEN];
  1016. char szDebugMsg[MAXDEBUGSTRLEN];
  1017. char* pch;
  1018. int cch;
  1019. TrcFlags trcf; //Used to decode dwFlags
  1020. DWORD pid;
  1021. DWORD tid;
  1022. DWORD dwError;
  1023. int indent, tls;
  1024. //Check to see if a Trace hook has been set. If it has, call
  1025. //it with pointers to all our parameters (they can be modified
  1026. //this way if desired). If the hook returns false, return.
  1027. //Otherwise, continue with our message output with the potentially
  1028. //modified parameters.
  1029. if (NULL != pfnTrace)
  1030. if (!pfnTrace(&dwFlags, &dwData1, &dwData2, szFile, &iLine))
  1031. return;
  1032. trcf.dw = dwFlags;
  1033. //Return if this is an informational message and they are disabled.
  1034. if ((TRCSEVINFO == trcf.fields.uSeverity) && !fInfo)
  1035. return;
  1036. // Call GetLastError now in case we need it later.
  1037. // This way api calls downstream won't disturb the value
  1038. // we need.
  1039. dwError = GetLastError();
  1040. pid = GetCurrentProcessId();
  1041. tid = GetCurrentThreadId();
  1042. szTemp[0] = '\0';
  1043. szTemp2[0] = '\0';
  1044. szDebugMsg[0] = '\0';
  1045. // Handle indentation (TLSindent is set by CTrace)
  1046. tls = (int)(DWORD_PTR)TlsGetValue(TlsIndex);
  1047. indent = (tls < 0 ? 0 : tls);
  1048. memset(szDebugMsg, ' ', 2*indent*sizeof(char));
  1049. szDebugMsg[2*indent] = '\0';
  1050. // Handle severity (Warning, Error, etc.)
  1051. if (TRCSEVNONE != trcf.fields.uSeverity)
  1052. {
  1053. sprintf(szTemp, "%s: ", TrcSeverity[trcf.fields.uSeverity]);
  1054. strcat(szDebugMsg, szTemp);
  1055. }
  1056. // Interpret the first data value
  1057. if (TRCDATANONE != trcf.fields.uData1)
  1058. {
  1059. if (TRCDATADEFAULT == trcf.fields.uData1)
  1060. dwData1 = dwError;
  1061. GetDataSz(trcf.fields.uData1, dwData1, szTemp2);
  1062. lstrcpyA(szTemp, szDebugMsg);
  1063. wsprintfA(szDebugMsg, "%s%s ", szTemp, szTemp2);
  1064. }
  1065. // Interpret the second data value.
  1066. if (TRCDATANONE != trcf.fields.uData2)
  1067. {
  1068. if (TRCDATADEFAULT == trcf.fields.uData2)
  1069. dwData2 = dwError;
  1070. GetDataSz(trcf.fields.uData2, dwData2, szTemp2);
  1071. lstrcpyA(szTemp, szDebugMsg);
  1072. wsprintfA(szDebugMsg, "%s%s", szTemp, szTemp2);
  1073. }
  1074. if (fVerbose)
  1075. {
  1076. // Handle scope (Internal/External call)
  1077. if (TRCSCOPENONE != trcf.fields.uScope)
  1078. {
  1079. sprintf(szTemp, "SCOPE: %s ", TrcScope[trcf.fields.uScope]);
  1080. strcat(szDebugMsg, szTemp);
  1081. }
  1082. // Handle subsytem (TOM, ITextServices, etc.)
  1083. if (TRCSUBSYSNONE != trcf.fields.uSubSystem)
  1084. {
  1085. sprintf(szTemp, "SUBSYSTEM: %s ", TrcSubsys[trcf.fields.uSubSystem]);
  1086. strcat(szDebugMsg, szTemp);
  1087. }
  1088. // Handle process ID, thread ID, file and line.
  1089. sprintf(szTemp, "PID: %u TID: %u ", pid, tid);
  1090. strcat(szDebugMsg, szTemp);
  1091. }
  1092. // Up to now there is no real danger of overflowing our buffer since
  1093. // we were dealing with strings of small size. Now we will be running
  1094. // in to paths and user strings. We will use _snprintf to concatonate
  1095. // new stuff to our message. This is not the most effecient way since
  1096. // it involves alot of copying, but it is a fairly simple way to keep
  1097. // adding to our string without having to worry about how much room is
  1098. // left in the buffer. It will truncate if we go past the end.
  1099. if (NULL != szFile)
  1100. {
  1101. lstrcpyA(szTemp, szDebugMsg);
  1102. if (0 != iLine)
  1103. {
  1104. wsprintfA(szDebugMsg, "%sFILE: %s (%u) ",
  1105. szTemp, szFile, iLine);
  1106. }
  1107. else
  1108. {
  1109. wsprintfA(szDebugMsg, "%sFILE: %s ",
  1110. szTemp, szFile);
  1111. }
  1112. }
  1113. // Append a CRLF to the end of the string (make sure we don't overflow)
  1114. cch = strlen(szDebugMsg);
  1115. pch = szDebugMsg;
  1116. if (cch < (MAXDEBUGSTRLEN - 3))
  1117. pch += cch;
  1118. else
  1119. pch += (MAXDEBUGSTRLEN - 3);
  1120. lstrcpyA(pch, "\r\n");
  1121. if (fLogging)
  1122. LogDebugString(szDebugMsg);
  1123. // Write to debug output.
  1124. OutputDebugStringA(szDebugMsg);
  1125. }
  1126. /*
  1127. * Tracef
  1128. *
  1129. * @mfunc:
  1130. * The given format string and parameters are used to render a
  1131. * string into a buffer. This string is passed to TraceMsg.
  1132. * The severity parameter determines the type of message. The
  1133. * following values are valid: TRCSEVWARN, TRCSEVERR, TRCSEVINFO.
  1134. *
  1135. * Arguments:
  1136. * dwSev Severity of message.
  1137. * szFmt Format string for wvsprintf (qqv)
  1138. */
  1139. void Tracef(DWORD dwSev, LPSTR szFmt, ...)
  1140. {
  1141. va_list valMarker;
  1142. char rgchTraceTagBuffer[MAXDEBUGSTRLEN];
  1143. // format out a string
  1144. va_start(valMarker, szFmt);
  1145. wvsprintfA(rgchTraceTagBuffer, szFmt, valMarker);
  1146. va_end(valMarker);
  1147. if (dwSev == TRCSEVERR)
  1148. TraceMsg(MAKEFLAGS(TRCSUBSYSNONE, TRCSEVERR, TRCSCOPENONE,
  1149. TRCDATASTRING, TRCDATANONE), (DWORD)(DWORD_PTR)(rgchTraceTagBuffer),
  1150. (DWORD)0, NULL, 0);
  1151. else if (dwSev == TRCSEVWARN)
  1152. TraceMsg(MAKEFLAGS(TRCSUBSYSNONE, TRCSEVWARN, TRCSCOPENONE,
  1153. TRCDATASTRING, TRCDATANONE), (DWORD)(DWORD_PTR)(rgchTraceTagBuffer),
  1154. (DWORD)0, NULL, 0);
  1155. else if (dwSev == TRCSEVINFO)
  1156. TraceMsg(MAKEFLAGS(TRCSUBSYSNONE, TRCSEVINFO, TRCSCOPENONE,
  1157. TRCDATASTRING, TRCDATANONE), (DWORD)(DWORD_PTR)(rgchTraceTagBuffer),
  1158. (DWORD)0, NULL, 0);
  1159. else if (dwSev == TRCSEVMEM)
  1160. TraceMsg(MAKEFLAGS(TRCSUBSYSNONE, TRCSEVMEM, TRCSCOPENONE,
  1161. TRCDATASTRING, TRCDATANONE), (DWORD)(DWORD_PTR)(rgchTraceTagBuffer),
  1162. (DWORD)0, NULL, 0);
  1163. else
  1164. TraceMsg(MAKEFLAGS(TRCSUBSYSNONE, TRCSEVNONE, TRCSCOPENONE,
  1165. TRCDATASTRING, TRCDATANONE), (DWORD)(DWORD_PTR)(rgchTraceTagBuffer),
  1166. (DWORD)0, NULL, 0);
  1167. }
  1168. /*
  1169. * TraceError
  1170. *
  1171. * @mfunc:
  1172. * This function is for compatibility with old debug functionality.
  1173. * An error message is generated and sent to TraceMsg.
  1174. *
  1175. */
  1176. void TraceError(LPSTR sz, LONG sc)
  1177. {
  1178. if (FAILED(sc))
  1179. {
  1180. char rgchTraceTagBuffer[MAXDEBUGSTRLEN];
  1181. wsprintfA(rgchTraceTagBuffer,
  1182. "%s, error=%ld (%#08lx).", sz, sc, sc);
  1183. TraceMsg(MAKEFLAGS(TRCSUBSYSNONE, TRCSEVERR, TRCSCOPENONE,
  1184. TRCDATASTRING, TRCDATANONE), (DWORD)(DWORD_PTR)(rgchTraceTagBuffer),
  1185. (DWORD)0, NULL, 0);
  1186. }
  1187. }
  1188. /*
  1189. * CheckTrace
  1190. *
  1191. * @mfunc
  1192. * This function checks to see if tracing should be performed
  1193. * in a function given the debug options set and the subsystem
  1194. * the function is in.
  1195. * ptrcf - Pointer to TrcFlags structure passed to CTrace.
  1196. *
  1197. * @rdesc
  1198. * True if tracing should be performed, false otherwise.
  1199. *
  1200. */
  1201. static BOOL CheckTrace(TrcFlags * ptrcf)
  1202. {
  1203. DWORD dwOpt;
  1204. //Set dwOpt to the correct value for the subsytem we are
  1205. //in.
  1206. switch (ptrcf->fields.uSubSystem)
  1207. {
  1208. case TRCSUBSYSDISP: dwOpt = OPTTRACEDISP; break;
  1209. case TRCSUBSYSWRAP: dwOpt = OPTTRACEWRAP; break;
  1210. case TRCSUBSYSEDIT: dwOpt = OPTTRACEEDIT; break;
  1211. case TRCSUBSYSTS: dwOpt = OPTTRACETS; break;
  1212. case TRCSUBSYSTOM: dwOpt = OPTTRACETOM; break;
  1213. case TRCSUBSYSOLE: dwOpt = OPTTRACEOLE; break;
  1214. case TRCSUBSYSBACK: dwOpt = OPTTRACEBACK; break;
  1215. case TRCSUBSYSSEL: dwOpt = OPTTRACESEL; break;
  1216. case TRCSUBSYSHOST: dwOpt = OPTTRACEHOST; break;
  1217. case TRCSUBSYSDTE: dwOpt = OPTTRACEDTE; break;
  1218. case TRCSUBSYSUNDO: dwOpt = OPTTRACEUNDO; break;
  1219. case TRCSUBSYSRANG: dwOpt = OPTTRACERANG; break;
  1220. case TRCSUBSYSUTIL: dwOpt = OPTTRACEUTIL; break;
  1221. case TRCSUBSYSNOTM: dwOpt = OPTTRACENOTM; break;
  1222. case TRCSUBSYSRTFR: dwOpt = OPTTRACERTFR; break;
  1223. case TRCSUBSYSRTFW: dwOpt = OPTTRACERTFW; break;
  1224. case TRCSUBSYSPRT: dwOpt = OPTTRACEPRT; break;
  1225. case TRCSUBSYSFE: dwOpt = OPTTRACEFE; break;
  1226. case TRCSUBSYSFONT: dwOpt = OPTTRACEFONT; break;
  1227. default:
  1228. return FALSE;
  1229. }
  1230. //If there is no tracing at any level enabled, return false.
  1231. if (!ISOPTSET(dwOpt) && !fTrace
  1232. && !(fTraceExt && (ptrcf->fields.uScope == TRCSCOPEEXTERN)))
  1233. return FALSE;
  1234. return TRUE;
  1235. }
  1236. /*
  1237. * CTrace::CTrace
  1238. *
  1239. * @mfunc
  1240. * This constructor is used to generate output about the function
  1241. * it is called from. Creating an instance of this class on the
  1242. * stack at the beginning of a function, will cause a trace message
  1243. * to be sent to the debug output. When the function returns, the
  1244. * destructor will be called automatically and another message
  1245. * will be sent to the debug output.
  1246. * This constructor takes several parameters to pass on to
  1247. * TraceMsg and it also stores certain data for use by the destructor.
  1248. *
  1249. * dwFlags - Packed values tell us how to generate the message.
  1250. * dw1 - The first of two data parameters. This must be
  1251. * the name of the function we were called from.
  1252. * dw2 - The second of two data parameters. This will be either
  1253. * unused or it will be a parameter to be interpreted by
  1254. * TraceMsg.
  1255. * szFile - File name we were called from.
  1256. *
  1257. */
  1258. CTrace::CTrace(DWORD dwFlags, DWORD dw1, DWORD dw2, LPSTR szFile)
  1259. {
  1260. char szFunc[80];
  1261. int tls;
  1262. trcf.dw = dwFlags;
  1263. //Return if tracing is not enabled.
  1264. if (!CheckTrace(&trcf))
  1265. return;
  1266. //Increment indentation level on entrance to function
  1267. tls = (int)(DWORD_PTR)TlsGetValue(TlsIndex);
  1268. tls++;
  1269. TlsSetValue(TlsIndex, (LPVOID)(DWORD_PTR)tls);
  1270. szFunc[0] = '\0';
  1271. lstrcpyA(szFileName, szFile);
  1272. lstrcpyA(szFuncName, (LPSTR)(DWORD_PTR)dw1);
  1273. sprintf(szFunc, "IN : %s.", szFuncName);
  1274. TraceMsg (trcf.dw, (DWORD)(DWORD_PTR)szFunc, dw2, szFileName, 0);
  1275. }
  1276. /*
  1277. * CTrace::~CTrace
  1278. *
  1279. * @mfunc
  1280. * This destructor is used to generate output about the function
  1281. * it is called from. Creating an instance of this class on the
  1282. * stack at the beginning of a function, will cause a trace message
  1283. * to be sent to the debug output. When the function returns, the
  1284. * destructor will be called automatically and another message
  1285. * will be sent to the debug output.
  1286. *
  1287. *
  1288. */
  1289. CTrace::~CTrace()
  1290. {
  1291. char szFunc[80];
  1292. int tls;
  1293. //Return if tracing is not enabled.
  1294. if (!CheckTrace(&trcf))
  1295. return;
  1296. szFunc[0] = '\0';
  1297. sprintf(szFunc, "OUT: %s.", szFuncName);
  1298. trcf.fields.uData2 = TRCDATANONE;
  1299. TraceMsg (trcf.dw, (DWORD)(DWORD_PTR)szFunc, 0, szFileName, 0);
  1300. //Decrement indentation level on exit from function
  1301. tls = (int)(DWORD_PTR)TlsGetValue(TlsIndex);
  1302. tls--;
  1303. TlsSetValue(TlsIndex, (LPVOID)(DWORD_PTR)tls);
  1304. }
  1305. #endif //!_RELEASE_ASSERTS_
  1306. #endif // NOFULLDEBUG
  1307. #endif // !!(DEBUG) && !! _RELEASE_ASSERTS_