Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

794 lines
19 KiB

/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
Debugex.cpp
Abstract:
Implementation of the CDebug class.
Author:
Eran Yariv (EranY) Jul, 1999
Revision History:
--*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>
#include <time.h>
#include "debugex.h"
#include <faxreg.h> // We're reading the default mask from HKLM\REGKEY_FAX_CLIENT\REGVAL_DBGLEVEL_EX
#include <faxutil.h> // For the DEBUG_FAX_TAPI_MSG, DEBUG_VER_MSG, DEBUG_WRN_MSG, and DEBUG_ERR_MSG constants
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#ifdef ENABLE_FRE_LOGGING
#define ENABLE_LOGGING
#endif
#ifdef DEBUG
#define ENABLE_LOGGING
#endif
#ifdef ENABLE_LOGGING
//////////////////////////////////////////////////////////////////////
// Static variables
//////////////////////////////////////////////////////////////////////
HANDLE CDebug::m_shLogFile = INVALID_HANDLE_VALUE;
LONG CDebug::m_sdwIndent = 0;
DWORD CDebug::m_sDbgMask = DEFAULT_DEBUG_MASK;
DWORD CDebug::m_sFmtMask = DEFAULT_FORMAT_MASK;
BOOL CDebug::m_sbMaskReadFromReg = FALSE;
BOOL CDebug::m_sbRegistryExist = FALSE;
BOOL CDebug::m_sbFlush = TRUE;
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CDebug::~CDebug()
/*++
Routine name : CDebug::~CDebug
Routine description:
Destructor
Author:
Eran Yariv (EranY), Jul, 1999
Arguments:
None.
Return Value:
None.
--*/
{
DWORD dwLastError = GetLastError ();
Unindent ();
switch (m_ReturnType)
{
case DBG_FUNC_RET_UNKNOWN:
DbgPrint (FUNC_TRACE, NULL, 0, TEXT("}"));
break;
case DBG_FUNC_RET_HR:
//
// We have the return HRESULT
//
if (NOERROR == *m_phr)
{
DbgPrint (FUNC_TRACE, NULL, 0, TEXT("} (NOERROR)"));
}
else if (S_FALSE == *m_phr)
{
DbgPrint (FUNC_TRACE, NULL, 0, TEXT("} (S_FALSE)"));
}
else
{
DbgPrint (FUNC_TRACE, NULL, 0, TEXT("} (0x%08X)"), *m_phr);
}
break;
case DBG_FUNC_RET_DWORD:
//
// We have the return DWORD
//
if (ERROR_SUCCESS == *m_pDword)
{
DbgPrint (FUNC_TRACE, NULL, 0, TEXT("} (ERROR_SUCCESS)"));
}
else
{
DbgPrint (FUNC_TRACE, NULL, 0, TEXT("} (%ld)"), *m_pDword);
}
break;
case DBG_FUNC_RET_BOOL:
//
// We have the return BOOL
//
if (*m_pBool)
{
DbgPrint (FUNC_TRACE, NULL, 0, TEXT("} (TRUE)"));
}
else
{
DbgPrint (FUNC_TRACE, NULL, 0, TEXT("} (FALSE)"));
}
break;
default:
DbgPrint (ASSERTION_FAILED,
TEXT(__FILE__),
__LINE__,
TEXT("ASSERTION FAILURE!!!"));
{
DebugBreak();
}
break;
}
SetLastError (dwLastError);
}
//////////////////////////////////////////////////////////////////////
// Implementation
//////////////////////////////////////////////////////////////////////
void
CDebug::EnterModuleWithParams (
LPCTSTR lpctstrModule,
LPCTSTR lpctstrFormat,
va_list arg_ptr
)
{
DWORD dwLastError = GetLastError ();
if (!m_sbMaskReadFromReg)
{
ReadMaskFromReg ();
}
lstrcpyn (m_tszModuleName,
lpctstrModule,
ARR_SIZE (m_tszModuleName) - 1);
m_tszModuleName[ARR_SIZE(m_tszModuleName)-1] = TEXT('\0');
TCHAR szArgs[1024] = {0};
_vsntprintf(szArgs, ARR_SIZE(szArgs)-1, lpctstrFormat, arg_ptr);
TCHAR szBuf[1024] = {0};
_sntprintf (szBuf, ARR_SIZE(szBuf) - 1, TEXT("%s (%s)"), m_tszModuleName, szArgs);
DbgPrint (FUNC_TRACE, NULL, 0, szBuf);
DbgPrint (FUNC_TRACE, NULL, 0, TEXT("{"));
Indent ();
SetLastError (dwLastError);
}
void
CDebug::EnterModule (
LPCTSTR lpctstrModule
)
{
DWORD dwLastError = GetLastError ();
if (!m_sbMaskReadFromReg)
{
ReadMaskFromReg ();
}
lstrcpyn (m_tszModuleName,
lpctstrModule,
ARR_SIZE (m_tszModuleName) - 1);
m_tszModuleName[ARR_SIZE(m_tszModuleName)-1] = TEXT('\0');
DbgPrint (FUNC_TRACE, NULL, 0, m_tszModuleName);
DbgPrint (FUNC_TRACE, NULL, 0, TEXT("{"));
Indent ();
SetLastError (dwLastError);
}
//*****************************************************************************
//* Name: OpenLogFile
//* Author: Mooly Beery (MoolyB), May, 2000
//*****************************************************************************
//* DESCRIPTION:
//* Creates a log file which accepts the debug output
//*
//* PARAMETERS:
//* [IN] LPCTSTR lpctstrFilename:
//* the filename which will be created in the temporary folder
//*
//* RETURN VALUE:
//* FALSE if the operation failed.
//* TRUE is succeeded.
//* Comments:
//* this function should be used together with CloseLogFile()
//*****************************************************************************
BOOL CDebug::OpenLogFile(LPCTSTR lpctstrFilename)
{
TCHAR szFilename[MAX_PATH] = {0};
TCHAR szTempFolder[MAX_PATH] = {0};
TCHAR szPathToFile[MAX_PATH] = {0};
if (!lpctstrFilename)
{
DbgPrint (ASSERTION_FAILED,
TEXT(__FILE__),
__LINE__,
TEXT("Internat error - bad Filename"));
DebugBreak();
return FALSE;
}
// first expand the filename
if (ExpandEnvironmentStrings(lpctstrFilename,szFilename,MAX_PATH)==0)
{
return FALSE;
}
// is this is a file description or a complete path to file
if (_tcschr(szFilename,_T('\\'))==NULL)
{
// this is just the file's name, need to add the temp folder to it.
if (GetTempPath(MAX_PATH,szTempFolder)==0)
{
return FALSE;
}
_tcsncpy(szPathToFile,szTempFolder,MAX_PATH-1);
_tcsncat(szPathToFile,szFilename,MAX_PATH-_tcslen(szPathToFile)-1);
}
else
{
// this is the full path to the log file, use it.
_tcsncpy(szPathToFile,szFilename,MAX_PATH-1);
}
m_shLogFile = ::SafeCreateFile(
szPathToFile,
GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
NULL);
if (m_shLogFile==INVALID_HANDLE_VALUE)
{
return FALSE;
}
SetLogFile(m_shLogFile);
// no sense to open the file and not enable printing to it.
m_sFmtMask |= DBG_PRNT_TO_FILE;
return TRUE;
}
//*****************************************************************************
//* Name: CloseLogFile
//* Author: Mooly Beery (MoolyB), May, 2000
//*****************************************************************************
//* DESCRIPTION:
//* Closes the log file which accepts the debug output
//*
//* PARAMETERS:
//*
//* RETURN VALUE:
//*
//* Comments:
//* this function should be used together with OpenLogFile()
//*****************************************************************************
void CDebug::CloseLogFile()
{
if (m_shLogFile!=INVALID_HANDLE_VALUE)
{
::CloseHandle(m_shLogFile);
m_shLogFile = INVALID_HANDLE_VALUE;
}
}
//*****************************************************************************
//* Name: SetLogFile
//* Author: Mooly Beery (MoolyB), May, 2000
//*****************************************************************************
//* DESCRIPTION:
//* redirects the debug output to the file whose handle is given
//*
//* PARAMETERS:
//* [IN] HANDLE hFile:
//* the handle of the file which will accept the debug output
//*
//* RETURN VALUE:
//* the previous handle
//*
//* Comments:
//* this function should be used only in cases the OpenLogFile is
//* insufficient and a different file location/type is required
//* otherwise, don't manipulate the handle yourself, just use the
//* pair OpenLogFile / CloseLogFile
//*****************************************************************************
HANDLE CDebug::SetLogFile(HANDLE hFile)
{
HANDLE OldHandle = m_shLogFile;
m_shLogFile = hFile;
return OldHandle;
}
void CDebug::DbgPrint (
DbgMsgType type,
LPCTSTR lpctstrFileName,
DWORD dwLine,
LPCTSTR lpctstrFormat,
...
)
/*++
Routine name : CDebug::DbgPrint
Routine description:
Print to debug (with file and line number)
Author:
Eran Yariv (EranY), Jul, 1999
Arguments:
type [in] - Type of message
lpctstrFileName [in] - Location of caller
dwLine [in] - Line of caller
lpctstrFormat [in] - printf format string
... [in] - optional parameters
Return Value:
None.
--*/
{
va_list arg_ptr;
va_start(arg_ptr, lpctstrFormat);
Print (type, lpctstrFileName, dwLine, lpctstrFormat, arg_ptr);
va_end (arg_ptr);
}
void CDebug::Trace (
DbgMsgType type,
LPCTSTR lpctstrFormat,
...
)
/*++
Routine name : CDebug::DbgPrint
Routine description:
Trace to debug
Author:
Eran Yariv (EranY), Jul, 1999
Arguments:
type [in] - Type of message
lpctstrFormat [in] - printf format string
... [in] - optional parameters
Return Value:
None.
--*/
{
va_list arg_ptr;
va_start(arg_ptr, lpctstrFormat);
Print (type, NULL, 0, lpctstrFormat, arg_ptr);
va_end (arg_ptr);
}
void CDebug::Print (
DbgMsgType type,
LPCTSTR lpctstrFileName,
DWORD dwLine,
LPCTSTR lpctstrFormat,
va_list arg_ptr
)
/*++
Routine name : CDebug::Print
Routine description:
Print to debug
Author:
Eran Yariv (EranY), Jul, 1999
Mooly Beery (MoolyB), Jun, 2000
Arguments:
type [in] - Type of message
lpctstrFileName [in] - Location of caller
dwLine [in] - Line of caller
lpctstrFormat [in] - printf format string
arg_ptr [in] - optional parameters list
Return Value:
None.
--*/
{
if (!(type & m_sDbgMask))
{
//
// This type of debug message is masked out
//
return;
}
TCHAR szMsg [2000]={0};
TCHAR szBuf [1000]={0};
TCHAR szTimeBuff[10]={0};
TCHAR szDateBuff[10]={0};
DWORD dwLastError = GetLastError();
DWORD dwInd = 0;
// Time stamps
if (m_sFmtMask & DBG_PRNT_TIME_STAMP)
{
dwInd += _stprintf(&szMsg[dwInd],
TEXT("[%-8s %-8s] "),
_tstrdate(szDateBuff),
_tstrtime(szTimeBuff));
}
// Thread ID
if (m_sFmtMask & DBG_PRNT_THREAD_ID)
{
dwInd += _stprintf(&szMsg[dwInd],
TEXT("[0x%04x] "),
GetCurrentThreadId());
}
// Message type
if (m_sFmtMask & DBG_PRNT_MSG_TYPE)
{
dwInd += _stprintf(&szMsg[dwInd],
TEXT("[%s] "),
GetMsgTypeString(type));
}
// Now comes the actual message
_vsntprintf(szBuf, ARR_SIZE(szBuf)-1, lpctstrFormat, arg_ptr);
int i;
i = _sntprintf( &szMsg[dwInd],
ARR_SIZE(szMsg) - dwInd - 1,
TEXT("%*c%s "),
m_sdwIndent * _DEBUG_INDENT_SIZE,
TEXT(' '),
szBuf);
if (i > 0)
{
dwInd += i;
}
else
{
//
// No more room
//
szMsg[ARR_SIZE(szMsg)-1]=TEXT('\0');
goto OutputString;
}
// filename & line number
if (m_sFmtMask & DBG_PRNT_FILE_LINE)
{
if (lpctstrFileName && dwLine)
{
//
// Protect from overrun.
//
i = _sntprintf( &szMsg[dwInd],
ARR_SIZE(szMsg)-dwInd-2, // 2 for '\n' and '\0'
TEXT("(%s %ld)"),
lpctstrFileName,
dwLine);
if (i > 0)
{
dwInd += i;
}
else
{
//
// No more room
//
szMsg[ARR_SIZE(szMsg)-1]=TEXT('\0');
goto OutputString;
}
}
}
_sntprintf( &szMsg[dwInd], ARR_SIZE(szMsg)-dwInd-1, TEXT("\n"));
szMsg[ARR_SIZE(szMsg)-1]=TEXT('\0');
OutputString:
// standard output?
if (m_sFmtMask & DBG_PRNT_TO_STD)
{
OutputDebugString(szMsg);
}
// file output?
if (m_sFmtMask & DBG_PRNT_TO_FILE)
{
if (m_shLogFile!=INVALID_HANDLE_VALUE)
{
OutputFileString(szMsg);
}
}
SetLastError (dwLastError);
} // CDebug::Print
void
CDebug::Unindent()
/*++
Routine name : CDebug::Unindent
Routine description:
Move indention one step backwards
Author:
Eran Yariv (EranY), Jul, 1999
Arguments:
Return Value:
None.
--*/
{
if (InterlockedDecrement(&m_sdwIndent)<0)
{
DbgPrint (ASSERTION_FAILED,
TEXT(__FILE__),
__LINE__,
TEXT("Internat error - bad indent"));
DebugBreak();
}
} // CDebug::Unindent
void CDebug::SetDebugMask(DWORD dwMask)
{
m_sbMaskReadFromReg = TRUE;
m_sDbgMask = dwMask;
}
void CDebug::SetFormatMask(DWORD dwMask)
{
m_sbMaskReadFromReg = TRUE;
m_sFmtMask = dwMask;
}
DWORD CDebug::ModifyDebugMask(DWORD dwAdd,DWORD dwRemove)
{
if (!m_sbMaskReadFromReg)
{
// first let's read the requested debug mask & format
ReadMaskFromReg();
}
m_sDbgMask |= dwAdd;
m_sDbgMask &= ~dwRemove;
return m_sDbgMask;
}
DWORD CDebug::ModifyFormatMask(DWORD dwAdd,DWORD dwRemove)
{
if (!m_sbMaskReadFromReg)
{
// first let's read the requested debug mask & format
ReadMaskFromReg();
}
m_sFmtMask |= dwAdd;
m_sFmtMask &= ~dwRemove;
return m_sFmtMask;
}
void CDebug::SetDebugFlush(BOOL fFlush)
{
m_sbFlush = fFlush;
}
BOOL CDebug::DebugFromRegistry()
{
if (!m_sbMaskReadFromReg)
{
// first let's read the requested debug mask & format
ReadMaskFromReg();
}
return m_sbRegistryExist;
}
BOOL CDebug::ReadMaskFromReg()
{
BOOL bRes = FALSE;
HKEY hkey = NULL;
DWORD dwRegValue;
DWORD dwRegType;
DWORD dwRes;
DWORD dwRegSize = sizeof (dwRegValue);
if (m_sbMaskReadFromReg)
{
//
// Debug & Format mask already read.
//
goto end;
}
m_sbMaskReadFromReg = TRUE;
m_sDbgMask = DEFAULT_DEBUG_MASK;
m_sFmtMask = DEFAULT_FORMAT_MASK;
dwRes = RegOpenKeyEx (HKEY_LOCAL_MACHINE, REGKEY_FAX_CLIENT, 0, KEY_READ, &hkey);
if (ERROR_SUCCESS != dwRes)
{
goto end;
}
dwRes = RegQueryValueEx (hkey,
REGVAL_DBGLEVEL_EX,
NULL,
&dwRegType,
(LPBYTE)&dwRegValue,
&dwRegSize);
if (ERROR_SUCCESS != dwRes)
{
goto end;
}
if (REG_DWORD != dwRegType)
{
//
// Expecting only a DWORD value
//
goto end;
}
m_sDbgMask = dwRegValue;
dwRes = RegQueryValueEx (hkey,
REGVAL_DBGFORMAT_EX,
NULL,
&dwRegType,
(LPBYTE)&dwRegValue,
&dwRegSize);
if (ERROR_SUCCESS != dwRes)
{
goto end;
}
if (REG_DWORD != dwRegType)
{
//
// Expecting only a DWORD value
//
goto end;
}
m_sFmtMask = dwRegValue;
bRes = TRUE;
m_sbRegistryExist = TRUE;
end:
if (hkey)
{
RegCloseKey (hkey);
}
return bRes;
} // CDebug::ReadMaskFromReg
BOOL CDebug::OutputFileString(LPCTSTR szMsg)
{
BOOL bRes = FALSE;
//
// Attempt to add the line to a log file
//
#ifdef UNICODE
char sFileMsg[2000];
int Count = WideCharToMultiByte(
CP_ACP,
0,
szMsg,
-1,
sFileMsg,
sizeof(sFileMsg)/sizeof(sFileMsg[0]),
NULL,
NULL
);
if (Count==0)
{
return bRes;
}
#else
const char* sFileMsg = szMsg;
#endif
DWORD dwFilePointer = ::SetFilePointer(m_shLogFile,0,NULL,FILE_END);
if (dwFilePointer==INVALID_SET_FILE_POINTER)
{
return bRes;
}
DWORD dwNumBytesWritten = 0;
DWORD dwNumOfBytesToWrite = strlen(sFileMsg);
if (!::WriteFile(m_shLogFile,sFileMsg,dwNumOfBytesToWrite,&dwNumBytesWritten,NULL))
{
return bRes;
}
if (dwNumBytesWritten!=dwNumOfBytesToWrite)
{
return bRes;
}
if (m_sbFlush)
{
if (!::FlushFileBuffers(m_shLogFile))
{
return bRes;
}
}
bRes = TRUE;
return bRes;
}
LPCTSTR CDebug::GetMsgTypeString(DWORD dwMask)
{
switch (dwMask)
{
case ASSERTION_FAILED: return _T("ERR");
case DBG_MSG:
case FUNC_TRACE: return _T(" ");
case DBG_WARNING: return _T("WRN");
case MEM_ERR:
case COM_ERR:
case RESOURCE_ERR:
case STARTUP_ERR:
case GENERAL_ERR:
case EXCEPTION_ERR:
case RPC_ERR:
case WINDOW_ERR:
case FILE_ERR:
case SECURITY_ERR:
case REGISTRY_ERR:
case PRINT_ERR:
case SETUP_ERR:
case NET_ERR: return _T("ERR");
default: return _T("???");
}
}
#endif