windows-nt/Source/XPSP1/NT/admin/pchealth/client/lamebtn/dll/logging.cpp
2020-09-26 16:20:57 +08:00

503 lines
16 KiB
C++

/*
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();
}