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.

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