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

1667 lines
52 KiB
C++

/*
Copyright 1999 Microsoft Corporation
Logging for MessageBoxes and the comment button (aka the "lame" button).
Walter Smith (wsmith)
Rajesh Soy (nsoy) - cleaned up code. 5/5/2000
Rajesh Soy (nsoy) - rearranged code, added messagebox text handling. 6/6/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 "resource.h"
#include <dbgtrace.h>
#include <objbase.h>
#include <atlcom.h>
#include <faultrep.h>
// MPC_Utils.h includes MPC_main.h, which apparently redefines ARRAYSIZE which
// causes a compiler warning.
#ifdef ARRAYSIZE
#undef ARRAYSIZE
#endif
#include <MPC_utils.h>
//
// Globals
//
HINSTANCE ghDllInst;
CComModule _Module;
//
// Routines Defined here
//
unsigned int __stdcall LogLameButtonThread(void* pvLogData);
VOID WINAPI CommentReport( HWND hwnd, PVOID pv);
//
// CSurveyDlg: The Comments dialog implementation
//
class CSurveyDlg :
public CAxDialogImpl<CSurveyDlg>
{
public:
//
// Constructor
//
CSurveyDlg()
{
ZeroMemory(&m_lldata, sizeof(m_lldata));
m_hwndTarget = NULL;
m_bShowHyperlink = FALSE;
m_crAnchor = RGB(0, 0, 0);
ZeroMemory(&m_szHyperlinkText, sizeof(m_szHyperlinkText));
ZeroMemory(&m_szHyperlinkCmdLine, sizeof(m_szHyperlinkCmdLine));
m_bHyperlinkHasFocus = FALSE;
}
//
// Destructor
//
~CSurveyDlg()
{
if (m_lldata.pbImage != NULL) {
free(m_lldata.pbImage);
m_lldata.pbImage = NULL;
}
}
enum { IDD = IDD_SURVEYDLG };
private:
LAMELOGDATA m_lldata; // Data collected by LAMEBTN.dll
HWND m_hwndTarget; // Window of dialog being commented on
BOOL m_bShowHyperlink; // Set to TRUE if we should display the hyperlink on our dialog.
COLORREF m_crAnchor; // Color of a hyperlink (anchor).
TCHAR m_szHyperlinkText[256]; // Display string for the hyperlink.
TCHAR m_szHyperlinkCmdLine[2048]; // Command line (obtained from the registry) to execute when the user clicks the hyperlink.
TCHAR m_bHyperlinkHasFocus; // Set to TRUE when the hyperlink button (IDC_BUTTON_HYPERLINK) has focus.
public:
BEGIN_MSG_MAP(CSurveyDlg)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
MESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem)
MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor)
COMMAND_ID_HANDLER(IDC_BUTTON_HYPERLINK, HyperlinkCmdHandler)
COMMAND_ID_HANDLER(IDOK, OnOK)
COMMAND_ID_HANDLER(IDCANCEL, OnCancel)
END_MSG_MAP()
//
// Init: Initializes the comment Dialog
//
void Init( HWND hwndTarget, PSTACKTRACEDATA pstdata);
//
// OnInitDialog: Fills up the Comment Dialog structures when the dialog is displayed
//
LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
//
// OnDrawItem: Draws owner-drawn controls (we have only one: IDC_BUTTON_HYPERLINK)
//
LRESULT OnDrawItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
//
// OnSetCursor: Sets the cursor to the hand if the mouse is over IDC_BUTTON_HYPERLINK
//
LRESULT OnSetCursor(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
//
// HyperlinkCmdHandler: Handles messages from the IDC_BUTTON_HYPERLINK button
//
LRESULT HyperlinkCmdHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
//
// OnOK: Submits Comment
//
LRESULT OnOK(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
//
// OnCancel: Cancel the comment
//
LRESULT OnCancel(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
private:
//
// CSurveyDlg::IsMessageBox: This routine returns TRUE if the hWnd passed is indeed
// a message box
//
BOOL IsMessageBox();
//
// GetInfoAndLogLameButton: Gathers the comment and callstack information, formats into XML
// and uploads to server
void GetInfoAndLogLameButton();
};
//
// CSurveyDlg::Init: Initializes the comment Dialog
//
void CSurveyDlg::Init(
HWND hwndTarget, // [in] Window of dialog being commented on
PSTACKTRACEDATA pstdata // [in] Call Stack
)
{
TraceFunctEnter("CSurveyDlg::Init");
_ASSERT(hwndTarget != NULL);
//
// Save off the target window
//
m_hwndTarget = hwndTarget;
//
// Save off the call stack
//
m_lldata.pStackTrace = pstdata;
//
// Grab the image of the target window
//
DebugTrace(0, "Calling SetActiveWindow");
::SetActiveWindow(hwndTarget);
try {
BYTE* pImageData = NULL;
DebugTrace(0, "Calling GetWindowImage");
GetWindowImage(hwndTarget, &pImageData, &m_lldata.cbImage);
m_lldata.pbImage = pImageData;
}
catch (HRESULT hr) {
m_lldata.pbImage = NULL;
m_lldata.cbImage = 0;
}
TraceFunctLeave();
}
//
// CSurveyDlg::OnInitDialog: Executes when Comments dialog is created
//
LRESULT
CSurveyDlg::OnInitDialog(
UINT uMsg,
WPARAM wParam,
LPARAM lParam,
BOOL& bHandled
)
{
DWORD idMessage;
TraceFunctEnter("OnInitDialog");
TCHAR szTitle[64];
//
// Obtain the Title of the Window being commented
//
if (::GetWindowText(m_hwndTarget, szTitle, ARRAYSIZE(szTitle)) != 0) {
idMessage = IDS_INTRO_WITH_TITLE;
if (lstrlen(szTitle) == ARRAYSIZE(szTitle) - 1) {
// Truncate the title a little more nicely
TCHAR* p = &szTitle[ARRAYSIZE(szTitle) - 4];
*p++ = '.';
*p++ = '.';
*p++ = '.';
}
}
else {
idMessage = IDS_INTRO;
}
//
// Load localized sting for Comment intro
//
TCHAR szTemplate[1024];
LoadString(_Module.GetResourceInstance(),
idMessage,
szTemplate,
ARRAYSIZE(szTemplate));
TCHAR* fmArgs[] = { szTitle };
TCHAR* szCommentIntro = NULL;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_STRING |
FORMAT_MESSAGE_ARGUMENT_ARRAY,
szTemplate,
0,
0,
(LPTSTR) &szCommentIntro,
1024,
(va_list*) &fmArgs);
if (szCommentIntro != NULL) {
SetDlgItemText(IDC_STATIC_INTRO, szCommentIntro);
LocalFree(szCommentIntro);
}
//
// Set the maximum limits on the edit controls.
//
SendDlgItemMessage(IDC_EDIT_EMAIL_ADDRESS, EM_LIMITTEXT, MAX_EMAIL_ADDRESS_SIZE, 0);
SendDlgItemMessage(IDC_EDIT_BETA_ID, EM_LIMITTEXT, MAX_BETA_ID_SIZE, 0);
SendDlgItemMessage(IDC_EDIT_COMMENT, EM_LIMITTEXT, COMMENT_TEXT_SIZE, 0);
//
// Prepopulate the email address and beta ID edit controls with whatever
// the user typed in last time. (We stored this in the registry the last
// time they pressed the submit button.)
//
HKEY hKey;
DWORD dwRet;
if ((dwRet = RegOpenKeyEx(HKEY_CURRENT_USER,
_T("Software\\Microsoft\\PCHealth\\Clients\\Dialog Comments"),
0,
KEY_QUERY_VALUE,
&hKey)) != ERROR_SUCCESS) {
DebugTrace(0, "No HKCU\\Software\\Microsoft\\PCHealth\\Clients\\Dialog Comments key in the registry (RegOpenKeyEx returned %ld)", dwRet);
}
else {
DWORD dwDataSize = sizeof(m_lldata.szEmailAddress);
if ((dwRet = RegQueryValueEx(hKey,
_T("Email Address"),
NULL,
NULL,
(LPBYTE) m_lldata.szEmailAddress,
&dwDataSize)) != ERROR_SUCCESS) {
DebugTrace(0, "No Email Address value in the HKCU\\Software\\Microsoft\\PCHealth\\Clients\\Dialog Comments registry key (RegQueryValueEx returned %ld)", dwRet);
m_lldata.szEmailAddress[0] = 0;
}
else {
DebugTrace(0, "Email address for this user in the registry: %s", m_lldata.szEmailAddress);
SendDlgItemMessage(IDC_EDIT_EMAIL_ADDRESS, WM_SETTEXT, 0, (LPARAM) m_lldata.szEmailAddress);
}
dwDataSize = sizeof(m_lldata.szBetaID);
if ((dwRet = RegQueryValueEx(hKey,
_T("Beta ID"),
NULL,
NULL,
(LPBYTE) m_lldata.szBetaID,
&dwDataSize)) != ERROR_SUCCESS) {
DebugTrace(0, "No Beta ID value in the HKCU\\Software\\Microsoft\\PCHealth\\Clients\\Dialog Comments registry key (RegQueryValueEx returned %ld)", dwRet);
m_lldata.szBetaID[0] = 0;
}
else {
DebugTrace(0, "Beta ID for this user in the registry: %s", m_lldata.szBetaID);
SendDlgItemMessage(IDC_EDIT_BETA_ID, WM_SETTEXT, 0, (LPARAM) m_lldata.szBetaID);
}
RegCloseKey(hKey);
}
//
// Populate the event category dropdown.
//
TCHAR szEventCategoryString[1024];
LoadString(_Module.GetResourceInstance(), IDS_EVENT_CATEGORY_1, szEventCategoryString, ARRAYSIZE(szEventCategoryString));
SendDlgItemMessage(IDC_COMBO_EVENT_CATEGORY, CB_ADDSTRING, 0, (LPARAM) szEventCategoryString);
LoadString(_Module.GetResourceInstance(), IDS_EVENT_CATEGORY_2, szEventCategoryString, ARRAYSIZE(szEventCategoryString));
SendDlgItemMessage(IDC_COMBO_EVENT_CATEGORY, CB_ADDSTRING, 0, (LPARAM) szEventCategoryString);
LoadString(_Module.GetResourceInstance(), IDS_EVENT_CATEGORY_3, szEventCategoryString, ARRAYSIZE(szEventCategoryString));
SendDlgItemMessage(IDC_COMBO_EVENT_CATEGORY, CB_ADDSTRING, 0, (LPARAM) szEventCategoryString);
LoadString(_Module.GetResourceInstance(), IDS_EVENT_CATEGORY_4, szEventCategoryString, ARRAYSIZE(szEventCategoryString));
SendDlgItemMessage(IDC_COMBO_EVENT_CATEGORY, CB_ADDSTRING, 0, (LPARAM) szEventCategoryString);
LoadString(_Module.GetResourceInstance(), IDS_EVENT_CATEGORY_5, szEventCategoryString, ARRAYSIZE(szEventCategoryString));
SendDlgItemMessage(IDC_COMBO_EVENT_CATEGORY, CB_ADDSTRING, 0, (LPARAM) szEventCategoryString);
LoadString(_Module.GetResourceInstance(), IDS_EVENT_CATEGORY_6, szEventCategoryString, ARRAYSIZE(szEventCategoryString));
SendDlgItemMessage(IDC_COMBO_EVENT_CATEGORY, CB_ADDSTRING, 0, (LPARAM) szEventCategoryString);
//
// Populate the severity dropdown.
//
TCHAR szSeverityString[1024];
LoadString(_Module.GetResourceInstance(), IDS_SEVERITY_1, szSeverityString, ARRAYSIZE(szSeverityString));
SendDlgItemMessage(IDC_COMBO_SEVERITY, CB_ADDSTRING, 0, (LPARAM) szSeverityString);
LoadString(_Module.GetResourceInstance(), IDS_SEVERITY_2, szSeverityString, ARRAYSIZE(szSeverityString));
SendDlgItemMessage(IDC_COMBO_SEVERITY, CB_ADDSTRING, 0, (LPARAM) szSeverityString);
LoadString(_Module.GetResourceInstance(), IDS_SEVERITY_3, szSeverityString, ARRAYSIZE(szSeverityString));
SendDlgItemMessage(IDC_COMBO_SEVERITY, CB_ADDSTRING, 0, (LPARAM) szSeverityString);
LoadString(_Module.GetResourceInstance(), IDS_SEVERITY_4, szSeverityString, ARRAYSIZE(szSeverityString));
SendDlgItemMessage(IDC_COMBO_SEVERITY, CB_ADDSTRING, 0, (LPARAM) szSeverityString);
//
// Initialize m_crAnchor. Ideally we could read this from IE's registry,
// but many other dialogs don't do that and we just don't have time now.
// We'll default to pure blue, since that is the IE default.
//
m_crAnchor = RGB(0, 0, 255);
//
// Initialize m_szHyperlinkText from the IDS_HYPERLINK_TEXT string resource.
//
m_bShowHyperlink = TRUE;
if (LoadString(_Module.GetResourceInstance(), IDS_HYPERLINK_TEXT, m_szHyperlinkText, ARRAYSIZE(m_szHyperlinkText)) == 0)
m_bShowHyperlink = FALSE;
//
// Initialize m_szHyperlinkCmdLine from the registry.
//
if (m_bShowHyperlink)
if ((dwRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
_T("Software\\Microsoft\\PCHealth\\Clients\\Dialog Comments"),
0,
KEY_QUERY_VALUE,
&hKey)) != ERROR_SUCCESS) {
DebugTrace(0, "No HKCU\\Software\\Microsoft\\PCHealth\\Clients\\Dialog Comments key in the registry (RegOpenKeyEx returned %ld)", dwRet);
m_bShowHyperlink = FALSE;
}
else {
DWORD dwDataSize = sizeof(m_szHyperlinkCmdLine);
if ((dwRet = RegQueryValueEx(hKey,
_T("Hyperlink command line"),
NULL,
NULL,
(LPBYTE) m_szHyperlinkCmdLine,
&dwDataSize)) != ERROR_SUCCESS) {
DebugTrace(0, "No Hyperlink command line value in the HKLM\\Software\\Microsoft\\PCHealth\\Clients\\Dialog Comments registry key (RegQueryValueEx returned %ld)", dwRet);
m_szHyperlinkCmdLine[0] = 0;
m_bShowHyperlink = FALSE;
}
else
DebugTrace(0, "Hyperlink command line in the registry: %s", m_szHyperlinkCmdLine);
RegCloseKey(hKey);
}
//
// Disable the hyperlink-related controls if we cannot successfully display
// and launch the hyperlink.
//
if (!m_bShowHyperlink) {
::SetWindowPos(GetDlgItem(IDC_STATIC_HELP_AND_SUPPORT_1), 0, 0, 0, 0, 0, SWP_HIDEWINDOW + SWP_NOMOVE + SWP_NOSIZE + SWP_NOZORDER);
::SetWindowPos(GetDlgItem(IDC_STATIC_HELP_AND_SUPPORT_2), 0, 0, 0, 0, 0, SWP_HIDEWINDOW + SWP_NOMOVE + SWP_NOSIZE + SWP_NOZORDER);
::SetWindowPos(GetDlgItem(IDC_BUTTON_HYPERLINK), 0, 0, 0, 0, 0, SWP_HIDEWINDOW + SWP_NOMOVE + SWP_NOSIZE + SWP_NOZORDER);
}
//
// Set the focus to:
// Email address if the user hasn't entered it before.
// Otherwise beta ID if the user hasn't entered it before.
// Otherwise the event category dropdown.
//
if (SendDlgItemMessage(IDC_EDIT_EMAIL_ADDRESS, WM_GETTEXTLENGTH, 0, 0) == 0)
GotoDlgCtrl(GetDlgItem(IDC_EDIT_EMAIL_ADDRESS));
else if (SendDlgItemMessage(IDC_EDIT_BETA_ID, WM_GETTEXTLENGTH, 0, 0) == 0)
GotoDlgCtrl(GetDlgItem(IDC_EDIT_BETA_ID));
else
GotoDlgCtrl(GetDlgItem(IDC_COMBO_EVENT_CATEGORY));
m_bHyperlinkHasFocus = FALSE;
TraceFunctLeave();
bHandled = TRUE;
return FALSE; // We set the focus, return FALSE to prevent O/S from setting focus.
}
//
// CSurveyDlg::OnDrawItem: Draws owner-drawn controls (we have only one: IDC_BUTTON_HYPERLINK)
//
LRESULT
CSurveyDlg::OnDrawItem(
UINT uMsg,
WPARAM wParam,
LPARAM lParam,
BOOL& bHandled
)
{
TraceFunctEnter("OnDrawItem");
HWND hwndHyperlink = NULL;
HDC hdcHyperlink = NULL;
HFONT hfontHelpAndSupport2 = NULL;
HFONT hfontHyperlinkOld = NULL;
HFONT hfontHyperlinkNew = NULL;
LOGFONT lfHyperlinkNew;
RECT rectHyperlink;
//
// If we cannot successfully display and launch the hyperlink, return now.
//
if (wParam != IDC_BUTTON_HYPERLINK)
goto Done;
if (!m_bShowHyperlink)
goto Done;
//
// Get the DC for IDC_BUTTON_HYPERLINK.
//
if ((hwndHyperlink = GetDlgItem(IDC_BUTTON_HYPERLINK)) == NULL)
goto Done;
if ((hdcHyperlink = ::GetDC(hwndHyperlink)) == NULL)
goto Done;
//
// Get the font used to draw IDC_STATIC_HELP_AND_SUPPORT_2. Create a new
// font based on that one but with underline.
//
if ((hfontHelpAndSupport2 = (HFONT) SendDlgItemMessage(IDC_STATIC_HELP_AND_SUPPORT_2, WM_GETFONT, 0, 0)) == NULL)
goto Done;
if (!GetObject(hfontHelpAndSupport2, sizeof(LOGFONT), &lfHyperlinkNew))
goto Done;
lfHyperlinkNew.lfUnderline = TRUE;
if ((hfontHyperlinkNew = CreateFontIndirect(&lfHyperlinkNew)) == NULL)
goto Done;
//
// For IDC_BUTTON_HYPERLINK, select the new underline font but don't delete
// the original font.
//
hfontHyperlinkOld = (HFONT) SelectObject(hdcHyperlink, hfontHyperlinkNew);
if ((hfontHyperlinkOld == NULL) || (hfontHyperlinkOld == (HFONT) (ULONG_PTR)GDI_ERROR))
goto Done;
//
// Draw the text using the IE anchor color. Center the text horizontally in
// the button.
//
SetTextColor(hdcHyperlink, m_crAnchor);
SetTextAlign(hdcHyperlink, TA_CENTER | TA_TOP);
SetBkMode(hdcHyperlink, TRANSPARENT);
::GetClientRect(hwndHyperlink, &rectHyperlink);
ExtTextOut(hdcHyperlink, (rectHyperlink.right / 2) + 1, 0, 0, NULL, m_szHyperlinkText, _tcslen(m_szHyperlinkText), NULL);
//
// For IDC_BUTTON_HYPERLINK, select the original font.
//
SelectObject(hdcHyperlink, hfontHyperlinkOld);
//
// Clean up.
//
Done:
//
// Delete the new font we created.
//
if (hfontHyperlinkNew != NULL)
DeleteObject(hfontHyperlinkNew);
//
// Release the DC for IDC_BUTTON_HYPERLINK.
//
if (hdcHyperlink != NULL)
::ReleaseDC(hwndHyperlink, hdcHyperlink);
//
// Return.
//
TraceFunctLeave();
bHandled = TRUE;
return TRUE;
}
//
// CSurveyDlg::OnSetCursor: Sets the cursor to the hand if the mouse is over the hyperlink window
//
LRESULT
CSurveyDlg::OnSetCursor(
UINT uMsg,
WPARAM wParam,
LPARAM lParam,
BOOL& bHandled
)
{
TraceFunctEnter("OnSetCursor");
if (m_bShowHyperlink && ((HWND) wParam == GetDlgItem(IDC_BUTTON_HYPERLINK))) {
HCURSOR hcursor = LoadCursor(NULL, IDC_HAND);
SetCursor(hcursor);
TraceFunctLeave();
bHandled = TRUE;
return TRUE;
}
TraceFunctLeave();
bHandled = FALSE;
return FALSE;
}
//
// HyperlinkCmdHandler: Handles messages from the IDC_BUTTON_HYPERLINK button
//
LRESULT
CSurveyDlg::HyperlinkCmdHandler(
WORD wNotifyCode,
WORD wID,
HWND hWndCtl,
BOOL& bHandled
)
{
TraceFunctEnter("HyperlinkCmdHandler");
//
// If we gained or lost focus, update the focus rectangle.
//
if ((wNotifyCode == BN_SETFOCUS) || (wNotifyCode == BN_KILLFOCUS)) {
HDC hdc;
RECT rect;
hdc = ::GetDC(hWndCtl);
::GetClientRect(hWndCtl, &rect);
DrawFocusRect(hdc, &rect);
::ReleaseDC(hWndCtl, hdc);
m_bHyperlinkHasFocus = (wNotifyCode == BN_SETFOCUS);
}
//
// If we were clicked, launch the hyperlink program.
//
else if ((wNotifyCode = BN_CLICKED) || (wNotifyCode = BN_DOUBLECLICKED)) {
DebugTrace(0, "User clicked IDC_BUTTON_HYPERLINK");
TCHAR szCmdLine[2048];
DWORD dwRet;
dwRet = ExpandEnvironmentStrings(m_szHyperlinkCmdLine, szCmdLine, 2048);
if ((dwRet == 0) || (dwRet > 2048)) {
DebugTrace(0, "ExpandEnvironmentStrings() failed on cmdline \"%s\" with error %ld", m_szHyperlinkCmdLine, GetLastError());
TCHAR szMsg[1024];
TCHAR szTitle[1024];
if ((LoadString(_Module.GetResourceInstance(), IDS_HYPERLINK_PROGRAM_FAILED, szMsg, ARRAYSIZE(szMsg)) != 0) &&
(LoadString(_Module.GetResourceInstance(), IDS_HYPERLINK_PROGRAM_FAILED_TITLE, szTitle, ARRAYSIZE(szTitle)) != 0))
MessageBox(szMsg, szTitle, MB_OK);
}
else {
TCHAR szWindowsDir[MAX_PATH];
STARTUPINFO si;
PROCESS_INFORMATION pi;
if (!GetSystemWindowsDirectory(szWindowsDir, MAX_PATH))
szWindowsDir[0] = 0;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
if (CreateProcess(NULL, szCmdLine, NULL, NULL, FALSE, 0, NULL, szWindowsDir, &si, &pi)) {
DebugTrace(0, "CreateProcess() succeeded on cmdline \"%s\" with PID %ld, TID %ld", szCmdLine, pi.dwProcessId, pi.dwThreadId);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
else {
DebugTrace(0, "CreateProcess() failed cmdline \"%s\" with error %ld", szCmdLine, GetLastError());
TCHAR szMsg[1024];
TCHAR szTitle[1024];
if ((LoadString(_Module.GetResourceInstance(), IDS_HYPERLINK_PROGRAM_FAILED, szMsg, ARRAYSIZE(szMsg)) != 0) &&
(LoadString(_Module.GetResourceInstance(), IDS_HYPERLINK_PROGRAM_FAILED_TITLE, szTitle, ARRAYSIZE(szTitle)) != 0))
MessageBox(szMsg, szTitle, MB_OK);
}
}
}
TraceFunctLeave();
bHandled = TRUE;
return 0;
}
//
// CSurveyDlg::OnOK: Executes when user has done typing the comment
// and has hit submit
LRESULT
CSurveyDlg::OnOK(
WORD wNotifyCode,
WORD wID,
HWND hWndCtl,
BOOL& bHandled
)
{
TraceFunctEnter("OnOK");
//
// When IDC_BUTTON_HYPERLINK has focus and the user presses Enter, IDOK is
// generated for some reason. I think this is because IDC_BUTTON_HYPERLINK
// is owner-drawn. Anyway, if IDC_BUTTON_HYPERLINK currently has focus then
// send BM_CLICK to that control and return immediately.
//
if (m_bHyperlinkHasFocus) {
DebugTrace(0, "User clicked IDC_BUTTON_HYPERLINK, sending BM_CLICK to that control");
SendDlgItemMessage(IDC_BUTTON_HYPERLINK, BM_CLICK, 0, 0);
TraceFunctLeave();
bHandled = TRUE;
return 0;
}
//
// verify that the user entered all required data.
//
if (SendDlgItemMessage(IDC_COMBO_EVENT_CATEGORY, CB_GETCURSEL, 0, 0) == CB_ERR) {
DebugTrace(0, "User did not select an event category, calling MessageBox");
TCHAR szMessageBoxTitle[1024];
TCHAR szMessageBoxText[1024];
LoadString(_Module.GetResourceInstance(), IDS_NEED_EVENT_CATEGORY, szMessageBoxText, ARRAYSIZE(szMessageBoxText));
LoadString(_Module.GetResourceInstance(), IDS_NEED_EVENT_CATEGORY_TITLE, szMessageBoxTitle, ARRAYSIZE(szMessageBoxTitle));
MessageBox(szMessageBoxText, szMessageBoxTitle, MB_OK);
DebugTrace(0, "OnOK exiting but not calling EndDialog");
TraceFunctLeave();
bHandled = TRUE;
return 0;
}
if (SendDlgItemMessage(IDC_COMBO_SEVERITY, CB_GETCURSEL, 0, 0) == CB_ERR) {
DebugTrace(0, "User did not select a severity, calling MessageBox");
TCHAR szMessageBoxTitle[1024];
TCHAR szMessageBoxText[1024];
LoadString(_Module.GetResourceInstance(), IDS_NEED_SEVERITY, szMessageBoxText, ARRAYSIZE(szMessageBoxText));
LoadString(_Module.GetResourceInstance(), IDS_NEED_SEVERITY_TITLE, szMessageBoxTitle, ARRAYSIZE(szMessageBoxTitle));
MessageBox(szMessageBoxText, szMessageBoxTitle, MB_OK);
DebugTrace(0, "OnOK exiting but not calling EndDialog");
TraceFunctLeave();
bHandled = TRUE;
return 0;
}
if (SendDlgItemMessage(IDC_EDIT_COMMENT, WM_GETTEXTLENGTH, 0, 0) == 0) {
DebugTrace(0, "User did not type in a comment, calling MessageBox");
TCHAR szMessageBoxTitle[1024];
TCHAR szMessageBoxText[1024];
LoadString(_Module.GetResourceInstance(), IDS_NEED_COMMENT, szMessageBoxText, ARRAYSIZE(szMessageBoxText));
LoadString(_Module.GetResourceInstance(), IDS_NEED_COMMENT_TITLE, szMessageBoxTitle, ARRAYSIZE(szMessageBoxTitle));
MessageBox(szMessageBoxText, szMessageBoxTitle, MB_OK);
DebugTrace(0, "OnOK exiting but not calling EndDialog");
TraceFunctLeave();
bHandled = TRUE;
return 0;
}
//
// Write the email address and beta ID for this user to the registry.
//
SendDlgItemMessage(IDC_EDIT_EMAIL_ADDRESS, WM_GETTEXT, MAX_EMAIL_ADDRESS_SIZE + 1, (LPARAM) m_lldata.szEmailAddress);
SendDlgItemMessage(IDC_EDIT_BETA_ID, WM_GETTEXT, MAX_BETA_ID_SIZE + 1, (LPARAM) m_lldata.szBetaID);
HKEY hKey;
DWORD dwRet;
if ((dwRet = RegCreateKeyEx(HKEY_CURRENT_USER,
_T("Software\\Microsoft\\PCHealth\\Clients\\Dialog Comments"),
0,
_T(""),
REG_OPTION_NON_VOLATILE,
KEY_READ + KEY_SET_VALUE,
NULL,
&hKey,
NULL)) != ERROR_SUCCESS) {
DebugTrace(0, "Could not create HKCU\\Software\\Microsoft\\PCHealth\\Clients\\Dialog Comments key in the registry (RegCreateKeyEx returned %ld)", dwRet);
}
else {
if ((dwRet = RegSetValueEx(hKey,
_T("Email Address"),
NULL,
REG_SZ,
(LPBYTE) m_lldata.szEmailAddress,
(_tcslen(m_lldata.szEmailAddress) + 1) * sizeof(TCHAR))) != ERROR_SUCCESS)
DebugTrace(0, "Failed to write Email Address value to the HKCU\\Software\\Microsoft\\PCHealth\\Clients\\Dialog Comments registry key (RegSetValueEx returned %ld)", dwRet);
else
DebugTrace(0, "Wrote email address for this user to the registry: %s", m_lldata.szEmailAddress);
if ((dwRet = RegSetValueEx(hKey,
_T("Beta ID"),
NULL,
REG_SZ,
(LPBYTE) m_lldata.szBetaID,
(_tcslen(m_lldata.szBetaID) + 1) * sizeof(TCHAR))) != ERROR_SUCCESS)
DebugTrace(0, "Failed to write Beta ID value to the HKCU\\Software\\Microsoft\\PCHealth\\Clients\\Dialog Comments registry key (RegSetValueEx returned %ld)", dwRet);
else
DebugTrace(0, "Wrote beta ID for this user to the registry: %s", m_lldata.szBetaID);
RegCloseKey(hKey);
}
//
// Call the routine to format data collected and transport
// it to server
DebugTrace(0, "Calling GetInfoAndLogLameButton");
GetInfoAndLogLameButton();
//
// Kill the comment dialog
//
DebugTrace(0, "Calling EndDialog on wID: %ld", wID);
EndDialog(wID);
TraceFunctLeave();
bHandled = TRUE;
return 0;
}
//
// CSurveyDlg::OnCancel: This executes when user cancels the comment
//
LRESULT
CSurveyDlg::OnCancel(
WORD wNotifyCode,
WORD wID,
HWND hWndCtl,
BOOL& bHandled
)
{
//
// Kill the comment dialog
//
EndDialog(wID);
bHandled = TRUE;
return 0;
}
//
// CSurveyDlg::IsMessageBox: This routine returns TRUE if the m_hwndTarget is indeed
// a message box
//
BOOL
CSurveyDlg::IsMessageBox()
{
TraceFunctEnter("CSurveyDlg::IsMessageBox");
BOOL fRetVal = FALSE;
LPMSGBOXPARAMS lpMsgData = NULL;
UINT cbSize = 0;
if(NULL == m_hwndTarget)
{
FatalTrace(0, "m_hwndTarget is NULL");
goto done;
}
//
// Looking at msgbox.c, I realized that the MsgBoxParams are stored in the MessageBox
// dialog itself using a SetWindowLongPtr. Hence GetWindowLongPtr should retrieve it for
// messageboxes.
//
lpMsgData = (LPMSGBOXPARAMS)::GetWindowLongPtr(m_hwndTarget, GWLP_USERDATA);
if(NULL == lpMsgData)
{
FatalTrace(0, "GetWindowLongPtr failed. Error: %ld", GetLastError());
fRetVal = FALSE;
goto done;
}
//
// There are windows other than msgboxes that can have data set in WindowLongPtr
// The following is a check to see if we have a message box or not. If this is not
// a real message box, it will throw an exception when we try to read cbSize for
// some cases.
//
DebugTrace(0, "Figuring if this is a msgbox. Addr: %ld", lpMsgData);
__try
{
cbSize = lpMsgData->cbSize;
}
__except( EXCEPTION_EXECUTE_HANDLER )
{
FatalTrace(0, "Corrupt MSGBOXPARAMS");
goto done;
}
DebugTrace(0, "cbSize: %ld", cbSize);
//
// Some more sanity checks
//
if(( cbSize > MSGBOX_TEXT_SIZE)||( cbSize < sizeof(MSGBOXPARAMS)))
{
FatalTrace(0, "Invalid MSGBOXPARAMS");
goto done;
}
else
{
//
// We have a MessageBox
//
fRetVal = TRUE;
//
// Extract the message box text from the MSGBOXPARAMS
//
// NTRAID#NTBUG9-155100-2000/08/13-jasonr
//
// Before we determined the maximum number of characters to copy from
// cbsize. I have no idea why we were doing that. Now the maximum is
// based on the size of the m_lldata.szMsgBoxText buffer. I wrapped the
// copy within a __try __except block just to be safe.
//
ZeroMemory(m_lldata.szMsgBoxText, sizeof(m_lldata.szMsgBoxText));
__try
{
_tcsncpy((_TCHAR *) m_lldata.szMsgBoxText, (const _TCHAR *) lpMsgData->lpszText, (sizeof(m_lldata.szMsgBoxText) / sizeof(_TCHAR)) - 1);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
}
DebugTrace(0,"MessageBox Text: %ls\n", m_lldata.szMsgBoxText);
}
done:
TraceFunctLeave();
return fRetVal;
}
//
// CSurveyDlg::GetInfoAndLogLameButton: The routine that does most of the work to gather
// and format the comment information and uploads
// it to server
void
CSurveyDlg::GetInfoAndLogLameButton()
{
TraceFunctEnter("GetInfoAndLogLameButton");
m_lldata.versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
//
// Get version of binary that launched the comments hook
//
GetVersionEx(&m_lldata.versionInfo);
TCHAR szClass[CLASS_SIZE];
TCHAR szTitle[TITLE_SIZE];
TCHAR szComment[COMMENT_TEXT_SIZE + 1];
TCHAR szText[1024];
//
// Clear out buffers First
//
ZeroMemory(m_lldata.szTitle, TITLE_SIZE);
ZeroMemory(m_lldata.szClass, CLASS_SIZE);
ZeroMemory(m_lldata.szMsgBoxText, MSGBOX_TEXT_SIZE);
//
// Gather the Title of the target window
//
if (::GetWindowText(m_hwndTarget, szTitle, TITLE_SIZE) == 0)
{
DebugTrace(0, "szTitle is NULL");
ZeroMemory(m_lldata.szTitle, TITLE_SIZE);
}
else
{
_tcscpy(m_lldata.szTitle, szTitle);
}
DebugTrace(0, "m_lldata.szTitle: %ls", m_lldata.szTitle);
//
// Gather the class of the target Window
//
if (::RealGetWindowClass(m_hwndTarget, szClass, CLASS_SIZE) == 0)
{
DebugTrace(0, "szClass is NULL");
ZeroMemory(m_lldata.szClass, CLASS_SIZE);
}
else
{
_tcscpy(m_lldata.szClass, szClass);
}
DebugTrace(0, "m_lldata.szClass: %ls", m_lldata.szClass);
//
// Check if m_hwndTarget is a MessageBox.
//
if(TRUE == IsMessageBox())
{
//
// We are dealing with a Message Box
//
DebugTrace(0, "We are dealing with a Message Box");
//
// The following disabled code is for reference reasons,
// Earlier, we used to send a WM_COPY to obtain the message box text
// Now, IsMessageBox does the trick
#ifdef _SEND_WM_COPY
if(NULL != m_hwndTarget)
{
HANDLE hMem = NULL;
WCHAR *pData = NULL;
TCHAR szTitleTmp [MSGBOX_TEXT_SIZE];
INT nChar = 0;
INT nChar1 = 0;
//
// Send WM_COPY to the message box. WM_COPY causes the MessageBox to write
// it's message box text to the clipboard
//
DebugTrace(0, "Sending WM_COPY to m_hwndTarget");
SendMessage( m_hwndTarget, WM_COPY, 0, 0 );
//
// Open the clipboard of the current task
//
DebugTrace(0, "OpenClipboard");
if(FALSE == ::OpenClipboard( m_hwndTarget ))
{
FatalTrace(0, "OpenClipBoard failed. Error: %ld", GetLastError());
goto done;
}
//
// Get the Data written by the target Window to the Clipboard
//
DebugTrace(0, "GetClipboardData");
hMem = GetClipboardData( CF_UNICODETEXT );
if(NULL == hMem)
{
FatalTrace(0, "GetClipBoardData failed. Error: %ld\n", GetLastError());
goto done;
}
//
// Get the memory location for the data written to the clipboard
//
DebugTrace(0, "GlobalLock");
pData = (LPWSTR) GlobalLock( hMem );
if(NULL == pData)
{
FatalTrace(0, "GlobalLock failed. Error: %ld\n", GetLastError());
goto done;
}
if(pData[0] == '\0')
{
FatalTrace(0, "Nothing in clipboard");
goto done;
}
//
// Advance past the first ---------------------------\r\n
//
DebugTrace(0, "Advancing past the first ---");
for(nChar = 0; (nChar < _tcslen(pData))&&(!((pData[nChar] == '-')&&(pData[nChar+1] == '\r')&&(pData[nChar+2] == '\n'))); nChar++);
//
// Check to see if we have data in the right format.
//
if ( nChar == _tcslen(pData))
{
//
// This check is necessary, because the check for messagebox based on the window class
// is best effort and not 100% accurate. So, we may think that the target window is a
// message box, where as it may not be. This check is therefore necessary.
FatalTrace(0, "This is not a valid messagebox");
goto done;
}
nChar += 3;
DebugTrace(0, "nChar: %ld", nChar);
//
// Extract the Caption
//
DebugTrace(0, "Extracting the Caption");
for(nChar1 = 0; !((pData[nChar] == '\r')&&(pData[nChar+1] == '\n')&&(pData[nChar+2] == '-')); nChar1++,nChar++)
{
szTitleTmp[ nChar1 ] = pData[nChar];
}
nChar += 2;
DebugTrace(0, "nChar: %ld", nChar);
szTitleTmp[ nChar1 + 1] = '\0';
DebugTrace(0, "MessageBox Title: %ls", szTitleTmp);
//
// Advance past the second ---------------------------\r\n
//
DebugTrace(0, "Advancing past the second ---");
for(; !((pData[nChar] == '-')&&(pData[nChar+1] == '\r')&&(pData[nChar+2] == '\n')); nChar++);
nChar += 3;
DebugTrace(0, "nChar: %ld", nChar);
//
// Extract the message box text
//
DebugTrace(0, "Extracting the MessageBox text");
for(nChar1 = 0; !((pData[nChar] == '\r')&&(pData[nChar+1] == '\n')&&(pData[nChar+2] == '-')); nChar1++,nChar++)
{
m_lldata.szMsgBoxText[ nChar1 ] = pData[nChar];
}
m_lldata.szMsgBoxText[ nChar1 + 1] = '\0';
DebugTrace(0,"MessageBox szText: %ls", m_lldata.szMsgBoxText);
//
// Clear out the clipboard
//
EmptyClipboard();
done:
if(NULL != hMem)
{
if(FALSE == GlobalUnlock( hMem ))
{
printf("GlobalUnlock failed. Error; %ld\n", GetLastError());
}
}
CloseClipboard();
}
#endif // _SEND_WM_COPY
}
else
{
DebugTrace(0, "class: %s is not a MessageBox", szClass);
}
//
// Obtain the Comment
//
if (GetDlgItemText(IDC_EDIT_COMMENT, szComment, COMMENT_TEXT_SIZE + 1) == 0)
{
DebugTrace(0, "Comment is NULL");
ZeroMemory(m_lldata.szComment, COMMENT_TEXT_SIZE + 1);
}
else
{
_tcscpy(m_lldata.szComment, szComment);
}
DebugTrace(0, "sizeof Comment text: %ld", _tcslen( m_lldata.szComment ));
//
// Populate m_lldata.dwEventCategory from the selection in
// IDC_COMBO_EVENT_CATEGORY. Note that this is purposefully done with a
// switch statement, rather than with an algorithmic calculation such as:
//
// m_lldata.dwEventCategory = 1 + SendDlgItemMessage(IDC_COMBO_EVENT_CATEGORY, CB_GETCURSEL, 0, 0);
//
// If we ever change the possible selections in the future, the algorithm
// might not be correct, so we don't use it.
//
LRESULT dwCurSel = SendDlgItemMessage(IDC_COMBO_EVENT_CATEGORY, CB_GETCURSEL, 0, 0);
_ASSERT(dwCurSel == 0 || dwCurSel == 1 || dwCurSel == 2 || dwCurSel == 3 || dwCurSel == 4 || dwCurSel == 5);
switch (dwCurSel) {
case 0:
m_lldata.dwEventCategory = 1;
break;
case 1:
m_lldata.dwEventCategory = 2;
break;
case 2:
m_lldata.dwEventCategory = 3;
break;
case 3:
m_lldata.dwEventCategory = 4;
break;
case 4:
m_lldata.dwEventCategory = 5;
break;
case 5:
m_lldata.dwEventCategory = 6;
break;
}
//
// Populate m_lldata.dwSeverity from the selection in IDC_COMBO_SEVERITY.
// Note that this is purposefully done with a switch statement, rather than
// with an algorithmic calculation such as:
//
// m_lldata.dwSeverity = 1 + SendDlgItemMessage(IDC_COMBO_SEVERITY, CB_GETCURSEL, 0, 0);
//
// If we ever change the possible selections in the future, the algorithm
// might not be correct, so we don't use it.
//
dwCurSel = SendDlgItemMessage(IDC_COMBO_SEVERITY, CB_GETCURSEL, 0, 0);
_ASSERT(dwCurSel == 0 || dwCurSel == 1 || dwCurSel == 2 || dwCurSel == 3);
switch (dwCurSel) {
case 0:
m_lldata.dwSeverity = 1;
break;
case 1:
m_lldata.dwSeverity = 2;
break;
case 2:
m_lldata.dwSeverity = 3;
break;
case 3:
m_lldata.dwSeverity = 4;
break;
}
//
// It doesn't seem like a good idea to initialize COM on somebody
// else's thread, so we launch a new thread to do the reporting.
//
DebugTrace(0, "Creating Seperate thread to deal with COM");
UINT uThreadId; // dummy
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, LogLameButtonThread, &m_lldata, 0, &uThreadId);
if (hThread != 0) {
DWORD dwEvent = WaitForSingleObject(hThread, INFINITE);
_ASSERT(dwEvent == WAIT_OBJECT_0);
//
// 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.
//
DWORD dwExitCode;
if (!GetExitCodeThread(hThread, &dwExitCode))
dwExitCode = 1;
CloseHandle(hThread);
TCHAR szThankYouMessage[1024];
TCHAR szThankYouMessageTitle[1024];
LoadString(_Module.GetResourceInstance(),
IDS_THANK_YOU,
szThankYouMessage,
ARRAYSIZE(szThankYouMessage));
LoadString(_Module.GetResourceInstance(),
IDS_THANK_YOU_TITLE,
szThankYouMessageTitle,
ARRAYSIZE(szThankYouMessageTitle));
MessageBox(szThankYouMessage, szThankYouMessageTitle, MB_OK);
}
TraceFunctLeave();
}
//
// DllMain : The DllMain for LAMEBTN.DLL
//
BOOL WINAPI DllMain
(
HINSTANCE hInstance,
DWORD dwreason,
LPVOID reserved
)
{
switch (dwreason) {
case DLL_PROCESS_ATTACH:
// _CrtSetBreakAlloc(275);
#ifndef NOTRACE
InitAsyncTrace();
#endif
ghDllInst = hInstance;
DisableThreadLibraryCalls(hInstance);
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_WNDW);
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG);
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);
_Module.Init(NULL, hInstance);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
_CrtDumpMemoryLeaks();
_Module.Term();
TermAsyncTrace();
break;
}
return TRUE;
}
//
// LogLameButtonThread: This is the thread spawned by the comments dialog
// to format the data collected into XML and upload
// to server
unsigned int __stdcall
LogLameButtonThread(
void* pvLogData
)
{
TraceFunctEnter("LogLameButtonThread");
//
// 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;
//
// Initialize COM
//
DebugTrace(0, "Initializing COM");
HRESULT hrCoInit = CoInitializeEx(NULL, COINIT_MULTITHREADED);
HRESULT hr = S_OK;
if (SUCCEEDED(hrCoInit)) {
//
// Create a temp file that will hold a minidump of the current process.
//
WCHAR szTempPath[MAX_PATH];
if ((GetTempPathW(MAX_PATH, szTempPath) == 0) || (GetTempFileNameW(szTempPath, _T("EMI"), 0, ((LAMELOGDATA *) pvLogData)->szMiniDumpPath) == 0)) {
DebugTrace(0, "GetTempPathW() or GetTempFileNameW() failed, minidump will not be created");
((LAMELOGDATA *) pvLogData)->szMiniDumpPath[0] = 0;
}
else {
DebugTrace(0, "Minidump will be stored in temp file \"%s\"", ((LAMELOGDATA *) pvLogData)->szMiniDumpPath);
//
// Build a command line for executing DUMPREP.EXE.
//
WCHAR szWindowsDir[MAX_PATH+1];
WCHAR szCmdLine[1024];
ZeroMemory(szWindowsDir, sizeof(szWindowsDir));
ZeroMemory(szCmdLine, sizeof(szCmdLine));
GetSystemWindowsDirectoryW(szWindowsDir, MAX_PATH);
wsprintf(szCmdLine, L"%s\\system32\\dumprep.exe %lu -d 7 7 \"%s\"", szWindowsDir, GetCurrentProcessId(), ((LAMELOGDATA *) pvLogData)->szMiniDumpPath);
//
// CreateProcess() on DUMPREP.EXE to create the minidump.
//
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
if (!CreateProcessW(NULL, szCmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
DebugTrace(0, "CreateProcess() failed cmdline \"%s\" with error %ld; minidump will not be created", szCmdLine, GetLastError());
DeleteFileW(((LAMELOGDATA *) pvLogData)->szMiniDumpPath);
((LAMELOGDATA *) pvLogData)->szMiniDumpPath[0] = 0;
}
else {
DebugTrace(0, "CreateProcess() succeeded on cmdline \"%s\" with PID %ld, TID %ld; waiting up to 60 seconds...", szCmdLine, pi.dwProcessId, pi.dwThreadId);
//
// Wait for DUMPREP.EXE to exit and interpret the exit code:
// frrvOk (defined in faultrep.h) is success; anything else is
// failure. Wait for a maximum of 60 seconds.
//
DWORD dwRet;
BOOL bSuccess = FALSE;
switch (dwRet = WaitForSingleObject(pi.hProcess, 60000)) {
case WAIT_OBJECT_0:
DebugTrace(0, "The process handle is signalled");
if (!GetExitCodeProcess(pi.hProcess, &dwRet)) {
DebugTrace(0, "GetExitCodeProcess() failed; GetLastError() = %lu; minidump will not be created", GetLastError());
DeleteFileW(((LAMELOGDATA *) pvLogData)->szMiniDumpPath);
((LAMELOGDATA *) pvLogData)->szMiniDumpPath[0] = 0;
}
else if (dwRet != frrvOk) {
DebugTrace(0, "The process failed with exit code %lu; minidump will not be created", dwRet);
DeleteFileW(((LAMELOGDATA *) pvLogData)->szMiniDumpPath);
((LAMELOGDATA *) pvLogData)->szMiniDumpPath[0] = 0;
}
else {
DebugTrace(0, "The process exited and the minidump was created successfully");
bSuccess = TRUE;
}
break;
case WAIT_TIMEOUT:
DebugTrace(0, "WaitForSingleObject() returned WAIT_TIMEOUT after 60 seconds; minidump will not be created");
DeleteFileW(((LAMELOGDATA *) pvLogData)->szMiniDumpPath);
((LAMELOGDATA *) pvLogData)->szMiniDumpPath[0] = 0;
break;
case WAIT_FAILED:
DebugTrace(0, "WaitForSingleObject() returned WAIT_FAILED, GetLastError() = %lu; minidump will not be created", GetLastError());
DeleteFileW(((LAMELOGDATA *) pvLogData)->szMiniDumpPath);
((LAMELOGDATA *) pvLogData)->szMiniDumpPath[0] = 0;
break;
default:
DebugTrace(0, "WaitForSingleObject() returned unknown code %lu, GetLastError() = %lu; minidump will not be created", dwRet, GetLastError());
DeleteFileW(((LAMELOGDATA *) pvLogData)->szMiniDumpPath);
((LAMELOGDATA *) pvLogData)->szMiniDumpPath[0] = 0;
break;
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
if (bSuccess) {
//
// Create a .CAB file
//
WCHAR szCABPath[MAX_PATH+1];
wcscpy(szCABPath, ((LAMELOGDATA *) pvLogData)->szMiniDumpPath);
wcscat(szCABPath, L".cab");
if (FAILED(MPC::CompressAsCabinet(((LAMELOGDATA *) pvLogData)->szMiniDumpPath, szCABPath, L"minidump.dmp")) ||
!MoveFileExW(szCABPath, ((LAMELOGDATA *) pvLogData)->szMiniDumpPath, MOVEFILE_REPLACE_EXISTING + MOVEFILE_WRITE_THROUGH)) {
DebugTrace(0, "MPC::CompressAsCabinet failed (more likely) or MoveFileExW failed (less likely); minidump will not be created");
DeleteFileW(((LAMELOGDATA *) pvLogData)->szMiniDumpPath);
DeleteFileW(szCABPath);
((LAMELOGDATA *) pvLogData)->szMiniDumpPath[0] = 0;
}
else
DebugTrace(0, "The minidump was compressed successfully as a .CAB file");
}
}
}
//
// Call the Routine that does the real work (defined in logging.cpp)
//
DebugTrace(0, "Calling LogLameBtn");
iRet = LogLameButton((LAMELOGDATA*) (pvLogData));
CoUninitialize();
}
else
{
FatalTrace(0, "Failed to initialize COM");
goto done;
}
done:
TraceFunctLeave();
return iRet;
}
//
// CommentReport: user calls into CommentReport passing in the hWnd and call stack when
// the Comments? link is clicked (This is the routine called via the Comments hook)
VOID WINAPI
CommentReport(
HWND hwnd, // [in] Window of Dialog being commented on
PVOID pv // [in] Call stack
)
{
TraceFunctEnter("CommentReport");
//
// Fix for bug 141367. Walk up through the stack of windows examining the
// module file name of each one. Count the number of windows that are owned
// by lamebtn.dll. If we find two it means there are two lamebtn dialogs on
// the screen already. In that case, return immediately. (We allow up to
// two of them so the user can comment on the lamebtn dialog itself.)
//
HMODULE hThisModule = NULL;
if ((hThisModule = GetModuleHandle(L"lamebtn.dll")) != NULL)
{
TCHAR szThisModule[MAX_PATH] = { 0 };
if (GetModuleFileName(hThisModule, szThisModule, MAX_PATH) > 0)
{
HWND hWnd2 = hwnd;
TCHAR szWndModule[MAX_PATH] = { 0 };
DWORD dwLamebtnDLLWindows = 0;
while (hWnd2 != NULL)
{
if ((GetWindowModuleFileName(hWnd2, szWndModule, MAX_PATH) > 0) &&
(_wcsicmp(szThisModule, szWndModule) == 0))
{
dwLamebtnDLLWindows++;
if (dwLamebtnDLLWindows >= 2) {
DebugTrace(0, "Two lamebtn dialogs are already up, therefore we won't bring up another one");
return;
}
}
hWnd2 = GetParent(hWnd2);
}
}
}
#ifdef _GENERATE_STACK_AT_CLIENT
TCHAR szWindowText[MAX_BUF_SIZE + 1];
TCHAR szBigBuff[2 * MAX_BUF_SIZE + 1];
TCHAR tmpbuf[128 + 1];
//
// Obtain the WindowText
//
GetWindowText(hwnd, szWindowText, MAX_BUF_SIZE);
//
// pvStackTrace can be NULL
//
if(pv)
{
wsprintf(tmpbuf, TEXT("\t(%x) = %x\n\t(%x) = %x\n\t(%x) = %x\n\t(%x) = %x"), ((int*)pv+12), (int)*((int*)pv+12), ((int*)pv+8),(int)*((int*)pv+8), ((int*)pv+4), (int)*((int*)pv+4),((int*)pv), (int)*((int*)pv));
}
else
{
//
// Generating a stack walk at the client is not really a good idea. Since it will work only
// on x86. Absence of call stack in the uploaded comment report should be handled at the server
// The following code though disabled is still kept here for reference.
//
RtlWalkFrameChain_t fnRtlWalkFrameChain =
(RtlWalkFrameChain_t) GetProcAddress(GetModuleHandle(_T("NTDLL.DLL")), "RtlWalkFrameChain");
STACKTRACEDATA* pstd = (STACKTRACEDATA*) _alloca(offsetof(STACKTRACEDATA, callers[64]));
pstd->nCallers = fnRtlWalkFrameChain(pstd->callers, 64, 0);
pv = (PVOID)pstd;
if(NULL != pv)
{
DebugTrace(0, "Generated a new stacktrace");
wsprintf(tmpbuf, TEXT("\t(%x) = %x\n\t(%x) = %x\n\t(%x) = %x\n\t(%x) = %x"), ((int*)pv+12), (int)*((int*)pv+12), ((int*)pv+8),(int)*((int*)pv+8), ((int*)pv+4), (int)*((int*)pv+4),((int*)pv), (int)*((int*)pv));
}
else
{
FatalTrace(0, "StackTrace not available...");
wsprintf(tmpbuf, TEXT("StackTrace not available..."));
}
FatalTrace(0, "StackTrace not available...");
wsprintf(tmpbuf, TEXT("StackTrace not available..."));
}
DebugTrace(0, "Got comment from window '%ls'", szWindowText, tmpbuf);
DebugTrace(0, "StackTrace: '%ls'", tmpbuf);
#endif
//
// Create the Comment dialog
//
CSurveyDlg dlg;
//
// Initialize the comment dialog
//
DebugTrace(0, "Calling dlg.Init");
dlg.Init(hwnd, (PSTACKTRACEDATA) pv);
//
// Launch the comment dialog
//
DebugTrace(0, "Calling DoModal");
dlg.DoModal(hwnd, NULL);
TraceFunctLeave();
}
//
// nsoy sayz: The following code is used by the MessageBox hook(which for some
// mysterious reason disappeared when Neptune code was moved to Whistler)
// Hence, the code used by the MessageBox hook is henceforth
// not maintained.
//
// UploadInstrumentationCollectionData: Dunno why this is present. Walter must have
// had some use for this.
VOID WINAPI UploadInstrumentationCollectionData()
{
//bugbug: do something meaningful
;
}
//
// LogMessageBoxThread: MessageBox hook data collection thread.
// - present for historical reasons. Not needed for Whistler
//
unsigned int __stdcall LogMessageBoxThread(void* pvLogData)
{
HRESULT hrCoInit = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (SUCCEEDED(hrCoInit)) {
LogMessageBox((MSGBOXLOGDATA*) pvLogData);
CoUninitialize();
}
return 0;
}