Click here to Skip to main content
15,880,956 members
Articles / Web Development / HTML

Catch All Bugs with BugTrap!

Rate me:
Please Sign up or sign in to vote.
4.34/5 (84 votes)
31 Jan 2009MIT5 min read 1.8M   9.1K   292  
A tool that can catch unhandled errors and exceptions, and deliver error reports to remote support servers
/*
 * This is a part of the BugTrap package.
 * Copyright (c) 2005-2007 IntelleSoft.
 * All rights reserved.
 *
 * Description: Manual mode dialog.
 * Author: Maksim Pyatkovskiy.
 *
 * This source code is only intended as a supplement to the
 * BugTrap package reference and related electronic documentation
 * provided with the product. See these sources for detailed
 * information regarding the BugTrap package.
 */

#include "stdafx.h"
#include "resource.h"

#include "WaitDlg.h"
#include "CustomDialogs.h"
#include "ManualModeDlg.h"
#include "MessageTip.h"
#include "MapProcessor.h"
#include "PdbProcessor.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

IMPLEMENT_RUNTIME_CLASS(CManualModeDlg, CBaseTabItem)

/// Dialog layout information.
static const LAYOUT_INFO g_arrLayout[] =
{
	LAYOUT_INFO(IDC_MAPPDBFILE,         ALIGN_LEFT,   ALIGN_TOP, ALIGN_RIGHT,  ALIGN_TOP),
	LAYOUT_INFO(IDC_MAPPDBFILE_BROWSE,  ALIGN_RIGHT,  ALIGN_TOP, ALIGN_RIGHT,  ALIGN_TOP),
	LAYOUT_INFO(IDC_BASEADDRESS,        ALIGN_LEFT,   ALIGN_TOP, ALIGN_CENTER, ALIGN_TOP),
	LAYOUT_INFO(IDC_BASEADDRESS_RADIX,  ALIGN_CENTER, ALIGN_TOP, ALIGN_CENTER, ALIGN_TOP),
	LAYOUT_INFO(IDC_CRASHADDRESS,       ALIGN_LEFT,   ALIGN_TOP, ALIGN_CENTER, ALIGN_TOP),
	LAYOUT_INFO(IDC_CRASHADDRESS_RADIX, ALIGN_CENTER,   ALIGN_TOP, ALIGN_CENTER, ALIGN_TOP),
	LAYOUT_INFO(IDC_MODULESIZE_LABEL,   ALIGN_CENTER, ALIGN_TOP, ALIGN_CENTER, ALIGN_TOP),
	LAYOUT_INFO(IDC_MODULESIZE,         ALIGN_CENTER, ALIGN_TOP, ALIGN_RIGHT,  ALIGN_TOP),
	LAYOUT_INFO(IDC_MODULESIZE_RADIX,   ALIGN_RIGHT,  ALIGN_TOP, ALIGN_RIGHT,  ALIGN_TOP),
	LAYOUT_INFO(IDC_FUNCTIONNAME,       ALIGN_LEFT,   ALIGN_TOP, ALIGN_RIGHT,  ALIGN_TOP),
	LAYOUT_INFO(IDC_SOURCEFILE,         ALIGN_LEFT,   ALIGN_TOP, ALIGN_RIGHT,  ALIGN_TOP),
	LAYOUT_INFO(IDC_LINENUMBER,         ALIGN_LEFT,   ALIGN_TOP, ALIGN_RIGHT,  ALIGN_TOP),
	LAYOUT_INFO(IDOK,                   ALIGN_CENTER, ALIGN_TOP, ALIGN_CENTER, ALIGN_TOP),
	LAYOUT_INFO(IDCANCEL,               ALIGN_CENTER, ALIGN_TOP, ALIGN_CENTER, ALIGN_TOP)
};

/**
 * @param hWnd - handle to the control to receive the default keyboard focus.
 * @param lParam - specifies additional initialization data.
 * @return message result code.
 */
LRESULT CManualModeDlg::OnInitDialog(HWND /*hWnd*/, LPARAM /*lParam*/)
{
	m_txtMapPdbFile.Attach(GetDlgItem(IDC_MAPPDBFILE));
	m_txtMapPdbFile.SetLimitText(MAX_PATH - 1);
	m_txtBaseAddress.Attach(GetDlgItem(IDC_BASEADDRESS), GetDlgItem(IDC_BASEADDRESS_RADIX));
	CNumEdit& txtBaseAddress = m_txtBaseAddress.GetNumEdit();
	txtBaseAddress.SetLimitText(8);
	txtBaseAddress.SetNumFormat(CNumEdit::NF_HEX);
	CNumEdit& txtModuleSize = m_txtModuleSize.GetNumEdit();
	m_txtModuleSize.Attach(GetDlgItem(IDC_MODULESIZE), GetDlgItem(IDC_MODULESIZE_RADIX));
	txtModuleSize.SetLimitText(8);
	txtModuleSize.SetNumFormat(CNumEdit::NF_HEX);
	txtModuleSize.EnableWindow(FALSE);
	CNumEdit& txtCrashAddress = m_txtCrashAddress.GetNumEdit();
	m_txtCrashAddress.Attach(GetDlgItem(IDC_CRASHADDRESS), GetDlgItem(IDC_CRASHADDRESS_RADIX));
	txtCrashAddress.SetLimitText(8);
	txtCrashAddress.SetNumFormat(CNumEdit::NF_HEX);
	m_txtFunctionName.Attach(GetDlgItem(IDC_FUNCTIONNAME));
	m_txtSourceFile.Attach(GetDlgItem(IDC_SOURCEFILE));
	m_txtLineNumber.Attach(GetDlgItem(IDC_LINENUMBER));

	//////////////////////////////////////////////////////////////
	// workaround for WinXP bug when scrollbars are not skinned //
	LONG lStyle = GetWindowLong(GWL_STYLE);                     //
	SetWindowLong(GWL_STYLE, lStyle | WS_HSCROLL | WS_VSCROLL); //
	SetWindowLong(GWL_STYLE, lStyle);                           //
	//////////////////////////////////////////////////////////////

	InitLayout(false, true);
	AddControlsToLayout(g_arrLayout, countof(g_arrLayout));

	CRect rcClient;
	GetClientRect(&rcClient);
	SetScrollSize(rcClient.right, rcClient.bottom);
	DWORD dwDlgUnits = GetDialogBaseUnits();
	int nLineUnit = HIWORD(dwDlgUnits);
	SetScrollLine(nLineUnit, nLineUnit);

	ClearProcessor();
	return TRUE;
}

void CManualModeDlg::OnDestroy()
{
	SetMsgHandled(FALSE);
	ClearProcessor();
}

void CManualModeDlg::ClearProcessor()
{
	m_eProcessedFileType = CBaseProcessor::PFT_UNDEFINED;
	m_pProcessor.reset();
	CNumEdit& txtModuleSize = m_txtModuleSize.GetNumEdit();
	txtModuleSize.SetWindowText(NULL);
	txtModuleSize.EnableWindow(FALSE);
	CRadixMenu& btnModuleSize = m_txtModuleSize.GetRadixMenu();
	btnModuleSize.EnableWindow(FALSE);
}

/**
 * @param uNotifyCode - notification code if the message is from a control. If the message is from an accelerator, this value is 1. If the message is from a menu, this value is zero.
 * @param nID - specifies the identifier of the menu item, control, or accelerator.
 * @param hWndCtl - handle to the control sending the message if the message is from a control. Otherwise, this parameter is NULL.
 */
void CManualModeDlg::OnMapPdbFileBrowse(UINT /*uNotifyCode*/, int /*nID*/, HWND /*hWndCtl*/)
{
	MsgTip::HideMessage();
	CString strMapPdbFile;
	m_txtMapPdbFile.GetWindowText(strMapPdbFile);
	CCustomFileDialog dlgSelectFile(TRUE,
		NULL,
		strMapPdbFile,
		OFN_HIDEREADONLY | OFN_FILEMUSTEXIST,
		_T("All Supported Files\0*.map;*.pdb;*.exe;*.dll\0")
		_T("Map Files\0*.map\0")
		_T("Pdb Files\0*.pdb\0")
		_T("Executable Files\0*.exe;*.dll\0")
		_T("All Files\0*.*\0"),
		m_hWnd);
	if (dlgSelectFile.DoModal(m_hWnd) == IDOK)
		m_txtMapPdbFile.SetWindowText(dlgSelectFile.m_szFileName);
}

/**
 * @param uNotifyCode - notification code if the message is from a control. If the message is from an accelerator, this value is 1. If the message is from a menu, this value is zero.
 * @param nID - specifies the identifier of the menu item, control, or accelerator.
 * @param hWndCtl - handle to the control sending the message if the message is from a control. Otherwise, this parameter is NULL.
 */
void CManualModeDlg::OnChangeMapPdbFile(UINT /*uNotifyCode*/, int /*nID*/, HWND /*hWndCtl*/)
{
	try
	{
		ClearProcessor();
		CString strMapPdbFile;
		m_txtMapPdbFile.GetWindowText(strMapPdbFile);
		if (strMapPdbFile.IsEmpty())
			return;
		if (GetFileAttributes(strMapPdbFile) != INVALID_FILE_ATTRIBUTES)
		{
			CWaitCursor wait;
			CBaseProcessor::PROCESSED_FILE_TYPE eProcessedFileType = CBaseProcessor::GetFileType(strMapPdbFile);
			switch (eProcessedFileType)
			{
			case CBaseProcessor::PFT_MAP:
				{
					CMapProcessor* pMapProcessor = new CMapProcessor();
					m_pProcessor.reset(pMapProcessor);
					m_eProcessedFileType = CBaseProcessor::PFT_MAP;
					pMapProcessor->LoadMapText(strMapPdbFile);
					CNumEdit& txtBaseAddress = m_txtBaseAddress.GetNumEdit();
					PVOID pPreferredBaseAddress = pMapProcessor->GetBaseAddress();
					if (pPreferredBaseAddress)
					{
						CString strPreferredBaseAddress;
						strPreferredBaseAddress.Format(_T("%08X"), pPreferredBaseAddress);
						txtBaseAddress.SetWindowText(strPreferredBaseAddress);
					}
					else
						txtBaseAddress.SetWindowText(NULL);
				}
				break;
			case CBaseProcessor::PFT_PDB:
				{
					m_eProcessedFileType = CBaseProcessor::PFT_PDB;
					CNumEdit& txtModuleSize = m_txtModuleSize.GetNumEdit();
					txtModuleSize.EnableWindow(TRUE);
					CRadixMenu& btnModuleSize = m_txtModuleSize.GetRadixMenu();
					btnModuleSize.EnableWindow(TRUE);
				}
				break;
			default:
				MsgTip::ShowMessage(m_txtMapPdbFile, IDS_INVALIDMAPPDBFILE);
				return;
			}
		}
	}
	catch (std::exception& error)
	{
		CString strProjectTitle;
		strProjectTitle.LoadString(IDS_PROJECTTITLE);
		MessageBox(CA2CT(error.what()), strProjectTitle, MB_OK | MB_ICONERROR);
	}
}

/**
 * @param uNotifyCode - notification code if the message is from a control. If the message is from an accelerator, this value is 1. If the message is from a menu, this value is zero.
 * @param nID - specifies the identifier of the menu item, control, or accelerator.
 * @param hWndCtl - handle to the control sending the message if the message is from a control. Otherwise, this parameter is NULL.
 */
void CManualModeDlg::OnCalculate(UINT /*uNotifyCode*/, int /*nID*/, HWND /*hWndCtl*/)
{
	try
	{
		CString strMapPdbFile;
		m_txtMapPdbFile.GetWindowText(strMapPdbFile);
		if (strMapPdbFile.IsEmpty())
		{
			MsgTip::ShowMessage(m_txtMapPdbFile, IDS_INVALIDMAPPDBFILE);
			return;
		}

		CNumEdit& txtBaseAddress = m_txtBaseAddress.GetNumEdit();
		DWORD64 dwBaseAddress64;
		txtBaseAddress.GetValue(dwBaseAddress64);
		PVOID ptrBaseAddress = (PVOID)dwBaseAddress64;
		if (! ptrBaseAddress)
		{
			MsgTip::ShowMessage(txtBaseAddress, IDS_INVALIDBASEADDRESS);
			return;
		}

		CNumEdit& txtCrashAddress = m_txtCrashAddress.GetNumEdit();
		DWORD64 dwCrashAddress64;
		txtCrashAddress.GetValue(dwCrashAddress64);
		PVOID ptrCrashAddress = (PVOID)dwCrashAddress64;
		if (! ptrCrashAddress)
		{
			MsgTip::ShowMessage(txtCrashAddress, IDS_INVALIDCRASHADDRESS);
			return;
		}

		CWaitDialog wait(m_hWnd);
		switch (m_eProcessedFileType)
		{
		case CBaseProcessor::PFT_MAP:
			{
				CBaseProcessor* pBaseProcessor = m_pProcessor.get();
				if (! pBaseProcessor || pBaseProcessor->GetRuntimeClass() != RUNTIME_CLASS(CMapProcessor))
				{
					MsgTip::ShowMessage(m_txtMapPdbFile, IDS_INVALIDMAPPDBFILE);
					return;
				}
				CMapProcessor* pMapProcessor = STATIC_DOWNCAST(CMapProcessor, pBaseProcessor);
				pMapProcessor->SetBaseAddress(ptrBaseAddress);
			}
			break;
		case CBaseProcessor::PFT_PDB:
			{
				CNumEdit& txtModuleSize = m_txtModuleSize.GetNumEdit();
				DWORD32 dwModuleSize;
				txtModuleSize.GetValue(dwModuleSize);
				if (! dwModuleSize)
				{
					MsgTip::ShowMessage(txtModuleSize, IDS_INVALIDMODULESIZE);
					return;
				}
				m_pProcessor.reset(); // unload old modules
				CPdbProcessor* pPdbProcessor = new CPdbProcessor();
				m_pProcessor.reset(pPdbProcessor);
				pPdbProcessor->LoadModule(strMapPdbFile, ptrBaseAddress, dwModuleSize);
			}
			break;
		default:
			MsgTip::ShowMessage(m_txtMapPdbFile, IDS_INVALIDMAPPDBFILE);
			return;
		}

		CString strFunctionInfo;
		boost::shared_ptr<CBaseFnInfo> pFnInfo;
		DWORD64 dwDisplacement64;
		if (m_pProcessor->FindFunctionInfo(ptrCrashAddress, pFnInfo, dwDisplacement64))
		{
			CString strFunctionName(CA2CT(pFnInfo->GetName().c_str()));
			if (dwDisplacement64 != 0)
				strFunctionInfo.Format(_T("%s+%I64u byte(s)"), strFunctionName, dwDisplacement64);
			else
				strFunctionInfo = strFunctionName;
		}
		else
			strFunctionInfo.LoadString(IDS_NOFUNCTIONINFO);
		m_txtFunctionName.SetWindowText(strFunctionInfo);

		CString strSourceFile, strLineInfo;
		boost::shared_ptr<CBaseFileInfo> pFileInfo;
		boost::shared_ptr<CBaseLineInfo> pLineInfo;
		DWORD dwDisplacement32;
		if (m_pProcessor->FindLineInfo(ptrCrashAddress, pFileInfo, pLineInfo, dwDisplacement32))
		{
			strSourceFile = CA2CT(pFileInfo->GetFileName().c_str());
			UINT uLineNumber = pLineInfo->GetNumber();
			if (dwDisplacement32 != 0)
				strLineInfo.Format(_T("line %u+%I32u byte(s)"), uLineNumber, dwDisplacement32);
			else
				strLineInfo.Format(_T("line %u"), uLineNumber);
		}
		else
		{
			strSourceFile.LoadString(IDS_NOSOURCEFILEINFO);
			strLineInfo.LoadString(IDS_NOLINEINFO);
		}
		m_txtSourceFile.SetWindowText(strSourceFile);
		m_txtLineNumber.SetWindowText(strLineInfo);
	}
	catch (std::exception& error)
	{
		CString strProjectTitle;
		strProjectTitle.LoadString(IDS_PROJECTTITLE);
		MessageBox(CA2CT(error.what()), strProjectTitle, MB_OK | MB_ICONERROR);
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions