source-engine/utils/sapi51/include/spdebug.h
FluorescentCIAAfricanAmerican 3bf9df6b27 1
2020-04-22 12:56:21 -04:00

637 lines
23 KiB
C++

/*******************************************************************************
* SPDebug.h *
*-----------*
* Description:
* This header file contains debug output services for SAPI5
*-------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
*******************************************************************************/
#pragma once
#include <TCHAR.h>
#include <crtdbg.h>
#ifdef ASSERT_WITH_STACK
#include "AssertWithStack.h"
#endif
const TCHAR g_szSpDebugKey[] = _T("SPDebug");
const TCHAR g_szSpDebugFuncTraceReportMode[] = _T("FuncTraceMode");
const TCHAR g_szSpDebugFuncTraceReportFile[] = _T("FuncTraceFile");
const TCHAR g_szSpDebugParamInfoReportMode[] = _T("ParamInfoMode");
const TCHAR g_szSpDebugParamInfoReportFile[] = _T("ParamInfoFile");
const TCHAR g_szSpDebugDumpInfoReportMode[] = _T("DumpInfoMode");
const TCHAR g_szSpDebugDumpInfoReportFile[] = _T("DumpInfoFile");
const TCHAR g_szSpDebugAssertReportMode[] = _T("AssertMode");
const TCHAR g_szSpDebugAssertReportFile[] = _T("AssertFile");
const TCHAR g_szSpDebugHRFailReportMode[] = _T("HRFailMode");
const TCHAR g_szSpDebugHRFailReportFile[] = _T("HRFailFile");
const TCHAR g_szSpDebugAssertSettingsReReadEachTime[] = _T("AssertSettingsReReadEachTime");
const TCHAR g_szSpDebugServerOnStart[] = _T("DebugServerOnStart");
const TCHAR g_szSpDebugClientOnStart[] = _T("DebugClientOnStart");
const TCHAR g_szSpDebugLog[] = _T("c:\\spdebug.log");
#ifdef _DEBUG
class CSpDebug
{
public:
CSpDebug()
{
m_mutex = NULL;
m_reportModePrev = -1;
m_hfilePrev = NULL;
Read();
}
~CSpDebug()
{
if (m_mutex != NULL)
{
CloseHandle(m_mutex);
}
}
BOOL FuncTrace(BOOL fEnter = TRUE)
{
return fEnter
? Enter(_CRT_WARN, m_FuncTraceMode, m_szFuncTraceFile)
: Leave();
}
BOOL ParamInfo(BOOL fEnter = TRUE)
{
return fEnter
? Enter(_CRT_WARN, m_ParamInfoMode, m_szParamInfoFile)
: Leave();
}
BOOL DumpInfo(BOOL fEnter = TRUE)
{
return fEnter
? Enter(_CRT_WARN, m_DumpInfoMode, m_szDumpInfoFile)
: Leave();
}
BOOL Assert(BOOL fEnter = TRUE)
{
if (m_fAssertSettingsReReadEachTime)
Read();
return fEnter
? Enter(_CRT_ASSERT, m_AssertMode, m_szAssertFile)
: Leave();
}
BOOL HRFail(BOOL fEnter = TRUE)
{
return fEnter
? Enter(_CRT_WARN, m_HRFailMode, m_szHRFailFile)
: Leave();
}
BOOL DebugServerOnStart()
{
return m_fDebugServerOnStart;
}
BOOL DebugClientOnStart()
{
return m_fDebugClientOnStart;
}
private:
void Read()
{
HKEY hkeyDebug;
RegCreateKeyEx(
HKEY_CLASSES_ROOT,
g_szSpDebugKey,
0,
NULL,
0,
KEY_READ | KEY_WRITE,
NULL,
&hkeyDebug,
NULL);
if (hkeyDebug == NULL)
{
RegCreateKeyEx(
HKEY_CLASSES_ROOT,
g_szSpDebugKey,
0,
NULL,
0,
KEY_READ,
NULL,
&hkeyDebug,
NULL);
}
DWORD dw = sizeof(m_fAssertSettingsReReadEachTime);
if (RegQueryValueEx(
hkeyDebug,
g_szSpDebugAssertSettingsReReadEachTime,
NULL,
NULL,
LPBYTE(&m_fAssertSettingsReReadEachTime),
&dw) != ERROR_SUCCESS)
{
m_fAssertSettingsReReadEachTime = FALSE;
RegSetValueEx(
hkeyDebug,
g_szSpDebugAssertSettingsReReadEachTime,
NULL,
REG_DWORD,
LPBYTE(&m_fAssertSettingsReReadEachTime),
sizeof(m_fAssertSettingsReReadEachTime));
}
ReadFor(
hkeyDebug,
g_szSpDebugFuncTraceReportMode,
g_szSpDebugFuncTraceReportFile,
&m_FuncTraceMode,
m_szFuncTraceFile,
0,
g_szSpDebugLog);
ReadFor(
hkeyDebug,
g_szSpDebugParamInfoReportMode,
g_szSpDebugParamInfoReportFile,
&m_ParamInfoMode,
m_szParamInfoFile,
0,
g_szSpDebugLog);
ReadFor(
hkeyDebug,
g_szSpDebugDumpInfoReportMode,
g_szSpDebugDumpInfoReportFile,
&m_DumpInfoMode,
m_szDumpInfoFile,
_CRTDBG_MODE_DEBUG,
g_szSpDebugLog);
ReadFor(
hkeyDebug,
g_szSpDebugAssertReportMode,
g_szSpDebugAssertReportFile,
&m_AssertMode,
m_szAssertFile,
_CRTDBG_MODE_WNDW,
g_szSpDebugLog);
ReadFor(
hkeyDebug,
g_szSpDebugHRFailReportMode,
g_szSpDebugHRFailReportFile,
&m_HRFailMode,
m_szHRFailFile,
_CRTDBG_MODE_DEBUG,
g_szSpDebugLog);
dw = sizeof(m_fDebugServerOnStart);
if (RegQueryValueEx(
hkeyDebug,
g_szSpDebugServerOnStart,
NULL,
NULL,
LPBYTE(&m_fDebugServerOnStart),
&dw) != ERROR_SUCCESS)
{
m_fDebugServerOnStart = FALSE;
RegSetValueEx(
hkeyDebug,
g_szSpDebugServerOnStart,
NULL,
REG_DWORD,
LPBYTE(&m_fDebugServerOnStart),
sizeof(m_fDebugServerOnStart));
}
dw = sizeof(m_fDebugClientOnStart);
if (RegQueryValueEx(
hkeyDebug,
g_szSpDebugClientOnStart,
NULL,
NULL,
LPBYTE(&m_fDebugClientOnStart),
&dw) != ERROR_SUCCESS)
{
m_fDebugClientOnStart = FALSE;
RegSetValueEx(
hkeyDebug,
g_szSpDebugClientOnStart,
NULL,
REG_DWORD,
LPBYTE(&m_fDebugClientOnStart),
sizeof(m_fDebugClientOnStart));
}
RegCloseKey(hkeyDebug);
}
void ReadFor(
HKEY hkey,
const TCHAR * pszModeValueName,
const TCHAR * pszFileValueName,
DWORD * pdwModeValue,
TCHAR * pszFileValue,
DWORD dwDefaultModeValue,
const TCHAR * pszDefaultFileValue)
{
DWORD dw = sizeof(*pdwModeValue);
if (RegQueryValueEx(
hkey,
pszModeValueName,
NULL,
NULL,
LPBYTE(pdwModeValue),
&dw) != ERROR_SUCCESS)
{
*pdwModeValue = dwDefaultModeValue;
RegSetValueEx(
hkey,
pszModeValueName,
NULL,
REG_DWORD,
LPBYTE(pdwModeValue),
sizeof(*pdwModeValue));
}
dw = MAX_PATH;
if (RegQueryValueEx(
hkey,
pszFileValueName,
NULL,
NULL,
LPBYTE(pszFileValue),
&dw) != ERROR_SUCCESS)
{
_tcscpy(pszFileValue, pszDefaultFileValue);
RegSetValueEx(
hkey,
pszFileValueName,
NULL,
REG_SZ,
LPBYTE(pszFileValue),
MAX_PATH);
}
}
BOOL Enter(int reportType, DWORD &reportMode, TCHAR * pszFile)
{
if (reportMode != 0)
{
// We'll hold the mutex, until the caller also calls Leave
if (m_mutex == NULL)
{
m_mutex = CreateMutex(NULL, FALSE, _T("SpDebug"));
}
WaitForSingleObject(m_mutex, INFINITE);
m_reportType = reportType;
m_reportModePrev = _CrtSetReportMode(reportType, reportMode);
if (reportMode & _CRTDBG_MODE_FILE)
{
HANDLE hfile = CreateFile(
pszFile,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
0,
NULL);
SetFilePointer(hfile, 0, NULL, FILE_END);
m_hfilePrev = (_HFILE)_CrtSetReportFile(reportType, (_HFILE)hfile);
}
return TRUE;
}
return FALSE;
}
BOOL Leave()
{
int reportMode = _CrtSetReportMode(m_reportType, m_reportModePrev);
if (reportMode & _CRTDBG_MODE_FILE)
{
CloseHandle((_HFILE)_CrtSetReportFile(m_reportType, (_HFILE)m_hfilePrev));
}
ReleaseMutex(m_mutex);
return TRUE;
}
private:
HANDLE m_mutex;
int m_reportType;
int m_reportModePrev;
_HFILE m_hfilePrev;
BOOL m_fAssertSettingsReReadEachTime;
DWORD m_FuncTraceMode;
TCHAR m_szFuncTraceFile[MAX_PATH + 1];
DWORD m_ParamInfoMode;
TCHAR m_szParamInfoFile[MAX_PATH + 1];
DWORD m_DumpInfoMode;
TCHAR m_szDumpInfoFile[MAX_PATH + 1];
DWORD m_AssertMode;
TCHAR m_szAssertFile[MAX_PATH + 1];
DWORD m_HRFailMode;
TCHAR m_szHRFailFile[MAX_PATH + 1];
BOOL m_fDebugServerOnStart;
BOOL m_fDebugClientOnStart;
};
inline CSpDebug *PSpDebug()
{
static CSpDebug debug;
return &debug;
}
class CSpFuncTrace
{
public:
CSpFuncTrace(PCHAR pFuncName)
{
m_pFuncName = pFuncName;
if (PSpDebug()->FuncTrace())
{
_RPT1( _CRT_WARN, "\nEntering Function: %s\n", m_pFuncName );
PSpDebug()->FuncTrace(FALSE);
}
}
~CSpFuncTrace()
{
if (PSpDebug()->FuncTrace())
{
_RPT1( _CRT_WARN, "Leaving Function: %s\n", m_pFuncName );
PSpDebug()->FuncTrace(FALSE);
}
}
private:
PCHAR m_pFuncName;
};
#endif // _DEBUG
//=== User macros ==============================================================
#ifdef _DEBUG
#define SPDBG_FUNC(name) \
CSpFuncTrace functrace(name)
#if defined(ASSERT_WITH_STACK) && !defined(_WIN64)
#define SPDBG_REPORT_ON_FAIL(hr) \
do \
{ \
HRESULT _hr = (hr); \
if (FAILED(_hr) && PSpDebug()->HRFail()) \
{ \
SYSTEMTIME sysTime; \
GetLocalTime(&sysTime); \
CHAR pszHrWithTime[100]; \
sprintf(pszHrWithTime, "%lX\n\n%d.%d.%d %02d:%02d:%02d", \
_hr, \
sysTime.wMonth,sysTime.wDay,sysTime.wYear, \
sysTime.wHour,sysTime.wMinute,sysTime.wSecond); \
PCHAR pszStack = \
(PCHAR)_alloca( \
cchMaxAssertStackLevelStringLen * \
cfrMaxAssertStackLevels + 1); \
GetStringFromStackLevels(0, 10, pszStack); \
_RPT4(_CRT_WARN, \
"%s(%d): Failed HR = %s\n\n%s\n", \
__FILE__, \
__LINE__, \
pszHrWithTime, \
pszStack); \
PSpDebug()->HRFail(FALSE); \
} \
} while (0)
#else // ASSERT_WITH_STACK & !_WIN64
#define SPDBG_REPORT_ON_FAIL(hr) \
do \
{ \
HRESULT _hr = (hr); \
if (FAILED(_hr) && PSpDebug()->HRFail()) \
{ \
_RPT3(_CRT_WARN, "%s(%d): Failed HR = %lX\n", __FILE__, __LINE__, (_hr) );\
PSpDebug()->HRFail(FALSE); \
} \
} while (0)
#endif // ASSERT_WITH_STACK
#define SPDBG_ASSERT(expr) \
do \
{ \
if (!(expr)) \
{ \
if (PSpDebug()->Assert()) \
{ \
_ASSERTE( expr ); \
PSpDebug()->Assert(FALSE); \
} \
} \
} \
while (0)
#define SPDBG_VERIFY(expr) \
SPDBG_ASSERT(expr)
#define SPDBG_PMSG0(format) \
do \
{ \
if (PSpDebug()->ParamInfo()) \
{ \
_RPT0(_CRT_WARN, format); \
PSpDebug()->ParamInfo(FALSE); \
} \
} while (0)
#define SPDBG_PMSG1(format, arg1) \
do \
{ \
if (PSpDebug()->ParamInfo()) \
{ \
_RPT1(_CRT_WARN, format, arg1); \
PSpDebug()->ParamInfo(FALSE); \
} \
} while (0)
#define SPDBG_PMSG2(format, arg1, arg2) \
do \
{ \
if (PSpDebug()->ParamInfo()) \
{ \
_RPT2(_CRT_WARN, format, arg1, arg2); \
PSpDebug()->ParamInfo(FALSE); \
} \
} while (0)
#define SPDBG_PMSG3(format, arg1, arg2, arg3) \
do \
{ \
if (PSpDebug()->ParamInfo()) \
{ \
_RPT3(_CRT_WARN, format, arg1, arg2, arg3); \
PSpDebug()->ParamInfo(FALSE); \
} \
} while (0)
#define SPDBG_PMSG4(format, arg1, arg2, arg3, arg4) \
do \
{ \
if (PSpDebug()->ParamInfo()) \
{ \
_RPT4(_CRT_WARN, format, arg1, arg2, arg3, arg4); \
PSpDebug()->ParamInfo(FALSE); \
} \
} while (0)
#define SPDBG_DMSG0(format) \
do \
{ \
if (PSpDebug()->DumpInfo()) \
{ \
_RPT0(_CRT_WARN, format); \
PSpDebug()->DumpInfo(FALSE); \
} \
} while (0)
#define SPDBG_DMSG1(format, arg1) \
do \
{ \
if (PSpDebug()->DumpInfo()) \
{ \
_RPT1(_CRT_WARN, format, arg1); \
PSpDebug()->DumpInfo(FALSE); \
} \
} while (0)
#define SPDBG_DMSG2(format, arg1, arg2) \
do \
{ \
if (PSpDebug()->DumpInfo()) \
{ \
_RPT2(_CRT_WARN, format, arg1, arg2); \
PSpDebug()->DumpInfo(FALSE); \
} \
} while (0)
#define SPDBG_DMSG3(format, arg1, arg2, arg3) \
do \
{ \
if (PSpDebug()->DumpInfo()) \
{ \
_RPT3(_CRT_WARN, format, arg1, arg2, arg3); \
PSpDebug()->DumpInfo(FALSE); \
} \
} while (0)
#define SPDBG_DMSG4(format, arg1, arg2, arg3, arg4) \
do \
{ \
if (PSpDebug()->DumpInfo()) \
{ \
_RPT4(_CRT_WARN, format, arg1, arg2, arg3, arg4); \
PSpDebug()->DumpInfo(FALSE); \
} \
} while (0)
#define SPDBG_RETURN(hr) \
{ \
HRESULT __hr = (hr); \
if (FAILED(__hr)) \
{ \
SPDBG_REPORT_ON_FAIL(__hr); \
} \
return __hr; \
}
#define SPDBG_DEBUG_SERVER_ON_START() \
{ \
if (PSpDebug()->DebugServerOnStart()) \
{ \
if (MessageBox( \
GetDesktopWindow(), \
_T("Attach Debugger to the SAPI Server process?"), \
_T("SAPI"), \
MB_YESNO) == IDYES) \
{ \
USES_CONVERSION; \
TCHAR szCommand[MAX_PATH + 1]; \
wsprintf( \
szCommand, \
_T("msdev -p %d"), \
GetCurrentProcessId()); \
system(T2A(szCommand)); \
} \
} \
}
#define SPDBG_DEBUG_CLIENT_ON_START() \
{ \
if (PSpDebug()->DebugClientOnStart()) \
{ \
TCHAR szModule[MAX_PATH + 1]; \
szModule[0] = '\0'; \
TCHAR * pszSapiServer = \
_T("sapisvr.exe"); \
GetModuleFileName( \
NULL, \
szModule, \
MAX_PATH); \
if ((_tcslen(szModule) <= \
_tcslen(pszSapiServer) || \
_tcsicmp( \
szModule + \
_tcslen(szModule) - \
_tcslen(pszSapiServer), \
pszSapiServer) != 0) && \
MessageBox( \
GetDesktopWindow(), \
_T("Attach Debugger to the SAPI Client process?"), \
_T("SAPI"), \
MB_YESNO) == IDYES) \
{ \
USES_CONVERSION; \
TCHAR szCommand[MAX_PATH + 1]; \
wsprintf( \
szCommand, \
_T("msdev -p %d"), \
GetCurrentProcessId()); \
system(T2A(szCommand)); \
} \
} \
}
#else // _DEBUG
#define SPDBG_FUNC(name)
#define SPDBG_REPORT_ON_FAIL(hr)
#define SPDBG_ASSERT(expr)
#define SPDBG_VERIFY(expr) (expr)
#define SPDBG_PMSG0(format)
#define SPDBG_PMSG1(format, arg1)
#define SPDBG_PMSG2(format, arg1, arg2)
#define SPDBG_PMSG3(format, arg1, arg2, arg3)
#define SPDBG_PMSG4(format, arg1, arg2, arg3, arg4)
#define SPDBG_DMSG0(format)
#define SPDBG_DMSG1(format, arg1)
#define SPDBG_DMSG2(format, arg1, arg2)
#define SPDBG_DMSG3(format, arg1, arg2, arg3)
#define SPDBG_DMSG4(format, arg1, arg2, arg3, arg4)
#define SPDBG_RETURN(hr) return (hr)
#define SPDBG_DEBUG_SERVER_ON_START()
#define SPDBG_DEBUG_CLIENT_ON_START()
#endif // _DEBUG