server-re/third-party/BugTrap-1.3-57bd515/source/BugTrap.cpp
2026-10-14 15:54:34 -04:00

2240 lines
63 KiB
C++

/*
* This is a part of the BugTrap package.
* Copyright (c) 2005-2009 IntelleSoft.
* All rights reserved.
*
* Description: External routines and the entry point.
* 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 "BugTrap.h"
#include "BugTrapUtils.h"
#include "BugTrapUI.h"
#include "Array.h"
#include "XmlReader.h"
#include "TextLogFile.h"
#include "XmlLogFile.h"
#include "LogStream.h"
#include "ModuleImportTable.h"
#include "Globals.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
/// Critical section used for synchronizing log files management.
static CRITICAL_SECTION g_csMutualLogAccess;
/// Critical section used for synchronizing output to the console.
static CRITICAL_SECTION g_csConsoleAccess;
/// Critical section used for synchronous error handler execution.
static CRITICAL_SECTION g_csHandlerSync;
/// True when code is invoked from DllMain().
static BOOL g_bInDllMain = FALSE;
/// Event fired when pending log request is finished.
static HANDLE g_hLogRequestComplete = NULL;
/// True when logging activity is enabled.
static BOOL g_bLoggingEnabled = FALSE;
/// Number of active request to logging functions from different threads.
static DWORD g_dwNumLogRequests = 0;
/// Array of pointers to log descriptors.
static CArray<CLogFile*, CDynamicTraits<CLogFile*> > g_arrLogFiles;
/// Old filter of unhandled exception.
static PTOP_LEVEL_EXCEPTION_FILTER g_pfnOldExceptionFilter = NULL;
/// Table of modules that import SetUnhandledExceptionFilter() function.
static CModuleImportTable g_ModuleImportTable;
#if defined _CRTDBG_MAP_ALLOC && defined _DEBUG
/// Global memory state object. Tracks memory leaks.
static _CrtMemState g_MemState;
#endif
/**
* @brief Request more privileges for current process.
* @return true if operation was completed successfully.
*/
static BOOL RequestMorePrivileges(void)
{
if (! g_bWinNT)
return TRUE; // simulation for Win9x
BOOL bResult = FALSE;
HANDLE hCurrentProcess = GetCurrentProcess();
HANDLE hToken;
if (OpenProcessToken(hCurrentProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
{
DWORD dwLength = 0;
if (! GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &dwLength) &&
GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
BYTE* pBuffer = new BYTE[dwLength];
if (pBuffer)
{
if (GetTokenInformation(hToken, TokenPrivileges, pBuffer, dwLength, &dwLength))
{
TOKEN_PRIVILEGES* pPrivs = (TOKEN_PRIVILEGES*)pBuffer;
for (DWORD dwPos = 0; dwPos < pPrivs->PrivilegeCount; ++dwPos)
pPrivs->Privileges[dwPos].Attributes |= SE_PRIVILEGE_ENABLED;
bResult = AdjustTokenPrivileges(hToken, FALSE, pPrivs, 0, NULL, NULL);
}
delete[] pBuffer;
}
}
CloseHandle(hToken);
}
return bResult;
}
/**
* Stop logging activity.
*/
static void StopLogging(void)
{
EnterCriticalSection(&g_csMutualLogAccess);
g_bLoggingEnabled = FALSE;
while (g_dwNumLogRequests > 0)
{
LeaveCriticalSection(&g_csMutualLogAccess);
WaitForSingleObject(g_hLogRequestComplete, INFINITE);
EnterCriticalSection(&g_csMutualLogAccess);
}
LeaveCriticalSection(&g_csMutualLogAccess);
}
/**
* Save all log link entries.
* @param bCrash - true if crash has occurred.
*/
static void SaveLogLinkEntries(bool bCrash)
{
size_t iNumLogLinks = g_arrLogLinks.GetCount();
for (size_t iLogLinkPos = 0; iLogLinkPos < iNumLogLinks; ++iLogLinkPos)
{
CLogLink* pLogLink = g_arrLogLinks[iLogLinkPos];
_ASSERTE(pLogLink != NULL);
pLogLink->SaveEntries(bCrash);
}
}
/**
* Save entries in all open log files.
* @param bCrash - true if crash has occurred.
*/
static void SaveLogFiles(bool bCrash)
{
_ASSERTE(! g_bLoggingEnabled && ! g_dwNumLogRequests);
size_t iNumLogFiles = g_arrLogFiles.GetCount();
for (size_t iLogFilePos = 0; iLogFilePos < iNumLogFiles; ++iLogFilePos)
{
CLogFile* pLogFile = g_arrLogFiles[iLogFilePos];
_ASSERTE(pLogFile != NULL);
pLogFile->SaveEntries(bCrash);
pLogFile->Close();
}
}
/**
* Flush contents of all open log files.
* @param bCrash - true if crash has occurred.
*/
static void FlushLogFiles(bool bCrash)
{
StopLogging();
SaveLogLinkEntries(bCrash);
SaveLogFiles(bCrash);
}
/**
* Log function prologue.
* @return false if function can't be performed.
*/
static BOOL EnterLogFunction(void)
{
EnterCriticalSection(&g_csMutualLogAccess);
BOOL bLoggingEnabled = g_bLoggingEnabled;
if (bLoggingEnabled)
++g_dwNumLogRequests;
LeaveCriticalSection(&g_csMutualLogAccess);
return bLoggingEnabled;
}
/**
* Log function epilogue.
*/
static void LeaveLogFunction(void)
{
EnterCriticalSection(&g_csMutualLogAccess);
_ASSERTE(g_dwNumLogRequests > 0);
--g_dwNumLogRequests;
SetEvent(g_hLogRequestComplete);
LeaveCriticalSection(&g_csMutualLogAccess);
}
/**
* Log function prologue.
* @param pLogFile - log file object.
* @return true if log file can be locked.
*/
static inline CLogFile* EnterLogFunction(CLogFile* pLogFile)
{
if (! pLogFile || ! EnterLogFunction())
return NULL;
pLogFile->CaptureObject();
return pLogFile;
}
/**
* @param iHandle - log file handle.
* @return log file object.
*/
static inline CLogFile* GetLogFileObject(INT_PTR iHandle)
{
if (iHandle >= 1 && iHandle <= (INT_PTR)g_arrLogFiles.GetCount())
return g_arrLogFiles[(size_t)(iHandle - 1)];
else
return NULL;
}
/**
* Log function prologue.
* @param iHandle - log file handle.
* @return log file object.
*/
static inline CLogFile* EnterLogFunction(INT_PTR iHandle)
{
CLogFile* pLogFile = GetLogFileObject(iHandle);
return EnterLogFunction(pLogFile);
}
/**
* Log function epilogue.
* @param pLogFile - log file object.
*/
static inline void LeaveLogFunction(CLogFile* pLogFile)
{
_ASSERTE(pLogFile != NULL);
pLogFile->ReleaseObject();
LeaveLogFunction();
}
/**
* Free global variables to excludes this memory from the dump of memory leaks.
*/
static void FreeGlobalData(void)
{
// Clear log files.
g_arrLogLinks.DeleteAll(true);
g_arrLogFiles.DeleteAll(true);
// Deallocate user messages.
g_strUserMessage.Free();
g_strFirstIntroMesage.Free();
g_strSecondIntroMesage.Free();
// Free module import table.
g_ModuleImportTable.Clear();
}
/**
* Prepare report engine.
* @param rParams - symbolic engine parameters.
*/
static void InitSymEngine(CSymEngine::CEngineParams& rParams)
{
// Request additional privileges.
RequestMorePrivileges();
#ifdef _MANAGED
// Flush contents of all .NET trace listeners and close all log files.
NetThunks::FlushTraceListeners();
#endif
// Flush contents of all open log files ands disable logging.
FlushLogFiles(true);
_ASSERTE(! g_bLoggingEnabled && ! g_dwNumLogRequests);
// All resource consuming objects are allocated dynamically.
// So, they don't eat computer memory if application works as expected.
if (g_pEnumProc == NULL)
g_pEnumProc = new CEnumProcess();
if (g_pSymEngine == NULL)
g_pSymEngine = new CSymEngine(rParams);
else
g_pSymEngine->SetEngineParameters(rParams);
}
/**
* Deallocate system engine object.
*/
static void FreeSymEngine(void)
{
// Destroy allocated handles.
delete g_pEnumProc;
g_pEnumProc = NULL;
delete g_pSymEngine;
g_pSymEngine = NULL;
delete g_pResManager;
g_pResManager = NULL;
// Certain actions may create global MAPI session object.
delete g_pMapiSession;
g_pMapiSession = NULL;
}
/**
* Read version info if application name is not specified.
*/
static inline void ReadVersionInfo(void)
{
if (*g_szAppName == _T('\0'))
{
#ifdef _MANAGED
NetThunks::ReadVersionInfo();
#else
BT_ReadVersionInfo(NULL);
#endif
}
}
/**
* Generic unhandled exception handler.
* @param rParams - symbolic engine parameters.
*/
static void HandleException(CSymEngine::CEngineParams& rParams)
{
// Block other threads.
EnterCriticalSection(&g_csHandlerSync);
// Save pointer to exception context.
g_pExceptionPointers = rParams.m_pExceptionPointers;
__try
{
// Flush log files and allocate symbolic engine.
InitSymEngine(rParams);
// Call user error handler before BugTrap user interface.
if (g_pfnPreErrHandler != NULL)
(*g_pfnPreErrHandler)(g_nPreErrHandlerParam);
#ifdef _MANAGED
NetThunks::FireBeforeUnhandledExceptionEvent();
#endif
// Read version info if application name is not specified.
ReadVersionInfo();
// Execute BugTrap action.
StartHandlerThread();
// Call user error handler after BugTrap user interface.
#ifdef _MANAGED
NetThunks::FireAfterUnhandledExceptionEvent();
#endif
if (g_pfnPostErrHandler != NULL)
(*g_pfnPostErrHandler)(g_nPostErrHandlerParam);
// Deallocate system engine object.
FreeSymEngine();
// Free global data (to avoid false messages about memory leaks).
FreeGlobalData();
}
// Catch any internal problems.
__except (InternalFilter(GetExceptionInformation()))
{
}
g_pExceptionPointers = NULL;
// Unlock other threads.
LeaveCriticalSection(&g_csHandlerSync);
}
/**
* Restart current process with default settings, the same
* command line, working directory and environment.
* @return true if process has been successfully restarted.
*/
static inline BOOL RestartApplication(void)
{
PTSTR pszCommandLine = GetCommandLine();
_ASSERTE(pszCommandLine != NULL);
STARTUPINFO StartupInfo;
ZeroMemory(&StartupInfo, sizeof(StartupInfo));
StartupInfo.cb = sizeof(StartupInfo);
PROCESS_INFORMATION ProcessInfo;
ZeroMemory(&ProcessInfo, sizeof(ProcessInfo));
if (! CreateProcess(NULL, pszCommandLine,
NULL, NULL, FALSE, 0, NULL, NULL,
&StartupInfo, &ProcessInfo))
{
return FALSE;
}
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
return TRUE;
}
/**
* Generic unhandled exception handler.
* @param pExceptionPointers - pointer to the exception information.
* @param eExceptionType - type of exception.
* @return determines how the exception is handled.
*/
static LONG GenericFilter(PEXCEPTION_POINTERS pExceptionPointers, CSymEngine::EXCEPTION_TYPE eExceptionType)
{
// Stack overflow is not handled by BugTrap.
if (pExceptionPointers->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW)
return EXCEPTION_CONTINUE_SEARCH;
{
// Initialize symbolic engine parameters.
CSymEngine::CEngineParams params(pExceptionPointers, eExceptionType);
// Call exception handler.
HandleException(params);
// ~CSymEngine() will be called at this point.
}
#if defined _CRTDBG_MAP_ALLOC && defined _DEBUG
// 1. Use DebugView of Mark Russinovich to check CRT output.
// 2. Don't call _CrtDumpMemoryLeaks() because it warns about
// memory allocated from static hash table used by CXmlReader.
_CrtMemDumpAllObjectsSince(&g_MemState);
#endif
if (g_dwFlags & BTF_RESTARTAPP)
RestartApplication();
HANDLE hCurrentProcess;
switch (g_eExitMode)
{
case BTEM_EXECUTEHANDLER:
return EXCEPTION_EXECUTE_HANDLER;
default: // BTEM_TERMINATEAPP
// Force application to quit.
hCurrentProcess = GetCurrentProcess();
TerminateProcess(hCurrentProcess, ~0u);
// Exit from the exception filter (this code will not be executed).
case BTEM_CONTINUESEARCH:
return EXCEPTION_CONTINUE_SEARCH;
}
}
/**
* Write log entry to the file.
* @param iHandle - log file handle.
* @param eLogLevel - log level number.
* @param eEntryMode - entry mode.
* @param pszEntry - log entry text.
* @return true if operation was completed successfully.
*/
static BOOL WriteLogEntry(INT_PTR iHandle, BUGTRAP_LOGLEVEL eLogLevel, CLogFile::ENTRY_MODE eEntryMode, PCTSTR pszEntry)
{
if (pszEntry == NULL)
return FALSE;
CLogFile* pLogFile = EnterLogFunction(iHandle);
if (! pLogFile)
return FALSE;
BOOL bResult = pLogFile->WriteLogEntry(eLogLevel, eEntryMode, g_csConsoleAccess, pszEntry);
LeaveLogFunction(pLogFile);
return bResult;
}
/**
* Write log entry to the file.
* @param iHandle - log file handle.
* @param eLogLevel - log level number.
* @param eEntryMode - entry mode.
* @param pszFormat - format string.
* @param argList - variable argument list.
* @return true if operation was completed successfully.
*/
static BOOL WriteLogEntry(INT_PTR iHandle, BUGTRAP_LOGLEVEL eLogLevel, CLogFile::ENTRY_MODE eEntryMode, PCTSTR pszFormat, va_list argList)
{
if (pszFormat == NULL)
return FALSE;
CLogFile* pLogFile = EnterLogFunction(iHandle);
if (! pLogFile)
return FALSE;
BOOL bResult = pLogFile->WriteLogEntryV(eLogLevel, eEntryMode, g_csConsoleAccess, pszFormat, argList);
LeaveLogFunction(pLogFile);
return bResult;
}
/**
* @brief Set default report path (report is located in Application Data folder by default).
*/
static void SetDefaultReportPath(void)
{
TCHAR szAppDataPath[MAX_PATH];
if (SHGetSpecialFolderPath(NULL, szAppDataPath, CSIDL_APPDATA, TRUE))
{
TCHAR szAppName[MAX_PATH];
if (GetCanonicalAppName(szAppName, countof(szAppName), TRUE))
{
PathCombine(g_szReportFilePath, szAppDataPath, szAppName);
PathAppend(g_szReportFilePath, _T("reports"));
}
}
}
/**
* @brief Attach library to the process.
*/
static void AttachProcess(void)
{
INITCOMMONCONTROLSEX InitCtrls;
// Initialize synchronization objects.
InitializeCriticalSection(&g_csHandlerSync);
InitializeCriticalSection(&g_csMutualLogAccess);
InitializeCriticalSection(&g_csConsoleAccess);
// Synchronize log completion.
g_hLogRequestComplete = CreateEvent(NULL, FALSE, FALSE, NULL); // non-signaled auto-reset event
// Initialize common controls.
InitCtrls.dwSize = sizeof(InitCtrls);
InitCtrls.dwICC = ICC_LISTVIEW_CLASSES | ICC_BAR_CLASSES;
InitCommonControlsEx(&InitCtrls);
// Setup unhandled exception handler.
BT_InstallSehFilter();
// Logging is enabled.
g_bLoggingEnabled = TRUE;
}
/**
* @brief Detach library from the process.
*/
static void DetachProcess(void)
{
// Flush log files to the disk.
FlushLogFiles(false);
_ASSERTE(! g_bLoggingEnabled && ! g_dwNumLogRequests);
// Restore exception handler.
BT_UninstallSehFilter();
// Close log event.
CloseHandle(g_hLogRequestComplete);
g_hLogRequestComplete = NULL;
// In managed world DllMain() is called after object destructors.
#ifndef _MANAGED
// Free global data (to avoid false messages about memory leaks).
FreeGlobalData();
#endif
// Delete synchronization objects.
DeleteCriticalSection(&g_csConsoleAccess);
DeleteCriticalSection(&g_csMutualLogAccess);
DeleteCriticalSection(&g_csHandlerSync);
}
/**
* @param hModule - handle to the DLL module.
* @param fdwReason - reason for calling function.
* @param pvReserved - reserved.
* @return true if initialization/de-initialization has been performed normally.
*/
BOOL WINAPI DllMain(HINSTANCE hModule, DWORD fdwReason, PVOID pvReserved)
{
pvReserved;
g_bInDllMain = TRUE;
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hModule);
#if defined _CRTDBG_MAP_ALLOC && defined _DEBUG
#ifndef _MANAGED
// Avoid incorrect and annoying message about memory leaks
// in static hash table used by CXmlReader.
CXmlReader::InitStdEntities();
#endif
// Watch for memory leaks.
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_LEAK_CHECK_DF);
_CrtMemCheckpoint(&g_MemState);
#endif
g_hInstance = hModule;
AttachProcess();
break;
case DLL_PROCESS_DETACH:
DetachProcess();
g_hInstance = NULL;
#if defined _CRTDBG_MAP_ALLOC && defined _DEBUG
// 1. Use DebugView by Mark Russinovich to check CRT output.
// 2. Don't call _CrtDumpMemoryLeaks() because it warns about
// memory allocated from static hash table used by CXmlReader.
_CrtMemDumpAllObjectsSince(&g_MemState);
#endif
break;
}
g_bInDllMain = FALSE;
return TRUE;
}
/**
* @return current BugTrap options.
*/
extern "C" BUGTRAP_API DWORD APIENTRY BT_GetFlags(void)
{
return g_dwFlags;
}
/**
* @param dwFlags - new BugTrap options.
*/
extern "C" BUGTRAP_API void APIENTRY BT_SetFlags(DWORD dwFlags)
{
g_dwFlags = dwFlags;
}
/**
* @param pExceptionPointers - pointer to the exception information.
* @return determines how the exception is handled.
*/
extern "C" BUGTRAP_API LONG CALLBACK BT_SehFilter(PEXCEPTION_POINTERS pExceptionPointers)
{
return GenericFilter(pExceptionPointers, CSymEngine::WIN32_EXCEPTION);
}
/**
* @param pExceptionPointers - pointer to the exception information.
* @return determines how the exception is handled.
*/
extern "C" BUGTRAP_API LONG CALLBACK BT_CppFilter(PEXCEPTION_POINTERS pExceptionPointers)
{
return GenericFilter(pExceptionPointers, CSymEngine::CPP_EXCEPTION);
}
/**
* @param pExceptionPointers - pointer to the exception information.
* @return determines how the exception is handled.
*/
extern "C" BUGTRAP_API LONG CALLBACK BT_NetFilter(PEXCEPTION_POINTERS pExceptionPointers)
{
#ifdef _MANAGED
return GenericFilter(pExceptionPointers, CSymEngine::NET_EXCEPTION);
#else
pExceptionPointers;
return 0;
#endif
}
/**
* @return application name.
*/
extern "C" BUGTRAP_API PCTSTR APIENTRY BT_GetAppName(void)
{
return g_szAppName;
}
/**
* @param pszAppName - application name.
*/
extern "C" BUGTRAP_API void APIENTRY BT_SetAppName(PCTSTR pszAppName)
{
if (pszAppName)
_tcscpy_s(g_szAppName, countof(g_szAppName), pszAppName);
else
*g_szAppName = _T('\0');
}
/**
* @return user-defined application version number.
*/
extern "C" BUGTRAP_API PCTSTR APIENTRY BT_GetAppVersion(void)
{
return g_szAppVersion;
}
/**
* @param pszAppVersion - user-defined application version number.
*/
extern "C" BUGTRAP_API void APIENTRY BT_SetAppVersion(PCTSTR pszAppVersion)
{
if (pszAppVersion)
_tcscpy_s(g_szAppVersion, countof(g_szAppVersion), pszAppVersion);
else
*g_szAppVersion = _T('\0');
}
/**
* @return web address of product support site.
*/
extern "C" BUGTRAP_API PCTSTR APIENTRY BT_GetSupportURL(void)
{
return g_szSupportURL;
}
/**
* @param pszSupportURL - web address of product support site.
*/
extern "C" BUGTRAP_API void APIENTRY BT_SetSupportURL(PCTSTR pszSupportURL)
{
if (pszSupportURL)
_tcscpy_s(g_szSupportURL, countof(g_szSupportURL), pszSupportURL);
else
*g_szSupportURL = _T('\0');
}
/**
* @return e-mail address of product support.
*/
extern "C" BUGTRAP_API PCTSTR APIENTRY BT_GetSupportEMail(void)
{
return g_szSupportEMail;
}
/**
* @param pszSupportEMail - e-mail address of product support.
*/
extern "C" BUGTRAP_API void APIENTRY BT_SetSupportEMail(PCTSTR pszSupportEMail)
{
if (pszSupportEMail)
_tcscpy_s(g_szSupportEMail, countof(g_szSupportEMail), pszSupportEMail);
else
*g_szSupportEMail = _T('\0');
}
/**
* @return e-mail address of error notification.
*/
extern "C" BUGTRAP_API PCTSTR APIENTRY BT_GetNotificationEMail(void)
{
return g_szNotificationEMail;
}
/**
* @param pszNotificationEMail - e-mail address of error notification.
*/
extern "C" BUGTRAP_API void APIENTRY BT_SetNotificationEMail(PCTSTR pszNotificationEMail)
{
if (pszNotificationEMail)
_tcscpy_s(g_szNotificationEMail, countof(g_szNotificationEMail), pszNotificationEMail);
else
*g_szNotificationEMail = _T('\0');
}
/**
* @return host name of product support server where BugTrapServer is installed.
*/
extern "C" BUGTRAP_API PCTSTR APIENTRY BT_GetSupportHost(void)
{
return g_szSupportHost;
}
/**
* @return port number of product support server where BugTrapServer is installed.
*/
extern "C" BUGTRAP_API SHORT APIENTRY BT_GetSupportPort(void)
{
return g_nSupportPort;
}
/**
* @param pszSupportHost - host name of product support server where BugTrapServer is installed.
*/
extern "C" BUGTRAP_API void APIENTRY BT_SetSupportHost(LPCTSTR pszSupportHost)
{
if (pszSupportHost)
_tcscpy_s(g_szSupportHost, countof(g_szSupportHost), pszSupportHost);
else
*g_szSupportHost = _T('\0');
}
/**
* @param nSupportPort - port number of product support server where BugTrapServer is installed.
*/
extern "C" BUGTRAP_API void APIENTRY BT_SetSupportPort(SHORT nSupportPort)
{
g_nSupportPort = nSupportPort;
}
/**
* @param pszSupportHost - host name of product support server where BugTrapServer is installed.
* @param nSupportPort - port number of product support server where BugTrapServer is installed.
*/
extern "C" BUGTRAP_API void APIENTRY BT_SetSupportServer(PCTSTR pszSupportHost, SHORT nSupportPort)
{
BT_SetSupportHost(pszSupportHost);
BT_SetSupportPort(nSupportPort);
}
extern "C" BUGTRAP_API void APIENTRY BT_ClearLogFiles(void)
{
g_arrLogLinks.DeleteAll(true);
}
/**
* @return number of log files attached to the report.
*/
extern "C" BUGTRAP_API DWORD APIENTRY BT_GetLogFilesCount(void)
{
return (DWORD)g_arrLogLinks.GetCount();
}
/**
* @param pszLogFile - custom log file name.
* @return index of matching long file name if present.
*/
static size_t FindLogLink(PCTSTR pszLogFile)
{
TCHAR szLogFileName[MAX_PATH];
if (GetCompleteLogFileName(szLogFileName, pszLogFile, NULL))
{
size_t nItemCount = g_arrLogLinks.GetCount();
for (size_t nItemPos = 0; nItemPos < nItemCount; ++nItemPos)
{
CLogLink* pLogLink = g_arrLogLinks[nItemPos];
_ASSERTE(pLogLink != NULL);
if (_tcsicmp(pLogLink->GetLogFileName(), szLogFileName) == 0)
return nItemPos;
}
}
return MAXSIZE_T;
}
/**
* @param nLogFileIndexOrName - log entry index of name.
* @param bGetByIndex - specifies type of @a nLogFileIndexOrName parameter.
* @param peLogType - log entry type.
* @param pdwLogEntrySize - log entry size.
* @param pLogEntry - log entry data.
* @return error status.
*/
extern "C" BUGTRAP_API DWORD APIENTRY BT_GetLogFileEntry(INT_PTR nLogFileIndexOrName, BOOL bGetByIndex, BUGTRAP_LOGTYPE* peLogType, PDWORD pdwLogEntrySize, PVOID pLogEntry)
{
if (bGetByIndex)
{
if (nLogFileIndexOrName < 0 || nLogFileIndexOrName >= (INT_PTR)g_arrLogLinks.GetCount())
return ERROR_NO_MORE_ITEMS;
}
else
{
if (nLogFileIndexOrName == 0)
return ERROR_BAD_ARGUMENTS;
nLogFileIndexOrName = FindLogLink((PCTSTR)nLogFileIndexOrName);
if (nLogFileIndexOrName < 0)
return ERROR_NOT_FOUND;
}
CLogLink* pLogLink = g_arrLogLinks[(size_t)nLogFileIndexOrName];
_ASSERTE(pLogLink != NULL);
BUGTRAP_LOGTYPE eLogType = pLogLink->GetLogType();
if (pLogEntry != NULL)
{
if (peLogType == NULL ||
*peLogType != eLogType ||
pdwLogEntrySize == NULL)
{
return ERROR_BAD_ARGUMENTS;
}
switch (eLogType)
{
case BTLT_LOGFILE:
if (*pdwLogEntrySize != sizeof(BUGTRAP_LOGFILEENTRY))
return ERROR_INCORRECT_SIZE;
{
BUGTRAP_LOGFILEENTRY* pLogFileEntry = (BUGTRAP_LOGFILEENTRY*)pLogEntry;
_tcscpy_s(pLogFileEntry->szLogFileName, countof(pLogFileEntry->szLogFileName), pLogLink->GetLogFileName());
}
break;
case BTLT_REGEXPORT:
if (*pdwLogEntrySize != sizeof(BUGTRAP_REGEXPORTENTRY))
return ERROR_INCORRECT_SIZE;
{
BUGTRAP_REGEXPORTENTRY* pRegExportEntry = (BUGTRAP_REGEXPORTENTRY*)pLogEntry;
CRegLink* pRegLink = (CRegLink*)pLogLink;
_tcscpy_s(pRegExportEntry->szLogFileName, countof(pRegExportEntry->szLogFileName), pRegLink->GetLogFileName());
_tcscpy_s(pRegExportEntry->szRegKey, countof(pRegExportEntry->szRegKey), pRegLink->GetRegKey());
}
break;
default:
_ASSERT(FALSE);
return ERROR_INTERNAL_ERROR;
}
}
else
{
if (peLogType != NULL)
*peLogType = eLogType;
if (pdwLogEntrySize != NULL)
{
switch (eLogType)
{
case BTLT_LOGFILE:
*pdwLogEntrySize = sizeof(BUGTRAP_LOGFILEENTRY);
break;
case BTLT_REGEXPORT:
*pdwLogEntrySize = sizeof(BUGTRAP_REGEXPORTENTRY);
break;
default:
_ASSERT(FALSE);
return ERROR_INTERNAL_ERROR;
}
}
}
return ERROR_SUCCESS;
}
/**
* @param pszLogFile - custom log file name.
*/
extern "C" BUGTRAP_API void APIENTRY BT_AddLogFile(PCTSTR pszLogFile)
{
if (pszLogFile && *pszLogFile)
{
if (FindLogLink(pszLogFile) == MAXSIZE_T)
{
CLogLink* pLogLink = new CLogLink(pszLogFile);
if (pLogLink != NULL)
g_arrLogLinks.AddItem(pLogLink);
}
}
}
/**
* @param pszRegFile - custom log file name.
* @param pszRegKey - registry key to be exported.
*/
extern "C" BUGTRAP_API void APIENTRY BT_AddRegFile(LPCTSTR pszRegFile, PCTSTR pszRegKey)
{
if (pszRegFile && *pszRegFile)
{
if (FindLogLink(pszRegFile) == MAXSIZE_T)
{
CRegLink* pRegLink = new CRegLink(pszRegFile, pszRegKey);
if (pRegLink != NULL)
g_arrLogLinks.AddItem(pRegLink);
}
}
}
/**
* @param pszLogFile - custom log file name.
*/
extern "C" BUGTRAP_API void APIENTRY BT_DeleteLogFile(PCTSTR pszLogFile)
{
if (pszLogFile && *pszLogFile)
{
size_t nItemPos = FindLogLink(pszLogFile);
if (nItemPos != MAXSIZE_T)
g_arrLogLinks.DeleteItem(nItemPos);
}
}
/**
* @return address of error handler called before BugTrap dialog.
*/
extern "C" BUGTRAP_API BT_ErrHandler APIENTRY BT_GetPreErrHandler(void)
{
return g_pfnPreErrHandler;
}
/**
* @param pfnPreErrHandler - address of error handler called before BugTrap dialog.
* @param nPreErrHandlerParam - user-defined parameter of error handler called before BugTrap dialog.
*/
extern "C" BUGTRAP_API void APIENTRY BT_SetPreErrHandler(BT_ErrHandler pfnPreErrHandler, INT_PTR nPreErrHandlerParam)
{
g_pfnPreErrHandler = pfnPreErrHandler;
g_nPreErrHandlerParam = nPreErrHandlerParam;
}
/**
* @return address of error handler called after BugTrap dialog.
*/
extern "C" BUGTRAP_API BT_ErrHandler APIENTRY BT_GetPostErrHandler(void)
{
return g_pfnPostErrHandler;
}
/**
* @param pfnPostErrHandler - address of error handler called after BugTrap dialog.
* @param nPostErrHandlerParam - user-defined parameter of error handler called after BugTrap dialog.
*/
extern "C" BUGTRAP_API void APIENTRY BT_SetPostErrHandler(BT_ErrHandler pfnPostErrHandler, INT_PTR nPostErrHandlerParam)
{
g_pfnPostErrHandler = pfnPostErrHandler;
g_nPostErrHandlerParam = nPostErrHandlerParam;
}
/**
* @param iHandle - log file handle.
* @return custom log file name.
*/
extern "C" BUGTRAP_API PCTSTR APIENTRY BT_GetLogFileName(INT_PTR iHandle)
{
CLogFile* pLogFile = EnterLogFunction(iHandle);
if (! pLogFile)
return NULL;
PCTSTR pszLogFileName = pLogFile->GetLogFileName();
LeaveLogFunction(pLogFile);
return pszLogFileName;
}
/**
* @param iHandle - log file handle.
* @return maximum size of log file in records.
*/
extern "C" BUGTRAP_API DWORD APIENTRY BT_GetLogSizeInEntries(INT_PTR iHandle)
{
CLogFile* pLogFile = EnterLogFunction(iHandle);
if (! pLogFile)
return 0;
DWORD dwLogSizeInEntries = pLogFile->GetLogSizeInEntries();
LeaveLogFunction(pLogFile);
return dwLogSizeInEntries;
}
/**
* @param iHandle - log file handle.
* @param dwLogSizeInEntries - maximum size of log file in records; pass MAXDWORD for unlimited log.
* @return true if operation was accepted.
*/
extern "C" BUGTRAP_API BOOL APIENTRY BT_SetLogSizeInEntries(INT_PTR iHandle, DWORD dwLogSizeInEntries)
{
CLogFile* pLogFile = EnterLogFunction(iHandle);
if (! pLogFile)
return FALSE;
BOOL bResult = pLogFile->SetLogSizeInEntries(dwLogSizeInEntries);
LeaveLogFunction(pLogFile);
return bResult;
}
/**
* @param iHandle - log file handle.
* @return maximum size of log file in records.
*/
extern "C" BUGTRAP_API DWORD APIENTRY BT_GetLogSizeInBytes(INT_PTR iHandle)
{
CLogFile* pLogFile = EnterLogFunction(iHandle);
if (! pLogFile)
return 0;
DWORD dwLogSizeInBytes = pLogFile->GetLogSizeInBytes();
LeaveLogFunction(pLogFile);
return dwLogSizeInBytes;
}
/**
* @param iHandle - log file handle.
* @param dwLogSizeInBytes - maximum size of log file in records; pass MAXDWORD for unlimited log.
* @return true if operation was accepted.
*/
extern "C" BUGTRAP_API BOOL APIENTRY BT_SetLogSizeInBytes(INT_PTR iHandle, DWORD dwLogSizeInBytes)
{
CLogFile* pLogFile = EnterLogFunction(iHandle);
if (! pLogFile)
return FALSE;
BOOL bResult = pLogFile->SetLogSizeInBytes(dwLogSizeInBytes);
LeaveLogFunction(pLogFile);
return bResult;
}
/**
* @param iHandle - log file handle.
* @return current set of log flags.
*/
extern "C" BUGTRAP_API DWORD APIENTRY BT_GetLogFlags(INT_PTR iHandle)
{
CLogFile* pLogFile = EnterLogFunction(iHandle);
if (! pLogFile)
return BTLF_NONE;
DWORD dwLogFlags = pLogFile->GetLogFlags();
LeaveLogFunction(pLogFile);
return dwLogFlags;
}
/**
* @param iHandle - log file handle.
* @param dwLogFlags - set of log flags.
* @return true if operation was completed successfully.
*/
extern "C" BUGTRAP_API BOOL APIENTRY BT_SetLogFlags(INT_PTR iHandle, DWORD dwLogFlags)
{
CLogFile* pLogFile = EnterLogFunction(iHandle);
if (! pLogFile)
return FALSE;
BOOL bResult = pLogFile->SetLogFlags(dwLogFlags);
LeaveLogFunction(pLogFile);
return bResult;
}
/**
* @param iHandle - log file handle.
* @return minimal log level accepted by tracing functions.
*/
extern "C" BUGTRAP_API BUGTRAP_LOGLEVEL APIENTRY BT_GetLogLevel(INT_PTR iHandle)
{
CLogFile* pLogFile = EnterLogFunction(iHandle);
if (! pLogFile)
return BTLL_NONE;
BUGTRAP_LOGLEVEL eLogLevel = pLogFile->GetLogLevel();
LeaveLogFunction(pLogFile);
return eLogLevel;
}
/**
* @param iHandle - log file handle.
* @param eLogLevel - minimal logl level accepted by tracing functions.
* @return true if operation was completed successfully.
*/
extern "C" BUGTRAP_API BOOL APIENTRY BT_SetLogLevel(INT_PTR iHandle, BUGTRAP_LOGLEVEL eLogLevel)
{
CLogFile* pLogFile = EnterLogFunction(iHandle);
if (! pLogFile)
return FALSE;
BOOL bResult = pLogFile->SetLogLevel(eLogLevel);
LeaveLogFunction(pLogFile);
return bResult;
}
/**
* @param iHandle - log file handle.
* @return current echo mode.
*/
extern "C" BUGTRAP_API DWORD APIENTRY BT_GetLogEchoMode(INT_PTR iHandle)
{
CLogFile* pLogFile = EnterLogFunction(iHandle);
if (! pLogFile)
return BTLE_NONE;
DWORD dwLogEchoMode = pLogFile->GetLogEchoMode();
LeaveLogFunction(pLogFile);
return dwLogEchoMode;
}
/**
* @param iHandle - log file handle.
* @param dwLogEchoMode - new echo mode.
* @return true if operation was completed successfully.
*/
extern "C" BUGTRAP_API BOOL APIENTRY BT_SetLogEchoMode(INT_PTR iHandle, DWORD dwLogEchoMode)
{
CLogFile* pLogFile = EnterLogFunction(iHandle);
if (! pLogFile)
return FALSE;
BOOL bResult = pLogFile->SetLogEchoMode(dwLogEchoMode);
LeaveLogFunction(pLogFile);
return bResult;
}
extern "C" BUGTRAP_API void CDECL BT_CallSehFilter(void)
{
__try {
RaiseException(EXCEPTION_ACCESS_VIOLATION, 0, 0, NULL);
} __except(BT_SehFilter(GetExceptionInformation())) {
}
}
extern "C" BUGTRAP_API void CDECL BT_CallCppFilter(void)
{
__try {
RaiseException(EXCEPTION_ACCESS_VIOLATION, 0, 0, NULL);
} __except(BT_CppFilter(GetExceptionInformation())) {
}
}
extern "C" BUGTRAP_API void CDECL BT_CallNetFilter(void)
{
#ifdef _MANAGED
__try {
RaiseException(EXCEPTION_ACCESS_VIOLATION, 0, 0, NULL);
} __except(BT_NetFilter(GetExceptionInformation())) {
}
#endif
}
/**
* @param iHandle - log file handle.
* @param eLogLevel - log level number.
* @param pszEntry - text of message.
* @return true if operation was completed successfully.
*/
extern "C" BUGTRAP_API BOOL APIENTRY BT_InsLogEntry(INT_PTR iHandle, BUGTRAP_LOGLEVEL eLogLevel, PCTSTR pszEntry)
{
return WriteLogEntry(iHandle, eLogLevel, CLogFile::EM_INSERT, pszEntry);
}
/**
* @param iHandle - log file handle.
* @param eLogLevel - log level number.
* @param pszEntry - text of message.
* @return true if operation was completed successfully.
*/
extern "C" BUGTRAP_API BOOL APIENTRY BT_AppLogEntry(INT_PTR iHandle, BUGTRAP_LOGLEVEL eLogLevel, PCTSTR pszEntry)
{
return WriteLogEntry(iHandle, eLogLevel, CLogFile::EM_APPEND, pszEntry);
}
/**
* @param iHandle - log file handle.
* @param eLogLevel - log level number.
* @param pszFormat - printf-like message format.
* @return true if operation was completed successfully.
*/
extern "C" BUGTRAP_API BOOL CDECL BT_AppLogEntryF(INT_PTR iHandle, BUGTRAP_LOGLEVEL eLogLevel, PCTSTR pszFormat, ...)
{
va_list argList;
va_start(argList, pszFormat);
BOOL bResult = WriteLogEntry(iHandle, eLogLevel, CLogFile::EM_APPEND, pszFormat, argList);
va_end(argList);
return bResult;
}
/**
* @param iHandle - log file handle.
* @param eLogLevel - log level number.
* @param pszFormat - printf-like message format.
* @param argList - variable length argument list.
* @return true if operation was completed successfully.
*/
extern "C" BUGTRAP_API BOOL APIENTRY BT_AppLogEntryV(INT_PTR iHandle, BUGTRAP_LOGLEVEL eLogLevel, PCTSTR pszFormat, va_list argList)
{
return WriteLogEntry(iHandle, eLogLevel, CLogFile::EM_APPEND, pszFormat, argList);
}
/**
* @param iHandle - log file handle.
* @param eLogLevel - log level number.
* @param pszFormat - printf-like message format.
* @return true if operation was completed successfully.
*/
extern "C" BUGTRAP_API BOOL CDECL BT_InsLogEntryF(INT_PTR iHandle, BUGTRAP_LOGLEVEL eLogLevel, PCTSTR pszFormat, ...)
{
va_list argList;
va_start(argList, pszFormat);
BOOL bResult = WriteLogEntry(iHandle, eLogLevel, CLogFile::EM_INSERT, pszFormat, argList);
va_end(argList);
return bResult;
}
/**
* @param iHandle - log file handle.
* @param eLogLevel - log level number.
* @param pszFormat - printf-like message format.
* @param argList - variable length argument list.
* @return true if operation was completed successfully.
*/
extern "C" BUGTRAP_API BOOL APIENTRY BT_InsLogEntryV(INT_PTR iHandle, BUGTRAP_LOGLEVEL eLogLevel, PCTSTR pszFormat, va_list argList)
{
return WriteLogEntry(iHandle, eLogLevel, CLogFile::EM_INSERT, pszFormat, argList);
}
/**
* @param iHandle - log file handle.
* @return true if operation was completed successfully.
*/
extern "C" BUGTRAP_API BOOL APIENTRY BT_ClearLog(INT_PTR iHandle)
{
CLogFile* pLogFile = EnterLogFunction(iHandle);
if (! pLogFile)
return FALSE;
// remove entries from the memory
BOOL bResult = pLogFile->ClearEntries();
LeaveLogFunction(pLogFile);
return bResult;
}
/**
* @return type of produced mini-dump.
*/
extern "C" BUGTRAP_API DWORD APIENTRY BT_GetDumpType(void)
{
return g_eDumpType;
}
/**
* @param dwDumpType - type of produced mini-dump.
*/
extern "C" BUGTRAP_API void APIENTRY BT_SetDumpType(DWORD dwDumpType)
{
g_eDumpType = (MINIDUMP_TYPE)dwDumpType;
}
/**
* @return the type of BugTrap action.
*/
extern "C" BUGTRAP_API BUGTRAP_ACTIVITY APIENTRY BT_GetActivityType(void)
{
return g_eActivityType;
}
/**
* @brief Get application termination mode.
* @return current application termination mode.
*/
extern "C" BUGTRAP_API BUGTRAP_EXITMODE APIENTRY BT_GetExitMode(void)
{
return g_eExitMode;
}
/**
* @return format of error report.
*/
extern "C" BUGTRAP_API BUGTRAP_REPORTFORMAT APIENTRY BT_GetReportFormat(void)
{
return g_eReportFormat;
}
/**
* @param eReportFormat - format of error report.
*/
extern "C" BUGTRAP_API void APIENTRY BT_SetReportFormat(BUGTRAP_REPORTFORMAT eReportFormat)
{
g_eReportFormat = eReportFormat;
}
/**
* @param eActivityType - the type of BugTrap action.
*/
extern "C" BUGTRAP_API void APIENTRY BT_SetActivityType(BUGTRAP_ACTIVITY eActivityType)
{
g_eActivityType = eActivityType;
}
/**
* @brief Set application termination mode.
* @param eExitMode - new application termination mode.
*/
extern "C" BUGTRAP_API void APIENTRY BT_SetExitMode(BUGTRAP_EXITMODE eExitMode)
{
g_eExitMode = eExitMode;
}
/**
* @return path to report file.
*/
extern "C" BUGTRAP_API PCTSTR APIENTRY BT_GetReportFilePath(void)
{
if (*g_szReportFilePath == _T('\0'))
SetDefaultReportPath();
return g_szReportFilePath;
}
/**
* @param pszReportFilePath - new report path.
*/
extern "C" BUGTRAP_API void APIENTRY BT_SetReportFilePath(PCTSTR pszReportFilePath)
{
if (pszReportFilePath && *pszReportFilePath)
_tcscpy_s(g_szReportFilePath, countof(g_szReportFilePath), pszReportFilePath);
else
SetDefaultReportPath();
}
/**
* @return name of MAPI profile.
*/
extern "C" BUGTRAP_API PCTSTR APIENTRY BT_GetMailProfile(void)
{
return g_szMailProfile;
}
/**
* @param pszMailProfile - name of MAPI profile.
* @param pszMailPassword - password of MAPI profile.
*/
extern "C" BUGTRAP_API void APIENTRY BT_SetMailProfile(PCTSTR pszMailProfile, PCTSTR pszMailPassword)
{
if (pszMailProfile)
_tcscpy_s(g_szMailProfile, countof(g_szMailProfile), pszMailProfile);
else
*g_szMailProfile = _T('\0');
if (pszMailPassword)
_tcscpy_s(g_szMailPassword, countof(g_szMailPassword), pszMailPassword);
else
*g_szMailPassword = _T('\0');
}
/**
* @param pszLogFileName - pointer to log file name or NULL pointer for default log file name value.
* @param eLogFormat - log file format (at this moment only text format is supported).
* @return handle of opened log file or NULL value.
*/
extern "C" BUGTRAP_API INT_PTR APIENTRY BT_OpenLogFile(PCTSTR pszLogFileName, BUGTRAP_LOGFORMAT eLogFormat)
{
CLogFile* pLogFile;
switch (eLogFormat)
{
case BTLF_TEXT:
pLogFile = new CTextLogFile();
break;
case BTLF_XML:
pLogFile = new CXmlLogFile();
break;
case BTLF_STREAM:
pLogFile = new CLogStream();
break;
default:
_ASSERT(FALSE);
return NULL;
}
size_t nCount = 0;
if (pLogFile != NULL)
{
EnterLogFunction();
pLogFile->SetLogFileName(pszLogFileName);
pszLogFileName = pLogFile->GetLogFileName();
if (CreateParentFolder(pszLogFileName) &&
pLogFile->LoadEntries())
{
EnterCriticalSection(&g_csMutualLogAccess);
g_arrLogFiles.AddItem(pLogFile);
nCount = g_arrLogFiles.GetCount();
LeaveCriticalSection(&g_csMutualLogAccess);
}
LeaveLogFunction();
}
if (nCount == 0)
{
delete pLogFile;
pLogFile = NULL;
}
return nCount;
}
/**
* @param iHandle - log file handle.
* @return true if operation was completed successfully.
*/
extern "C" BUGTRAP_API BOOL APIENTRY BT_CloseLogFile(INT_PTR iHandle)
{
BT_FlushLogFile(iHandle);
// remove file entry from the list
EnterCriticalSection(&g_csMutualLogAccess);
size_t iLogFilePos = g_arrLogFiles.LSearch((CLogFile*)iHandle);
if (iLogFilePos != MAXSIZE_T)
g_arrLogFiles.DeleteItem(iLogFilePos);
LeaveCriticalSection(&g_csMutualLogAccess);
return TRUE;
}
/**
* @param iHandle - log file handle.
* @return true if operation was completed successfully.
*/
extern "C" BUGTRAP_API BOOL APIENTRY BT_FlushLogFile(INT_PTR iHandle)
{
CLogFile* pLogFile = EnterLogFunction(iHandle);
if (! pLogFile)
return FALSE;
BOOL bResult = pLogFile->SaveEntries(false);
LeaveLogFunction(pLogFile);
return bResult;
}
/**
* @return user message.
*/
extern "C" BUGTRAP_API PCTSTR APIENTRY BT_GetUserMessage(void)
{
return g_strUserMessage;
}
/**
* @param pszUserMessage - user message.
*/
extern "C" BUGTRAP_API void APIENTRY BT_SetUserMessage(PCTSTR pszUserMessage)
{
g_strUserMessage = pszUserMessage;
}
/**
* @param dwErrorCode - Win32 error code.
*/
extern "C" BUGTRAP_API void APIENTRY BT_SetUserMessageFromCode(DWORD dwErrorCode)
{
PTSTR pszMessageBuffer = NULL;
DWORD dwNumChars = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, dwErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
(PTSTR)&pszMessageBuffer, 0, NULL);
CStrStream strTemp(dwNumChars ? 32 + dwNumChars : 128);
TCHAR szErrorCode[32];
_stprintf_s(szErrorCode, countof(szErrorCode), _T("0x%08lX - "), dwErrorCode);
strTemp << szErrorCode;
if (pszMessageBuffer)
{
TrimSpaces(pszMessageBuffer);
strTemp << pszMessageBuffer;
LocalFree(pszMessageBuffer);
}
else
{
TCHAR szErrorMessage[64];
LoadString(g_hInstance, IDS_UNDEFINED_ERROR, szErrorMessage, countof(szErrorMessage));
strTemp << szErrorMessage;
}
g_strUserMessage = strTemp;
}
/**
* @param hModule - module instance handle. Can be set to NULL for the main executable.
* @return true operation has been completed successfully.
*/
extern "C" BUGTRAP_API BOOL APIENTRY BT_ReadVersionInfo(HMODULE hModule)
{
TCHAR szModuleFileName[MAX_PATH];
if (GetModuleFileName(hModule, szModuleFileName, countof(szModuleFileName)) == 0)
return FALSE;
DWORD dwSize, dwHandle;
dwSize = GetFileVersionInfoSize(szModuleFileName, &dwHandle);
if (dwSize == 0)
return FALSE;
PBYTE pVersionInfo = new BYTE[dwSize];
if (pVersionInfo == NULL)
return FALSE;
BOOL bResult = FALSE;
struct LANGANDCODEPAGE
{
LANGID wLanguage;
WORD wCodePage;
};
LANGANDCODEPAGE* pTranslation;
UINT uTranslationLength;
if (GetFileVersionInfo(szModuleFileName, dwHandle, dwSize, pVersionInfo) &&
VerQueryValue(pVersionInfo, _T("\\VarFileInfo\\Translation"), (void**)&pTranslation, &uTranslationLength))
{
LANGID lidDefault = GetUserDefaultLangID();
size_t iNumItems = uTranslationLength / sizeof(LANGANDCODEPAGE);
size_t iItemPos = 0, iDefaultItem = MAXSIZE_T, iNeutralItem = MAXSIZE_T;
while (iItemPos < iNumItems)
{
if (pTranslation[iItemPos].wLanguage == lidDefault)
iDefaultItem = iItemPos;
else if (pTranslation[iItemPos].wLanguage == MAKELANGID(LANG_NEUTRAL, LANG_NEUTRAL))
iNeutralItem = iItemPos;
++iItemPos;
}
if (iDefaultItem != MAXSIZE_T)
iItemPos = iDefaultItem;
else if (iNeutralItem != MAXSIZE_T)
iItemPos = iNeutralItem;
else if (iNumItems > 0)
iItemPos = 0;
else
iItemPos = MAXSIZE_T;
if (iItemPos != MAXSIZE_T)
{
PTSTR pszValue;
UINT uValueLength;
TCHAR szSubBlock[128];
_stprintf_s(szSubBlock, countof(szSubBlock), _T("\\StringFileInfo\\%04x%04x\\ProductName"), pTranslation[iItemPos].wLanguage, pTranslation[iItemPos].wCodePage);
if (VerQueryValue(pVersionInfo, szSubBlock, (void**)&pszValue, &uValueLength))
{
bResult = TRUE;
BT_SetAppName(pszValue);
_stprintf_s(szSubBlock, countof(szSubBlock), _T("\\StringFileInfo\\%04x%04x\\ProductVersion"), pTranslation[iItemPos].wLanguage, pTranslation[iItemPos].wCodePage);
if (VerQueryValue(pVersionInfo, szSubBlock, (void**)&pszValue, &uValueLength))
BT_SetAppVersion(pszValue);
else
BT_SetAppVersion(NULL);
}
}
}
delete[] pVersionInfo;
return bResult;
}
/**
* @brief Return a pointer to the original (unmodified) SetUnhandledExceptionFilter().
* @return a pointer to the original (unmodified) SetUnhandledExceptionFilter().
*/
static inline PFSetUnhandledExceptionFilter GetOriginalSUEF(void)
{
#ifdef _MANAGED
if (! g_bInDllMain)
return g_ModuleImportTable.GetOriginalProcAddress();
else
return &SetUnhandledExceptionFilter;
#else
return g_ModuleImportTable.GetOriginalProcAddress();
#endif
}
/**
* @brief Override SetUnhandledExceptionFilter().
* @param hModule - module handle.
*/
static inline void OverrideSUEF(HMODULE hModule)
{
#ifdef _MANAGED
if (! g_bInDllMain && (g_dwFlags & BTF_INTERCEPTSUEF))
g_ModuleImportTable.Override(hModule);
#else
if (g_dwFlags & BTF_INTERCEPTSUEF)
g_ModuleImportTable.Override(hModule);
#endif
}
/**
* @brief Restore SetUnhandledExceptionFilter().
* @param hModule - module handle.
*/
static inline void RestoreSUEF(HMODULE hModule)
{
#ifdef _MANAGED
if (! g_bInDllMain)
g_ModuleImportTable.Restore(hModule);
#else
g_ModuleImportTable.Restore(hModule);
#endif
}
/**
* @brief Override/restore SetUnhandledExceptionFilter().
* @param hModule - module handle.
* @param bOverride - true if SetUnhandledExceptionFilter() must be overridden.
*/
static void inline InterceptSUEF(HMODULE hModule, BOOL bOverride)
{
g_ModuleImportTable.Intercept(hModule, bOverride);
}
/**
* @return the address of the previous exception filter established with the function.
*/
extern "C" BUGTRAP_API LPTOP_LEVEL_EXCEPTION_FILTER APIENTRY BT_InstallSehFilter(void)
{
// Setup unhandled exception handler.
PFSetUnhandledExceptionFilter pfnSetUnhandledExceptionFilter = GetOriginalSUEF();
_ASSERTE(pfnSetUnhandledExceptionFilter != NULL);
LPTOP_LEVEL_EXCEPTION_FILTER pfnOldExceptionFilter = (*pfnSetUnhandledExceptionFilter)(BT_SehFilter);
if (pfnOldExceptionFilter != BT_SehFilter)
g_pfnOldExceptionFilter = pfnOldExceptionFilter;
// Override SetUnhandledExceptionFilter().
OverrideSUEF(NULL);
return g_pfnOldExceptionFilter;
}
extern "C" BUGTRAP_API void APIENTRY BT_UninstallSehFilter(void)
{
// Restore SetUnhandledExceptionFilter().
RestoreSUEF(NULL);
// Restore unhandled exception handler.
PFSetUnhandledExceptionFilter pfnSetUnhandledExceptionFilter = GetOriginalSUEF();
_ASSERTE(pfnSetUnhandledExceptionFilter != NULL);
(*pfnSetUnhandledExceptionFilter)(g_pfnOldExceptionFilter);
g_pfnOldExceptionFilter = NULL;
}
/**
* @param hModule - module handle (could be set to NULL for main executable).
* @param bOverride - true if SetUnhandledExceptionFilter() must be overridden.
*/
extern "C" BUGTRAP_API void BT_InterceptSUEF(HMODULE hModule, BOOL bOverride)
{
InterceptSUEF(hModule, bOverride);
}
/**
* @param eDialogMessage - message type.
* @return pointer to message text.
*/
static CStrHolder* GetDialogMessage(BUGTRAP_DIALOGMESSAGE eDialogMessage)
{
switch (eDialogMessage)
{
case BTDM_INTRO1:
return &g_strFirstIntroMesage;
case BTDM_INTRO2:
return &g_strSecondIntroMesage;
default:
return NULL;
}
}
/**
* @param eDialogMessage - message type.
* @return message text.
*/
extern "C" BUGTRAP_API LPCTSTR APIENTRY BT_GetDialogMessage(BUGTRAP_DIALOGMESSAGE eDialogMessage)
{
CStrHolder* pstrDialogMessage = GetDialogMessage(eDialogMessage);
if (pstrDialogMessage == NULL || pstrDialogMessage->IsEmpty())
return NULL;
else
return (PCTSTR)*pstrDialogMessage;
}
/**
* @param eDialogMessage - message type.
* @param pszMessage - message text.
*/
extern "C" BUGTRAP_API void APIENTRY BT_SetDialogMessage(BUGTRAP_DIALOGMESSAGE eDialogMessage, LPCTSTR pszMessage)
{
CStrHolder* pstrDialogMessage = GetDialogMessage(eDialogMessage);
if (pstrDialogMessage != NULL)
{
if (pszMessage && *pszMessage)
*pstrDialogMessage = pszMessage;
else
pstrDialogMessage->Free();
}
}
/**
* @brief Parse registry key and return root key and sub-key.
* @param pszRegKey - registry key path.
* @param hKey - root key.
* @param pszRootName - root name.
* @param pszRegPath - registry path.
*/
static BOOL GetRootKey(PCTSTR pszRegKey, HKEY& hRootKey, PCTSTR& pszRootName, PCTSTR& pszRegPath)
{
/// Registry key synonym.
static struct REGKEY_SYNONYM
{
/// Registry key handle.
HKEY hKey;
/// Name of the key.
PCTSTR pszName;
/// Full name of the key.
PCTSTR pszFullName;
}
arrRegKeySynonyms[] =
{
{ HKEY_CLASSES_ROOT, _T("HKEY_CLASSES_ROOT"), _T("HKEY_CLASSES_ROOT") },
{ HKEY_CLASSES_ROOT, _T("HKCR"), _T("HKEY_CLASSES_ROOT") },
{ HKEY_CURRENT_USER, _T("HKEY_CURRENT_USER"), _T("HKEY_CURRENT_USER") },
{ HKEY_CURRENT_USER, _T("HKCU"), _T("HKEY_CURRENT_USER") },
{ HKEY_LOCAL_MACHINE, _T("HKEY_LOCAL_MACHINE"), _T("HKEY_LOCAL_MACHINE") },
{ HKEY_LOCAL_MACHINE, _T("HKLM"), _T("HKEY_LOCAL_MACHINE") },
{ HKEY_USERS, _T("HKEY_USERS"), _T("HKEY_USERS") },
{ HKEY_USERS, _T("HKU"), _T("HKEY_USERS") },
{ HKEY_CURRENT_CONFIG, _T("HKEY_CURRENT_CONFIG"), _T("HKEY_CURRENT_CONFIG") },
{ HKEY_CURRENT_CONFIG, _T("HKCC"), _T("HKEY_CURRENT_CONFIG") }
};
for (size_t iItemNum = 0; iItemNum < countof(arrRegKeySynonyms); ++iItemNum)
{
const REGKEY_SYNONYM* pRegKeySynonym = arrRegKeySynonyms + iItemNum;
PCTSTR pszName = pRegKeySynonym->pszName;
size_t nNameLength = _tcslen(pszName);
if (_tcsnicmp(pszRegKey, pszName, nNameLength) == 0)
{
if (pszRegKey[nNameLength] == _T('\\'))
pszRegPath = pszRegKey + nNameLength + 1;
else if (pszRegKey[nNameLength] == _T('\0'))
pszRegPath = pszRegKey + nNameLength;
else
continue;
hRootKey = pRegKeySynonym->hKey;
pszRootName = pRegKeySynonym->pszFullName;
return TRUE;
}
}
return FALSE;
}
/// Registry export data.
struct REGEXPORT_DATA
{
/// Contains full registry path.
TCHAR szRegPathBuffer[MAX_PATH];
/// Root name.
PCTSTR pszRootName;
/// File handle.
HANDLE hFile;
/// Output file buffer.
TCHAR arrFileBuffer[1024];
/// Position in the buffer.
DWORD dwFileBufferPos;
/// Dynamically allocated value buffer.
PBYTE pbValueBuffer;
/// Value size.
DWORD dwValueSize;
/// Size of value buffer.
DWORD dwValueBufferSize;
#ifndef _UNICODE
/// Auxiliary buffer.
PBYTE pbAuxiliaryBuffer;
/// Size of auxiliary value.
DWORD dwAuxiliarySize;
/// Size of auxiliary buffer.
DWORD dwAuxiliaryBufferSize;
#endif
/// Temporarily stored key or value name.
TCHAR szName[MAX_PATH];
/// Name size.
DWORD dwNameSize;
/// Temporary buffer.
TCHAR szAuxiliaryBuffer[128];
/// Temporary time buffer.
FILETIME ftime;
};
/**
* @brief Flush buffer to the disk if necessary.
* @param rRegData - registry data block.
*/
static void FlushRegData(REGEXPORT_DATA& rRegData)
{
if (rRegData.dwFileBufferPos > 0)
{
DWORD dwNumWritten;
WriteFile(rRegData.hFile, rRegData.arrFileBuffer, rRegData.dwFileBufferPos * sizeof(TCHAR), &dwNumWritten, NULL);
rRegData.dwFileBufferPos = 0;
}
}
#ifdef _UNICODE
/**
* @brief Write data to the buffer and flush buffer to the disk if necessary.
* @param rRegData - registry data block.
* @param pbData - binary data to be written.
* @param dwDataSize - data size.
* @return number of bytes written to the file.
*/
static DWORD WriteRegData(REGEXPORT_DATA& rRegData, const BYTE* pbData, DWORD dwDataSize)
{
DWORD dwNumBytes = 0;
while (dwDataSize > 0)
{
if (rRegData.dwFileBufferPos >= countof(rRegData.arrFileBuffer))
FlushRegData(rRegData);
rRegData.arrFileBuffer[rRegData.dwFileBufferPos++] = pbData[dwNumBytes++];
--dwDataSize;
}
return dwNumBytes;
}
#endif
/**
* @brief Write data to the buffer and flush buffer to the disk if necessary.
* @param rRegData - registry data block.
* @param pszText - text to be written.
* @return number of characters written to the file.
*/
static DWORD WriteRegData(REGEXPORT_DATA& rRegData, PCTSTR pszText)
{
DWORD dwNumChars = 0;
while (*pszText)
{
if (rRegData.dwFileBufferPos >= countof(rRegData.arrFileBuffer))
FlushRegData(rRegData);
rRegData.arrFileBuffer[rRegData.dwFileBufferPos++] = *pszText++;
++dwNumChars;
}
return dwNumChars;
}
/**
* @brief Write data to the buffer and flush buffer to the disk if necessary.
* @param rRegData - registry data block.
* @param dwValueType - type code.
* @param pbValueData - value data.
* @param dwValueSize - value size.
* @param dwPosition - initial cursor position.
* @return number of characters written to the file.
*/
static DWORD WriteRegData(REGEXPORT_DATA& rRegData, DWORD dwValueType, PBYTE pbValueData, DWORD dwValueSize, DWORD dwPosition)
{
DWORD dwNumChars;
if (dwValueType != REG_NONE)
{
_stprintf_s(rRegData.szAuxiliaryBuffer, countof(rRegData.szAuxiliaryBuffer), _T("hex(%02x):"), dwValueType);
dwNumChars = WriteRegData(rRegData, rRegData.szAuxiliaryBuffer);
}
else
dwNumChars = WriteRegData(rRegData, _T("hex:"));
dwPosition += dwNumChars;
for (;;)
{
while (dwValueSize > 0 && dwPosition <= 76)
{
if (dwValueSize > 1)
_stprintf_s(rRegData.szAuxiliaryBuffer, countof(rRegData.szAuxiliaryBuffer), _T("%02x,"), *pbValueData);
else
_stprintf_s(rRegData.szAuxiliaryBuffer, countof(rRegData.szAuxiliaryBuffer), _T("%02x"), *pbValueData);
DWORD dwResult = WriteRegData(rRegData, rRegData.szAuxiliaryBuffer);
dwNumChars += dwResult;
dwPosition += dwResult;
++pbValueData;
--dwValueSize;
}
if (dwValueSize > 0)
{
dwNumChars += WriteRegData(rRegData, _T("\\\r\n "));
dwPosition = 2;
}
else
break;
}
return dwNumChars;
}
/**
* @brief Write data to the buffer and flush buffer to the disk if necessary.
* @param rRegData - registry data block.
* @param dwValueType - type code.
* @param dwPosition - initial cursor position.
* @return number of characters written to the file.
*/
static inline DWORD WriteRegData(REGEXPORT_DATA& rRegData, DWORD dwValueType, DWORD dwPosition)
{
return WriteRegData(rRegData, dwValueType, rRegData.pbValueBuffer, rRegData.dwValueSize, dwPosition);
}
#ifndef _UNICODE
/**
* @brief Convert ANSI text to Unicode.
* @param rRegData - registry data block.
* @return true if conversion was completed successfully.
*/
static BOOL ConvertRegBuffer(REGEXPORT_DATA& rRegData)
{
DWORD dwNewDataSize = MultiByteToWideChar(CP_ACP, 0, (PCSTR)rRegData.pbValueBuffer, rRegData.dwValueSize, NULL, 0);
DWORD dwNewDataSize2 = dwNewDataSize * sizeof(WCHAR);
if (dwNewDataSize2 > rRegData.dwAuxiliaryBufferSize)
{
PBYTE pbNewData = (PBYTE)malloc(dwNewDataSize2);
if (pbNewData != NULL)
{
if (rRegData.pbAuxiliaryBuffer != NULL)
free(rRegData.pbAuxiliaryBuffer);
rRegData.pbAuxiliaryBuffer = pbNewData;
rRegData.dwAuxiliaryBufferSize = dwNewDataSize2;
}
else
return FALSE;
}
MultiByteToWideChar(CP_ACP, 0, (PCSTR)rRegData.pbValueBuffer, rRegData.dwValueSize, (PWSTR)rRegData.pbAuxiliaryBuffer, dwNewDataSize);
rRegData.dwAuxiliarySize = dwNewDataSize2;
return TRUE;
}
#endif
/**
* @brief Export registry values to the file.
* @param rRegData - registry data.
* @param hKey - registry key.
*/
static void ExportRegValues(REGEXPORT_DATA& rRegData, HKEY hKey)
{
for (DWORD dwRegIndex = 0; ; ++dwRegIndex)
{
DWORD dwValueType;
rRegData.dwNameSize = countof(rRegData.szName);
rRegData.dwValueSize = rRegData.dwValueBufferSize;
LONG lResult = RegEnumValue(hKey, dwRegIndex, rRegData.szName, &rRegData.dwNameSize, NULL, &dwValueType, rRegData.pbValueBuffer, &rRegData.dwValueSize);
if (lResult == ERROR_NO_MORE_ITEMS)
break;
if (lResult == ERROR_MORE_DATA)
{
DWORD dwNewDataSize = (rRegData.dwValueSize + 0x3FF) & ~0x3FF;
PBYTE pbNewData = (PBYTE)malloc(dwNewDataSize);
if (pbNewData != NULL)
{
free(rRegData.pbValueBuffer);
rRegData.pbValueBuffer = pbNewData;
rRegData.dwValueBufferSize = dwNewDataSize;
}
else
continue;
lResult = RegEnumValue(hKey, dwRegIndex, rRegData.szName, &rRegData.dwNameSize, NULL, &dwValueType, rRegData.pbValueBuffer, &rRegData.dwValueSize);
}
if (lResult == ERROR_SUCCESS)
{
DWORD dwNumChars = 0;
if (*rRegData.szName)
{
dwNumChars += WriteRegData(rRegData, _T("\""));
dwNumChars += WriteRegData(rRegData, rRegData.szName);
dwNumChars += WriteRegData(rRegData, _T("\"="));
}
else
dwNumChars += WriteRegData(rRegData, _T("@="));
switch (dwValueType)
{
case REG_BINARY:
WriteRegData(rRegData, (DWORD)REG_NONE, dwNumChars);
break;
case REG_SZ:
WriteRegData(rRegData, _T("\""));
WriteRegData(rRegData, (PTSTR)rRegData.pbValueBuffer);
WriteRegData(rRegData, _T("\""));
break;
case REG_DWORD:
_stprintf_s(rRegData.szAuxiliaryBuffer, countof(rRegData.szAuxiliaryBuffer), _T("dword:%08x"), *(PDWORD)rRegData.pbValueBuffer);
WriteRegData(rRegData, rRegData.szAuxiliaryBuffer);
break;
case REG_EXPAND_SZ:
case REG_MULTI_SZ:
#ifdef _UNICODE
WriteRegData(rRegData, dwValueType, dwNumChars);
#else
if (ConvertRegBuffer(rRegData))
WriteRegData(rRegData, dwValueType, rRegData.pbAuxiliaryBuffer, rRegData.dwAuxiliarySize, dwNumChars);
#endif
break;
default:
WriteRegData(rRegData, dwValueType, dwNumChars);
}
WriteRegData(rRegData, _T("\r\n"));
}
}
}
/// Forward declaration of function that exports registry key to the file.
static void ExportRegKey(REGEXPORT_DATA& rRegData, HKEY hKey, DWORD dwRegPathLength);
/**
* @brief Export registry keys to the file.
* @param hKey - registry key.
* @param dwRegPathLength - pre-calculated registry path length.
* @param rRegData - registry data.
*/
static void ExportRegKeys(REGEXPORT_DATA& rRegData, HKEY hKey, DWORD dwRegPathLength)
{
if (dwRegPathLength + 1 >= countof(rRegData.szRegPathBuffer))
return;
rRegData.szRegPathBuffer[dwRegPathLength] = _T('\\');
++dwRegPathLength;
PTSTR pszRegPathEnd = rRegData.szRegPathBuffer + dwRegPathLength;
for (DWORD dwRegIndex = 0; ; ++dwRegIndex)
{
rRegData.dwNameSize = countof(rRegData.szName);
LONG lResult = RegEnumKeyEx(hKey, dwRegIndex, rRegData.szName, &rRegData.dwNameSize, NULL, NULL, NULL, &rRegData.ftime);
if (lResult == ERROR_NO_MORE_ITEMS)
break;
if (lResult == ERROR_SUCCESS)
{
_tcscpy_s(pszRegPathEnd, countof(rRegData.szRegPathBuffer) - dwRegPathLength, rRegData.szName);
HKEY hNestedKey;
if (RegOpenKeyEx(hKey, rRegData.szName, 0l, KEY_READ, &hNestedKey) == ERROR_SUCCESS)
{
ExportRegKey(rRegData, hNestedKey, dwRegPathLength + rRegData.dwNameSize);
RegCloseKey(hNestedKey);
}
}
}
--dwRegPathLength;
rRegData.szRegPathBuffer[dwRegPathLength] = _T('\0');
}
/**
* @brief Export registry key to the file.
* @param rRegData - registry data.
* @param hKey - registry key.
* @param dwRegPathLength - pre-calculated registry path length.
*/
static void ExportRegKey(REGEXPORT_DATA& rRegData, HKEY hKey, DWORD dwRegPathLength)
{
WriteRegData(rRegData, _T("["));
WriteRegData(rRegData, rRegData.pszRootName);
WriteRegData(rRegData, _T("\\"));
WriteRegData(rRegData, rRegData.szRegPathBuffer);
WriteRegData(rRegData, _T("]\r\n"));
ExportRegValues(rRegData, hKey);
WriteRegData(rRegData, _T("\r\n"));
ExportRegKeys(rRegData, hKey, dwRegPathLength);
}
/**
* @brief Write error code & description to the REG-file.
* @param rRegData - registry data.
* @param pszRegKey - registry key that wasn't exported.
* @param lResult - error code.
*/
static void WriteRegError(REGEXPORT_DATA& rRegData, PCTSTR pszRegKey, LONG lResult)
{
WriteRegData(rRegData, _T("; Error: cannot open registry key ["));
WriteRegData(rRegData, pszRegKey);
WriteRegData(rRegData, _T("]\r\n; Error code: "));
_stprintf_s(rRegData.szAuxiliaryBuffer, countof(rRegData.szAuxiliaryBuffer), _T("0x%08lX"), lResult);
WriteRegData(rRegData, rRegData.szAuxiliaryBuffer);
PTSTR pszMessageBuffer = NULL;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, lResult, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
(PTSTR)&pszMessageBuffer, 0, NULL);
if (pszMessageBuffer)
{
TrimSpaces(pszMessageBuffer);
WriteRegData(rRegData, _T("\r\n; Description: "));
WriteRegData(rRegData, pszMessageBuffer);
LocalFree(pszMessageBuffer);
}
WriteRegData(rRegData, _T("\r\n"));
}
/**
* @param pszRegFileName - output reg-file name.
* @param pszRegKey - registry key path.
* @return > 0 - if registry key was exported; 0 - if registry key was not exported, but error info was stored to a file. < 0 - if function ws not able to allocate memory, create file, etc.
*/
extern "C" BUGTRAP_API int APIENTRY BT_ExportRegistryKey(LPCTSTR pszRegFile, LPCTSTR pszRegKey)
{
int nResult = -1;
HKEY hRootKey;
PCTSTR pszRegPath;
REGEXPORT_DATA RegData;
if (GetRootKey(pszRegKey, hRootKey, RegData.pszRootName, pszRegPath))
{
TCHAR szRegFileName[MAX_PATH];
if (GetCompleteLogFileName(szRegFileName, pszRegFile, _T(".reg")) &&
CreateParentFolder(szRegFileName))
{
RegData.dwValueSize = 0;
RegData.dwFileBufferPos = 0;
RegData.dwValueBufferSize = 1024;
RegData.pbValueBuffer = (PBYTE)malloc(RegData.dwValueBufferSize);
if (RegData.pbValueBuffer)
{
#ifndef _UNICODE
RegData.pbAuxiliaryBuffer = NULL;
RegData.dwAuxiliarySize = 0;
RegData.dwAuxiliaryBufferSize = 0;
#endif
RegData.hFile = CreateFile(szRegFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (RegData.hFile != INVALID_HANDLE_VALUE)
{
#ifdef _UNICODE
WriteRegData(RegData, g_arrUTF16LEPreamble, sizeof(g_arrUTF16LEPreamble));
#endif
WriteRegData(RegData, _T("Windows Registry Editor Version 5.00\r\n\r\n"));
_tcscpy_s(RegData.szRegPathBuffer, countof(RegData.szRegPathBuffer), pszRegPath);
HKEY hKey;
LONG lResult = RegOpenKeyEx(hRootKey, RegData.szRegPathBuffer, 0l, KEY_READ, &hKey);
if (lResult == ERROR_SUCCESS)
{
ExportRegKey(RegData, hKey, (DWORD)_tcslen(RegData.szRegPathBuffer));
RegCloseKey(hKey);
nResult = +1;
}
else
{
WriteRegError(RegData, pszRegKey, lResult);
nResult = 0;
}
FlushRegData(RegData);
CloseHandle(RegData.hFile);
}
free(RegData.pbValueBuffer);
#ifndef _UNICODE
if (RegData.pbAuxiliaryBuffer)
free(RegData.pbAuxiliaryBuffer);
#endif
}
}
}
return nResult;
}
/**
* Initialize snapshot.
* @return flag indicating whatever system resources should be released.
*/
static BOOL InitSnapshot(void)
{
if (g_pExceptionPointers == NULL)
{
CSymEngine::CEngineParams params;
// Initialize symbolic engine.
InitSymEngine(params);
// Read version info if application name is not specified.
ReadVersionInfo();
return TRUE;
}
else
return FALSE;
}
/**
* Initialize snapshot.
* @param pExceptionPointers - pointer to the exception information.
* @return true if snapshot has been initialized.
*/
static BOOL InitSnapshot(PEXCEPTION_POINTERS pExceptionPointers)
{
_ASSERTE(g_pExceptionPointers == NULL);
if (g_pExceptionPointers != NULL)
return FALSE;
g_pExceptionPointers = pExceptionPointers;
CSymEngine::CEngineParams params(pExceptionPointers, CSymEngine::WIN32_EXCEPTION);
// Initialize symbolic engine.
InitSymEngine(params);
// Read version info if application name is not specified.
ReadVersionInfo();
return TRUE;
}
/**
* @param pszFileName - snapshot file name or NULL, if you want to generate file name automatically.
* @return true if operation has been completed successfully.
*/
extern "C" BUGTRAP_API BOOL APIENTRY BT_SaveSnapshot(PCTSTR pszFileName)
{
// Initialize snapshot.
BOOL bFreeSymEngine = InitSnapshot();
// Save snapshot.
BOOL bResult = g_pSymEngine != NULL && g_pEnumProc != NULL ? SaveReport(pszFileName) : FALSE;
// Deallocate system engine object.
if (bFreeSymEngine)
FreeSymEngine();
return bResult;
}
/**
* @param pExceptionPointers - pointer to the exception information.
* @param pszFileName - snapshot file name or NULL, if you want to generate file name automatically.
* @return true if operation has been completed successfully.
*/
extern "C" BUGTRAP_API BOOL APIENTRY BT_SaveSnapshotEx(PEXCEPTION_POINTERS pExceptionPointers, PCTSTR pszFileName)
{
// Initialize snapshot.
if (! InitSnapshot(pExceptionPointers))
return FALSE;
// Save snapshot.
BOOL bResult = g_pSymEngine != NULL && g_pEnumProc != NULL ? SaveReport(pszFileName) : FALSE;
// Deallocate system engine object.
FreeSymEngine();
g_pExceptionPointers = NULL;
return bResult;
}
/**
* @return true if operation has been completed successfully.
*/
extern "C" BUGTRAP_API BOOL APIENTRY BT_MailSnapshot(void)
{
// Initialize snapshot.
BOOL bFreeSymEngine = InitSnapshot();
// Save snapshot.
BOOL bResult = g_pSymEngine != NULL && g_pEnumProc != NULL ? MailReport() : FALSE;
// Deallocate system engine object.
if (bFreeSymEngine)
FreeSymEngine();
return bResult;
}
/**
* @param pExceptionPointers - pointer to the exception information.
* @return true if operation has been completed successfully.
*/
extern "C" BUGTRAP_API BOOL APIENTRY BT_MailSnapshotEx(PEXCEPTION_POINTERS pExceptionPointers)
{
// Initialize snapshot.
if (! InitSnapshot(pExceptionPointers))
return FALSE;
// Save snapshot.
BOOL bResult = g_pSymEngine != NULL && g_pEnumProc != NULL ? MailReport() : FALSE;
// Deallocate system engine object.
FreeSymEngine();
g_pExceptionPointers = NULL;
return bResult;
}
/**
* @return true if operation has been completed successfully.
*/
extern "C" BUGTRAP_API BOOL APIENTRY BT_SendSnapshot(void)
{
// Initialize snapshot.
BOOL bFreeSymEngine = InitSnapshot();
// Save snapshot.
BOOL bResult = g_pSymEngine != NULL && g_pEnumProc != NULL ? SendReport() : FALSE;
// Deallocate system engine object.
if (bFreeSymEngine)
FreeSymEngine();
return bResult;
}
/**
* @param pExceptionPointers - pointer to the exception information.
* @return true if operation has been completed successfully.
*/
extern "C" BUGTRAP_API BOOL APIENTRY BT_SendSnapshotEx(PEXCEPTION_POINTERS pExceptionPointers)
{
// Initialize snapshot.
if (! InitSnapshot(pExceptionPointers))
return FALSE;
// Save snapshot.
BOOL bResult = g_pSymEngine != NULL && g_pEnumProc != NULL ? SendReport() : FALSE;
// Deallocate system engine object.
FreeSymEngine();
g_pExceptionPointers = NULL;
return bResult;
}