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.

502 lines
16 KiB

  1. /*
  2. Copyright 1999 Microsoft Corporation
  3. Logging for MessageBoxes and the comment button (aka the "lame" button).
  4. Walter Smith (wsmith)
  5. Rajesh Soy (nsoy) - modified 05/05/2000
  6. Rajesh Soy (nsoy) - reorganized code and cleaned it up, added comments 06/06/2000
  7. */
  8. #ifdef THIS_FILE
  9. #undef THIS_FILE
  10. #endif
  11. static char __szTraceSourceFile[] = __FILE__;
  12. #define THIS_FILE __szTraceSourceFile
  13. #include "stdafx.h"
  14. #define NOTRACE
  15. #include "logging.h"
  16. #include "simplexml.h"
  17. #include "Base64.h"
  18. #include <dbgtrace.h>
  19. //
  20. // Routines defined here
  21. //
  22. int LogLameButton(PLAMELOGDATA pData);
  23. void GetISO8601DateTime(LPTSTR buf);
  24. wstring Hexify(DWORD dwValue);
  25. wstring Decimalify(DWORD dwValue);
  26. wstring WDecimalify(WORD dwValue);
  27. void AddTextSubnode(SimpleXMLNode* pParentElt, LPCWSTR pTag, LPCWSTR pText, SimpleXMLNode** ppNewElt);
  28. void AddBase64Subnode(SimpleXMLNode* pParentElt, LPCWSTR pTag, DWORD cbData, const LPBYTE pbData, SimpleXMLNode** ppNewElt);
  29. void LogMessageBox(PMSGBOXLOGDATA pData);
  30. //
  31. // LogLameButton: This is the routine that gets called from the Comments dialog to format
  32. // data into XML and upload to server
  33. //
  34. int LogLameButton(PLAMELOGDATA pData)
  35. {
  36. TraceFunctEnter("LogLameButton");
  37. USES_CONVERSION;
  38. //
  39. // NTRAID#NTBUG9-154248-2000/08/08-jasonr
  40. // NTRAID#NTBUG9-152439-2000/08/08-jasonr
  41. //
  42. // We used to pop up the "Thank You" message box in the new thread.
  43. // Now we pop it up in the dialog box thread instead to fix these bugs.
  44. // The new thread now returns 0 to indicate success, 1 to indicate
  45. // failure. We only pop up the dialog box on success.
  46. //
  47. int iRet = 1;
  48. SimpleXMLNode* pElt;
  49. try {
  50. //
  51. // Create the Top-level XML document
  52. //
  53. DebugTrace(0, "Creating XMLDocument");
  54. SimpleXMLDocument doc;
  55. SimpleXMLNode* pDocTop = doc.GetTopNode();
  56. //
  57. // Create the <dialogComment timestamp= scope= severity= class= machineId= build= ProductSuiteMask= ProductType=>...</dialogComment> node
  58. //
  59. SimpleXMLNode* pTopElt = pDocTop->AppendChild(wstring(L"dialogComment"));
  60. TCHAR szTimestamp[32];
  61. GetISO8601DateTime(szTimestamp);
  62. //
  63. // Set the 'formatVersion' attribute of the dialogComment node
  64. //
  65. DebugTrace(0, " formatVersion is 20000822");
  66. pTopElt->SetAttribute(wstring(L"formatVersion"), wstring(L"20000822"));
  67. //
  68. // Set the 'timestamp' attribute of the dialogComment node
  69. //
  70. DebugTrace(0, " szTimeStamp = %ls", szTimestamp);
  71. pTopElt->SetAttribute(wstring(L"timestamp"), wstring(T2W(szTimestamp)));
  72. //
  73. // Set the 'eventCategory' attribute of the dialogComment node
  74. //
  75. DebugTrace(0, " eventCategory is %d", pData->dwEventCategory);
  76. pTopElt->SetAttribute(wstring(L"eventCategory"), Decimalify(pData->dwEventCategory));
  77. //
  78. // Set the 'severity' attribute of the dialogComment node
  79. //
  80. DebugTrace(0, " severity is %d", pData->dwSeverity);
  81. pTopElt->SetAttribute(wstring(L"severity"), Decimalify(pData->dwSeverity));
  82. //
  83. // Set the 'emailAddress' attribute of the dialogComment node
  84. //
  85. DebugTrace(0, " emailAddress is %s", pData->szEmailAddress);
  86. pTopElt->SetAttribute(wstring(L"emailAddress"), wstring(T2CW(pData->szEmailAddress)));
  87. //
  88. // Set the 'betaId' attribute of the dialogComment node
  89. //
  90. DebugTrace(0, " betaId is %s", pData->szBetaID);
  91. pTopElt->SetAttribute(wstring(L"betaId"), wstring(T2CW(pData->szBetaID)));
  92. //
  93. // Set the 'class' attribute of the dialogComment node
  94. //
  95. DebugTrace(0, " Class is %ls", pData->szClass);
  96. pTopElt->SetAttribute(wstring(L"class"), wstring(T2CW(pData->szClass)));
  97. //
  98. // Set the 'machineId' attibute of the dialogComment node
  99. //
  100. GUIDSTR szSignature;
  101. GetMachineSignature(szSignature);
  102. pTopElt->SetAttribute(wstring(L"machineId"), wstring(T2CW(szSignature)));
  103. //
  104. // Set the 'build' attibute of the dialogComment node
  105. //
  106. pTopElt->SetAttribute(wstring(L"build"), Decimalify(pData->versionInfo.dwBuildNumber));
  107. //
  108. // Fix for DCR 128611
  109. //
  110. pTopElt->SetAttribute(wstring(L"acp"), Decimalify(GetACP()));
  111. pTopElt->SetAttribute(wstring(L"userLCID"), Decimalify(GetUserDefaultLCID()));
  112. pTopElt->SetAttribute(wstring(L"systemLCID"), Decimalify(GetSystemDefaultLCID()));
  113. //
  114. // Fix for DCR 128609
  115. //
  116. OSVERSIONINFOEX OsInfo;
  117. OsInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  118. if(FALSE == GetVersionEx( (LPOSVERSIONINFO)&OsInfo))
  119. {
  120. FatalTrace(0, "GetVersionEx failed. Error: %ld", GetLastError());
  121. }
  122. else
  123. {
  124. DebugTrace(0, "ProductSuiteMask: %ld", OsInfo.wSuiteMask);
  125. pTopElt->SetAttribute(wstring(L"ProductSuiteMask"), WDecimalify(OsInfo.wSuiteMask));
  126. DebugTrace(0, "ProductType: %ld", OsInfo.wProductType);
  127. pTopElt->SetAttribute(wstring(L"ProductType"), WDecimalify(OsInfo.wProductType));
  128. }
  129. //
  130. // Add the <title>...</title> subnode to dialogComment
  131. //
  132. DebugTrace(0, " Title: %ls", pData->szTitle);
  133. AddTextSubnode(pTopElt, L"title", T2CW(pData->szTitle), NULL);
  134. //
  135. // Add the <comment>...</comment> subnode to dialogComment
  136. //
  137. DebugTrace(0, "Adding Comment Tag");
  138. AddTextSubnode(pTopElt, L"comment", T2CW(pData->szComment), NULL);
  139. //
  140. // Add the <image>...</image> subnode to dialogComment
  141. //
  142. DebugTrace(0, "Adding image tag");
  143. if (pData->pbImage != NULL && pData->cbImage != 0)
  144. {
  145. //
  146. // The image node is added only if there is an image captured else not
  147. //
  148. AddBase64Subnode(pTopElt, L"image", pData->cbImage, pData->pbImage, NULL);
  149. }
  150. //
  151. // Add the <msgboxtext>...</msgboxtext> subnode to dialogComment
  152. //
  153. DebugTrace(0, "Adding msgboxtext tag");
  154. if (0 != _tcslen(pData->szMsgBoxText))
  155. {
  156. //
  157. // MsgBoxText subnode is added only if it exists
  158. //
  159. AddTextSubnode(pTopElt, L"MsgBoxText", pData->szMsgBoxText, NULL);
  160. }
  161. //
  162. // Add the <STACKTRACE>...</STACKTRACE> subnode to the dialogComment
  163. //
  164. DebugTrace(0, "Adding stacktrace");
  165. pElt = pTopElt->AppendChild(wstring(L""));
  166. GenerateXMLStackTrace(pData->pStackTrace, pElt); // defined in stack.cpp
  167. //
  168. // Add the <minidump>...</minidump> subnote do the dialogComment.
  169. //
  170. DebugTrace(0, "Adding minidump");
  171. if (pData->szMiniDumpPath[0] != 0) {
  172. //
  173. // Open the file containing the minidump.
  174. //
  175. HANDLE hFile = INVALID_HANDLE_VALUE;
  176. if ((hFile = CreateFileW(pData->szMiniDumpPath,
  177. GENERIC_READ,
  178. 0,
  179. NULL,
  180. OPEN_EXISTING,
  181. FILE_ATTRIBUTE_NORMAL + FILE_FLAG_SEQUENTIAL_SCAN + FILE_FLAG_DELETE_ON_CLOSE,
  182. NULL)) == INVALID_HANDLE_VALUE) {
  183. DebugTrace(0, "CreateFile() failed on minidump file \"%s\"; GetLastError() returned %lu; minidump will not be included in XML", pData->szMiniDumpPath, GetLastError());
  184. DeleteFile(pData->szMiniDumpPath);
  185. pData->szMiniDumpPath[0] = 0;
  186. }
  187. else {
  188. //
  189. // Get the size of the file.
  190. //
  191. LARGE_INTEGER i64FileSize;
  192. if (!GetFileSizeEx(hFile, &i64FileSize)) {
  193. DebugTrace(0, "GetFileSizeEx() failed; GetLastError() returned %lu; minidump will not be included in XML", GetLastError());
  194. pData->szMiniDumpPath[0] = 0;
  195. }
  196. else if (i64FileSize.QuadPart > 16777216) {
  197. DebugTrace(0, "Minidump file is greater than 16MB in size and therefore will not be included in XML");
  198. pData->szMiniDumpPath[0] = 0;
  199. }
  200. else {
  201. //
  202. // Allocate buffer big enough to hold the file.
  203. //
  204. LPBYTE pBuffer = NULL;
  205. if ((pBuffer = (LPBYTE) HeapAlloc(GetProcessHeap(), 0, i64FileSize.LowPart)) == NULL) {
  206. DebugTrace(0, "Could not allocate %lu bytes off the process heap; minidump will not be included in XML", i64FileSize.LowPart);
  207. pData->szMiniDumpPath[0] = 0;
  208. }
  209. else {
  210. //
  211. // Read the file into memory.
  212. //
  213. DWORD dwBytesRead = 0;
  214. if (!ReadFile(hFile, pBuffer, i64FileSize.QuadPart, &dwBytesRead, NULL)) {
  215. DebugTrace(0, "ReadFile() failed; GetLastError() returned %lu; minidump will not be included in XML", GetLastError());
  216. pData->szMiniDumpPath[0] = 0;
  217. }
  218. else if (dwBytesRead < i64FileSize.LowPart) {
  219. DebugTrace(0, "ReadFile() did not read all of the file; minidump will not be included in XML");
  220. pData->szMiniDumpPath[0] = 0;
  221. }
  222. else {
  223. //
  224. // Add the node to the XML.
  225. //
  226. AddBase64Subnode(pTopElt, L"minidump", i64FileSize.LowPart, pBuffer, NULL);
  227. }
  228. //
  229. // Deallocate the buffer.
  230. //
  231. HeapFree(GetProcessHeap(), 0, pBuffer);
  232. }
  233. }
  234. //
  235. // Close the file.
  236. //
  237. CloseHandle(hFile);
  238. }
  239. }
  240. //
  241. // Upload the XML blob hence formed
  242. //
  243. DebugTrace(0, "Calling QueueXMLDocumentUpload");
  244. iRet = QueueXMLDocumentUpload(UPLOAD_LAMEBUTTON, doc); // defined in upload.cpp
  245. }
  246. catch (HRESULT hr) {
  247. FatalTrace(0, "LogLameButton: unexpected error %lX\n", hr);
  248. }
  249. catch (...) {
  250. FatalTrace(0, "LogLameButton: unexpected error");
  251. }
  252. return iRet;
  253. }
  254. //
  255. // GetISO8601DateTime: Get the current date/time in ISO8601 format (e.g., "1988-04-07T18:39:09.287").
  256. // 'buf' must be at least 24*sizeof(TCHAR) bytes long.
  257. //
  258. void
  259. GetISO8601DateTime(
  260. LPTSTR buf // [out] string with the ISO8601 formated datatime
  261. )
  262. {
  263. SYSTEMTIME st;
  264. GetSystemTime(&st);
  265. wsprintf(buf, _T("%d-%02d-%02dT%02d:%02d:%02d.%03d"),
  266. st.wYear, st.wMonth, st.wDay,
  267. st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
  268. }
  269. //
  270. // Hexify: converts a DWORD to wstring in Hex representation
  271. //
  272. wstring
  273. Hexify(
  274. DWORD dwValue // [in] - DWORD to be converted
  275. )
  276. {
  277. WCHAR buf[64];
  278. wsprintfW(buf, L"0x%lx", dwValue);
  279. return wstring(buf);
  280. }
  281. //
  282. // Decimalify: converts a DWORD to wstring in Decimal representation
  283. //
  284. wstring
  285. Decimalify(
  286. DWORD dwValue // [in] - DWORD to be converted
  287. )
  288. {
  289. WCHAR buf[64];
  290. wsprintfW(buf, L"%ld", dwValue);
  291. return wstring(buf);
  292. }
  293. //
  294. // Decimalify: converts a WORD to wstring in Decimal representation
  295. //
  296. wstring
  297. WDecimalify(
  298. WORD wValue // [in] - WORD to be converted
  299. )
  300. {
  301. WCHAR buf[64];
  302. wsprintfW(buf, L"%d", wValue);
  303. return wstring(buf);
  304. }
  305. //
  306. // AddTextSubnode: Creates a XML subnode, given data contained in the subnode as a Text blob
  307. //
  308. void
  309. AddTextSubnode(
  310. SimpleXMLNode* pParentElt, // [in] - parent XML node
  311. LPCWSTR pTag, // [in] - name of the child tag
  312. LPCWSTR pText, // [in] - data (as Text) contained in the child node
  313. SimpleXMLNode** ppNewElt // [out] - child XML node
  314. )
  315. {
  316. _ASSERT(pParentElt != NULL);
  317. _ASSERT(pTag != NULL);
  318. _ASSERT(pText != NULL);
  319. SimpleXMLNode* pNewNode = pParentElt->AppendChild(wstring(pTag));
  320. pNewNode->text = wstring(pText);
  321. if (ppNewElt != NULL)
  322. *ppNewElt = pNewNode;
  323. }
  324. //
  325. // AddBase64Subnode: Creates a XML subnode, given data contained in the subnode as a binary blob
  326. //
  327. void AddBase64Subnode(
  328. SimpleXMLNode* pParentElt, // [in] - parent XML node
  329. LPCWSTR pTag, // [in] - name of the child tag
  330. DWORD cbData, // [in] - size of data
  331. const LPBYTE pbData, // [in] - data (as a binary blob) contained in the child node
  332. SimpleXMLNode** ppNewElt // [out] - child XML node
  333. )
  334. {
  335. USES_CONVERSION;
  336. _ASSERT(pParentElt != NULL);
  337. _ASSERT(pTag != NULL);
  338. _ASSERT(pbData != NULL);
  339. Base64Coder coder;
  340. coder.Encode(pbData, cbData);
  341. LPWSTR pszData;
  342. if ((pszData = (LPWSTR) HeapAlloc(GetProcessHeap(), 0, (strlen(coder.EncodedMessage()) + 1) * sizeof(WCHAR))) != NULL) {
  343. if (MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, coder.EncodedMessage(), -1, pszData, strlen(coder.EncodedMessage()) + 1) != 0)
  344. AddTextSubnode(pParentElt, pTag, pszData, ppNewElt);
  345. HeapFree(GetProcessHeap(), 0, pszData);
  346. }
  347. }
  348. //
  349. // LogMessageBox: Routine to log calls into the messagebox hook. This is not supported anymore.
  350. // and hence not maintained.
  351. void LogMessageBox(PMSGBOXLOGDATA pData)
  352. {
  353. TraceFunctEnter("LogMessageBox");
  354. _ASSERTE(pData->pStackTrace != NULL);
  355. _ASSERTE(pData->szCaption != NULL);
  356. _ASSERTE(pData->szOwnerClass != NULL);
  357. _ASSERTE(pData->szOwnerTitle != NULL);
  358. _ASSERTE(pData->szText != NULL);
  359. USES_CONVERSION;
  360. SimpleXMLNode* pElt;
  361. try {
  362. // Top-level document
  363. SimpleXMLDocument doc;
  364. SimpleXMLNode* pDocTop = doc.GetTopNode();
  365. // <messageBox style= helpId= ownerClass= ownerTitle= result= machineId= build= acp= userLCID= systemLCID=>...</messageBox>
  366. SimpleXMLNode* pTopElt = pDocTop->AppendChild(wstring(L"messageBox"));
  367. TCHAR szTimestamp[32];
  368. GetISO8601DateTime(szTimestamp);
  369. pTopElt->SetAttribute(wstring(L"timestamp"), wstring(T2W(szTimestamp)));
  370. pTopElt->SetAttribute(wstring(L"style"), Decimalify(pData->dwStyle));
  371. pTopElt->SetAttribute(wstring(L"helpId"), Decimalify(pData->dwContextHelpId));
  372. pTopElt->SetAttribute(wstring(L"ownerClass"), wstring(T2CW(pData->szOwnerClass)));
  373. pTopElt->SetAttribute(wstring(L"ownerTitle"), wstring(T2CW(pData->szOwnerTitle)));
  374. pTopElt->SetAttribute(wstring(L"result"), Decimalify(pData->dwResult));
  375. GUIDSTR szSignature;
  376. GetMachineSignature(szSignature);
  377. pTopElt->SetAttribute(wstring(L"machineId"), wstring(T2CW(szSignature)));
  378. pTopElt->SetAttribute(wstring(L"build"), Decimalify(pData->versionInfo.dwBuildNumber));
  379. // <caption> ... </caption>
  380. DebugTrace(0, " Caption is %ls", pData->szCaption);
  381. AddTextSubnode(pTopElt, L"caption", T2CW(pData->szCaption), NULL);
  382. // <text> ... </text>
  383. // Only capture the first 200 characters of the text, on the assumption
  384. // the rest is kind of boring to look at.
  385. TCHAR szText[200];
  386. lstrcpyn(szText, pData->szText, ARRAYSIZE(szText));
  387. AddTextSubnode(pTopElt, L"text", T2W(szText), NULL);
  388. // <STACKTRACE>...</STACKTRACE>
  389. if (pData->pStackTrace != NULL) {
  390. pElt = pTopElt->AppendChild(wstring(L""));
  391. GenerateXMLStackTrace(pData->pStackTrace, pElt);
  392. }
  393. QueueXMLDocumentUpload(UPLOAD_LAMEBUTTON, doc);
  394. }
  395. catch (HRESULT hr) {
  396. _RPTF1(_CRT_ERROR, "LogLameButton: unexpected error %lX\n", hr);
  397. }
  398. catch (...) {
  399. _RPTF0(_CRT_ERROR, "LogLameButton: unexpected error");
  400. }
  401. TraceFunctLeave();
  402. }