2240 lines
63 KiB
C++
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;
|
|
}
|