|
|
/*
Copyright 1999 Microsoft Corporation Logging for MessageBoxes and the comment button (aka the "lame" button).
Walter Smith (wsmith) Rajesh Soy (nsoy) - modified 05/05/2000 Rajesh Soy (nsoy) - reorganized code and cleaned it up, added comments 06/06/2000 */
#ifdef THIS_FILE
#undef THIS_FILE
#endif
static char __szTraceSourceFile[] = __FILE__; #define THIS_FILE __szTraceSourceFile
#include "stdafx.h"
#define NOTRACE
#include "logging.h"
#include "simplexml.h"
#include "Base64.h"
#include <dbgtrace.h>
//
// Routines defined here
//
int LogLameButton(PLAMELOGDATA pData); void GetISO8601DateTime(LPTSTR buf); wstring Hexify(DWORD dwValue); wstring Decimalify(DWORD dwValue); wstring WDecimalify(WORD dwValue); void AddTextSubnode(SimpleXMLNode* pParentElt, LPCWSTR pTag, LPCWSTR pText, SimpleXMLNode** ppNewElt); void AddBase64Subnode(SimpleXMLNode* pParentElt, LPCWSTR pTag, DWORD cbData, const LPBYTE pbData, SimpleXMLNode** ppNewElt); void LogMessageBox(PMSGBOXLOGDATA pData);
//
// LogLameButton: This is the routine that gets called from the Comments dialog to format
// data into XML and upload to server
//
int LogLameButton(PLAMELOGDATA pData) { TraceFunctEnter("LogLameButton"); USES_CONVERSION;
//
// NTRAID#NTBUG9-154248-2000/08/08-jasonr
// NTRAID#NTBUG9-152439-2000/08/08-jasonr
//
// We used to pop up the "Thank You" message box in the new thread.
// Now we pop it up in the dialog box thread instead to fix these bugs.
// The new thread now returns 0 to indicate success, 1 to indicate
// failure. We only pop up the dialog box on success.
//
int iRet = 1;
SimpleXMLNode* pElt;
try { //
// Create the Top-level XML document
//
DebugTrace(0, "Creating XMLDocument");
SimpleXMLDocument doc; SimpleXMLNode* pDocTop = doc.GetTopNode();
//
// Create the <dialogComment timestamp= scope= severity= class= machineId= build= ProductSuiteMask= ProductType=>...</dialogComment> node
//
SimpleXMLNode* pTopElt = pDocTop->AppendChild(wstring(L"dialogComment"));
TCHAR szTimestamp[32]; GetISO8601DateTime(szTimestamp);
//
// Set the 'formatVersion' attribute of the dialogComment node
//
DebugTrace(0, " formatVersion is 20000822"); pTopElt->SetAttribute(wstring(L"formatVersion"), wstring(L"20000822"));
//
// Set the 'timestamp' attribute of the dialogComment node
//
DebugTrace(0, " szTimeStamp = %ls", szTimestamp); pTopElt->SetAttribute(wstring(L"timestamp"), wstring(T2W(szTimestamp)));
//
// Set the 'eventCategory' attribute of the dialogComment node
//
DebugTrace(0, " eventCategory is %d", pData->dwEventCategory); pTopElt->SetAttribute(wstring(L"eventCategory"), Decimalify(pData->dwEventCategory)); //
// Set the 'severity' attribute of the dialogComment node
//
DebugTrace(0, " severity is %d", pData->dwSeverity); pTopElt->SetAttribute(wstring(L"severity"), Decimalify(pData->dwSeverity)); //
// Set the 'emailAddress' attribute of the dialogComment node
//
DebugTrace(0, " emailAddress is %s", pData->szEmailAddress); pTopElt->SetAttribute(wstring(L"emailAddress"), wstring(T2CW(pData->szEmailAddress))); //
// Set the 'betaId' attribute of the dialogComment node
//
DebugTrace(0, " betaId is %s", pData->szBetaID); pTopElt->SetAttribute(wstring(L"betaId"), wstring(T2CW(pData->szBetaID)));
//
// Set the 'class' attribute of the dialogComment node
//
DebugTrace(0, " Class is %ls", pData->szClass); pTopElt->SetAttribute(wstring(L"class"), wstring(T2CW(pData->szClass)));
//
// Set the 'machineId' attibute of the dialogComment node
//
GUIDSTR szSignature; GetMachineSignature(szSignature); pTopElt->SetAttribute(wstring(L"machineId"), wstring(T2CW(szSignature)));
//
// Set the 'build' attibute of the dialogComment node
//
pTopElt->SetAttribute(wstring(L"build"), Decimalify(pData->versionInfo.dwBuildNumber));
//
// Fix for DCR 128611
//
pTopElt->SetAttribute(wstring(L"acp"), Decimalify(GetACP())); pTopElt->SetAttribute(wstring(L"userLCID"), Decimalify(GetUserDefaultLCID())); pTopElt->SetAttribute(wstring(L"systemLCID"), Decimalify(GetSystemDefaultLCID()));
//
// Fix for DCR 128609
//
OSVERSIONINFOEX OsInfo; OsInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); if(FALSE == GetVersionEx( (LPOSVERSIONINFO)&OsInfo)) { FatalTrace(0, "GetVersionEx failed. Error: %ld", GetLastError()); } else { DebugTrace(0, "ProductSuiteMask: %ld", OsInfo.wSuiteMask); pTopElt->SetAttribute(wstring(L"ProductSuiteMask"), WDecimalify(OsInfo.wSuiteMask));
DebugTrace(0, "ProductType: %ld", OsInfo.wProductType); pTopElt->SetAttribute(wstring(L"ProductType"), WDecimalify(OsInfo.wProductType)); }
//
// Add the <title>...</title> subnode to dialogComment
//
DebugTrace(0, " Title: %ls", pData->szTitle); AddTextSubnode(pTopElt, L"title", T2CW(pData->szTitle), NULL);
//
// Add the <comment>...</comment> subnode to dialogComment
//
DebugTrace(0, "Adding Comment Tag"); AddTextSubnode(pTopElt, L"comment", T2CW(pData->szComment), NULL);
//
// Add the <image>...</image> subnode to dialogComment
//
DebugTrace(0, "Adding image tag"); if (pData->pbImage != NULL && pData->cbImage != 0) { //
// The image node is added only if there is an image captured else not
//
AddBase64Subnode(pTopElt, L"image", pData->cbImage, pData->pbImage, NULL); }
//
// Add the <msgboxtext>...</msgboxtext> subnode to dialogComment
//
DebugTrace(0, "Adding msgboxtext tag"); if (0 != _tcslen(pData->szMsgBoxText)) { //
// MsgBoxText subnode is added only if it exists
//
AddTextSubnode(pTopElt, L"MsgBoxText", pData->szMsgBoxText, NULL); }
//
// Add the <STACKTRACE>...</STACKTRACE> subnode to the dialogComment
//
DebugTrace(0, "Adding stacktrace"); pElt = pTopElt->AppendChild(wstring(L"")); GenerateXMLStackTrace(pData->pStackTrace, pElt); // defined in stack.cpp
//
// Add the <minidump>...</minidump> subnote do the dialogComment.
//
DebugTrace(0, "Adding minidump");
if (pData->szMiniDumpPath[0] != 0) {
//
// Open the file containing the minidump.
//
HANDLE hFile = INVALID_HANDLE_VALUE;
if ((hFile = CreateFileW(pData->szMiniDumpPath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL + FILE_FLAG_SEQUENTIAL_SCAN + FILE_FLAG_DELETE_ON_CLOSE, NULL)) == INVALID_HANDLE_VALUE) {
DebugTrace(0, "CreateFile() failed on minidump file \"%s\"; GetLastError() returned %lu; minidump will not be included in XML", pData->szMiniDumpPath, GetLastError()); DeleteFile(pData->szMiniDumpPath); pData->szMiniDumpPath[0] = 0; } else {
//
// Get the size of the file.
//
LARGE_INTEGER i64FileSize;
if (!GetFileSizeEx(hFile, &i64FileSize)) { DebugTrace(0, "GetFileSizeEx() failed; GetLastError() returned %lu; minidump will not be included in XML", GetLastError()); pData->szMiniDumpPath[0] = 0; } else if (i64FileSize.QuadPart > 16777216) { DebugTrace(0, "Minidump file is greater than 16MB in size and therefore will not be included in XML"); pData->szMiniDumpPath[0] = 0; } else {
//
// Allocate buffer big enough to hold the file.
//
LPBYTE pBuffer = NULL;
if ((pBuffer = (LPBYTE) HeapAlloc(GetProcessHeap(), 0, i64FileSize.LowPart)) == NULL) { DebugTrace(0, "Could not allocate %lu bytes off the process heap; minidump will not be included in XML", i64FileSize.LowPart); pData->szMiniDumpPath[0] = 0; } else {
//
// Read the file into memory.
//
DWORD dwBytesRead = 0;
if (!ReadFile(hFile, pBuffer, i64FileSize.QuadPart, &dwBytesRead, NULL)) { DebugTrace(0, "ReadFile() failed; GetLastError() returned %lu; minidump will not be included in XML", GetLastError()); pData->szMiniDumpPath[0] = 0; } else if (dwBytesRead < i64FileSize.LowPart) { DebugTrace(0, "ReadFile() did not read all of the file; minidump will not be included in XML"); pData->szMiniDumpPath[0] = 0; } else {
//
// Add the node to the XML.
//
AddBase64Subnode(pTopElt, L"minidump", i64FileSize.LowPart, pBuffer, NULL); }
//
// Deallocate the buffer.
//
HeapFree(GetProcessHeap(), 0, pBuffer); } }
//
// Close the file.
//
CloseHandle(hFile); } } //
// Upload the XML blob hence formed
//
DebugTrace(0, "Calling QueueXMLDocumentUpload"); iRet = QueueXMLDocumentUpload(UPLOAD_LAMEBUTTON, doc); // defined in upload.cpp
} catch (HRESULT hr) { FatalTrace(0, "LogLameButton: unexpected error %lX\n", hr); } catch (...) { FatalTrace(0, "LogLameButton: unexpected error"); }
return iRet; }
//
// GetISO8601DateTime: Get the current date/time in ISO8601 format (e.g., "1988-04-07T18:39:09.287").
// 'buf' must be at least 24*sizeof(TCHAR) bytes long.
//
void GetISO8601DateTime( LPTSTR buf // [out] string with the ISO8601 formated datatime
) { SYSTEMTIME st; GetSystemTime(&st);
wsprintf(buf, _T("%d-%02d-%02dT%02d:%02d:%02d.%03d"), st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds); }
//
// Hexify: converts a DWORD to wstring in Hex representation
//
wstring Hexify( DWORD dwValue // [in] - DWORD to be converted
) { WCHAR buf[64]; wsprintfW(buf, L"0x%lx", dwValue); return wstring(buf); }
//
// Decimalify: converts a DWORD to wstring in Decimal representation
//
wstring Decimalify( DWORD dwValue // [in] - DWORD to be converted
) { WCHAR buf[64]; wsprintfW(buf, L"%ld", dwValue); return wstring(buf); }
//
// Decimalify: converts a WORD to wstring in Decimal representation
//
wstring WDecimalify( WORD wValue // [in] - WORD to be converted
) { WCHAR buf[64]; wsprintfW(buf, L"%d", wValue); return wstring(buf); }
//
// AddTextSubnode: Creates a XML subnode, given data contained in the subnode as a Text blob
//
void AddTextSubnode( SimpleXMLNode* pParentElt, // [in] - parent XML node
LPCWSTR pTag, // [in] - name of the child tag
LPCWSTR pText, // [in] - data (as Text) contained in the child node
SimpleXMLNode** ppNewElt // [out] - child XML node
) { _ASSERT(pParentElt != NULL); _ASSERT(pTag != NULL); _ASSERT(pText != NULL);
SimpleXMLNode* pNewNode = pParentElt->AppendChild(wstring(pTag)); pNewNode->text = wstring(pText);
if (ppNewElt != NULL) *ppNewElt = pNewNode; }
//
// AddBase64Subnode: Creates a XML subnode, given data contained in the subnode as a binary blob
//
void AddBase64Subnode( SimpleXMLNode* pParentElt, // [in] - parent XML node
LPCWSTR pTag, // [in] - name of the child tag
DWORD cbData, // [in] - size of data
const LPBYTE pbData, // [in] - data (as a binary blob) contained in the child node
SimpleXMLNode** ppNewElt // [out] - child XML node
) { USES_CONVERSION;
_ASSERT(pParentElt != NULL); _ASSERT(pTag != NULL); _ASSERT(pbData != NULL);
Base64Coder coder; coder.Encode(pbData, cbData);
LPWSTR pszData;
if ((pszData = (LPWSTR) HeapAlloc(GetProcessHeap(), 0, (strlen(coder.EncodedMessage()) + 1) * sizeof(WCHAR))) != NULL) { if (MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, coder.EncodedMessage(), -1, pszData, strlen(coder.EncodedMessage()) + 1) != 0) AddTextSubnode(pParentElt, pTag, pszData, ppNewElt);
HeapFree(GetProcessHeap(), 0, pszData); } }
//
// LogMessageBox: Routine to log calls into the messagebox hook. This is not supported anymore.
// and hence not maintained.
void LogMessageBox(PMSGBOXLOGDATA pData) { TraceFunctEnter("LogMessageBox"); _ASSERTE(pData->pStackTrace != NULL); _ASSERTE(pData->szCaption != NULL); _ASSERTE(pData->szOwnerClass != NULL); _ASSERTE(pData->szOwnerTitle != NULL); _ASSERTE(pData->szText != NULL);
USES_CONVERSION;
SimpleXMLNode* pElt;
try { // Top-level document
SimpleXMLDocument doc; SimpleXMLNode* pDocTop = doc.GetTopNode();
// <messageBox style= helpId= ownerClass= ownerTitle= result= machineId= build= acp= userLCID= systemLCID=>...</messageBox>
SimpleXMLNode* pTopElt = pDocTop->AppendChild(wstring(L"messageBox"));
TCHAR szTimestamp[32]; GetISO8601DateTime(szTimestamp); pTopElt->SetAttribute(wstring(L"timestamp"), wstring(T2W(szTimestamp)));
pTopElt->SetAttribute(wstring(L"style"), Decimalify(pData->dwStyle)); pTopElt->SetAttribute(wstring(L"helpId"), Decimalify(pData->dwContextHelpId)); pTopElt->SetAttribute(wstring(L"ownerClass"), wstring(T2CW(pData->szOwnerClass))); pTopElt->SetAttribute(wstring(L"ownerTitle"), wstring(T2CW(pData->szOwnerTitle))); pTopElt->SetAttribute(wstring(L"result"), Decimalify(pData->dwResult));
GUIDSTR szSignature; GetMachineSignature(szSignature); pTopElt->SetAttribute(wstring(L"machineId"), wstring(T2CW(szSignature)));
pTopElt->SetAttribute(wstring(L"build"), Decimalify(pData->versionInfo.dwBuildNumber));
// <caption> ... </caption>
DebugTrace(0, " Caption is %ls", pData->szCaption); AddTextSubnode(pTopElt, L"caption", T2CW(pData->szCaption), NULL);
// <text> ... </text>
// Only capture the first 200 characters of the text, on the assumption
// the rest is kind of boring to look at.
TCHAR szText[200]; lstrcpyn(szText, pData->szText, ARRAYSIZE(szText)); AddTextSubnode(pTopElt, L"text", T2W(szText), NULL);
// <STACKTRACE>...</STACKTRACE>
if (pData->pStackTrace != NULL) { pElt = pTopElt->AppendChild(wstring(L"")); GenerateXMLStackTrace(pData->pStackTrace, pElt); }
QueueXMLDocumentUpload(UPLOAD_LAMEBUTTON, doc); } catch (HRESULT hr) { _RPTF1(_CRT_ERROR, "LogLameButton: unexpected error %lX\n", hr); } catch (...) { _RPTF0(_CRT_ERROR, "LogLameButton: unexpected error"); }
TraceFunctLeave(); }
|