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.
698 lines
17 KiB
698 lines
17 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
debug.c
|
|
|
|
Abstract:
|
|
|
|
This file implements the debug code for the
|
|
fax project. All components that require
|
|
debug prints, asserts, etc.
|
|
|
|
Author:
|
|
|
|
Wesley Witt (wesw) 22-Dec-1995
|
|
|
|
History:
|
|
1-Sep-1999 yossg add ArielK additions, activate DebugLogPrint
|
|
only while Setup g_fIsSetupLogFileMode
|
|
.
|
|
.
|
|
|
|
Environment:
|
|
|
|
User Mode
|
|
|
|
--*/
|
|
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <tchar.h>
|
|
#include <time.h>
|
|
|
|
#include "faxreg.h"
|
|
#include "faxutil.h"
|
|
|
|
BOOL ConsoleDebugOutput = FALSE;
|
|
INT FaxDebugLevel = -1;
|
|
DWORD FaxDebugLevelEx = -1;
|
|
DWORD FaxFormatLevelEx = -1;
|
|
DWORD FaxContextLevelEx = -1;
|
|
|
|
TCHAR g_szPathToFile[MAX_PATH] = {0};
|
|
DWORD g_dwMaxSize = -1; // max log file size, -1 = no max size
|
|
FILE * g_pLogFile = NULL;
|
|
static BOOL g_fIsSetupLogFileMode = FALSE;
|
|
|
|
HANDLE g_hLogFile = INVALID_HANDLE_VALUE;
|
|
LONG g_iLogFileRefCount = 0;
|
|
|
|
BOOL debugOutputFileString(LPCTSTR szMsg);
|
|
BOOL debugCheckFileSize();
|
|
|
|
VOID
|
|
StartDebugLog(LPTSTR lpszSetupLogFile)
|
|
{
|
|
g_fIsSetupLogFileMode = TRUE;
|
|
if (!g_pLogFile)
|
|
{
|
|
g_pLogFile = _tfopen(lpszSetupLogFile, TEXT("w"));
|
|
}
|
|
}
|
|
|
|
VOID
|
|
CloseDebugLog()
|
|
{
|
|
g_fIsSetupLogFileMode = FALSE;
|
|
if (!g_pLogFile)
|
|
{
|
|
fclose(g_pLogFile);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
DebugLogPrint(
|
|
LPCTSTR buf
|
|
)
|
|
{
|
|
if (g_pLogFile)
|
|
{
|
|
_fputts(TEXT("FAX Server Setup Log: "), g_pLogFile);
|
|
_fputts( buf, g_pLogFile);
|
|
fflush(g_pLogFile);
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//* Name: debugOpenLogFile
|
|
//* Author: Mooly Beery (MoolyB), May, 2000
|
|
//*****************************************************************************
|
|
//* DESCRIPTION:
|
|
//* Creates a log file which accepts the debug output
|
|
//* FormatLevelEx should be set in the registry to include DBG_PRNT_TO_FILE
|
|
//*
|
|
//* PARAMETERS:
|
|
//* [IN] LPCTSTR lpctstrFilename:
|
|
//* the filename which will be created in the temporary folder
|
|
//* [IN] DWORD dwMaxSize
|
|
//* Maximum allowed log file size in bytes. -1 means no max size.
|
|
//*
|
|
//* RETURN VALUE:
|
|
//* FALSE if the operation failed.
|
|
//* TRUE is succeeded.
|
|
//* Comments:
|
|
//* this function should be used together with CloseLogFile()
|
|
//*****************************************************************************
|
|
BOOL debugOpenLogFile(LPCTSTR lpctstrFilename, DWORD dwMaxSize)
|
|
{
|
|
TCHAR szFilename[MAX_PATH] = {0};
|
|
TCHAR szTempFolder[MAX_PATH] = {0};
|
|
|
|
if (g_hLogFile!=INVALID_HANDLE_VALUE)
|
|
{
|
|
InterlockedIncrement(&g_iLogFileRefCount);
|
|
return TRUE;
|
|
}
|
|
|
|
if (!lpctstrFilename)
|
|
{
|
|
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(g_szPathToFile,szTempFolder,MAX_PATH-1);
|
|
_tcsncat(g_szPathToFile,szFilename,MAX_PATH-_tcslen(g_szPathToFile)-1);
|
|
}
|
|
else
|
|
{
|
|
// this is the full path to the log file, use it.
|
|
_tcsncpy(g_szPathToFile,szFilename,MAX_PATH-1);
|
|
}
|
|
g_dwMaxSize = dwMaxSize;
|
|
|
|
g_hLogFile = ::SafeCreateFile(
|
|
g_szPathToFile,
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_WRITE | FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
if (g_hLogFile==INVALID_HANDLE_VALUE)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
DWORD dwFilePointer = ::SetFilePointer(g_hLogFile,0,NULL,FILE_END);
|
|
if (dwFilePointer==INVALID_SET_FILE_POINTER)
|
|
{
|
|
::CloseHandle(g_hLogFile);
|
|
g_hLogFile = INVALID_HANDLE_VALUE;
|
|
return FALSE;
|
|
}
|
|
|
|
InterlockedExchange(&g_iLogFileRefCount,1);
|
|
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 debugCloseLogFile()
|
|
{
|
|
InterlockedDecrement(&g_iLogFileRefCount);
|
|
if (g_iLogFileRefCount==0)
|
|
{
|
|
if (g_hLogFile!=INVALID_HANDLE_VALUE)
|
|
{
|
|
::CloseHandle(g_hLogFile);
|
|
g_hLogFile = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
DWORD
|
|
GetDebugLevel(
|
|
VOID
|
|
)
|
|
{
|
|
DWORD rc;
|
|
DWORD err;
|
|
DWORD size;
|
|
DWORD type;
|
|
HKEY hkey;
|
|
|
|
err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
REGKEY_FAX_CLIENT,
|
|
0,
|
|
KEY_READ,
|
|
&hkey);
|
|
|
|
if (err != ERROR_SUCCESS)
|
|
return 0;
|
|
|
|
size = sizeof(DWORD);
|
|
err = RegQueryValueEx(hkey,
|
|
REGVAL_DBGLEVEL,
|
|
0,
|
|
&type,
|
|
(LPBYTE)&rc,
|
|
&size);
|
|
|
|
if (err != ERROR_SUCCESS || type != REG_DWORD)
|
|
rc = 0;
|
|
|
|
RegCloseKey(hkey);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
DWORD
|
|
GetDebugLevelEx(
|
|
VOID
|
|
)
|
|
{
|
|
DWORD RetVal = 0;
|
|
DWORD err;
|
|
DWORD size;
|
|
DWORD type;
|
|
HKEY hkey;
|
|
|
|
// first let's set the defaults
|
|
|
|
FaxDebugLevelEx = 0; // Default get no debug output
|
|
FaxFormatLevelEx = DBG_PRNT_ALL_TO_STD;
|
|
FaxContextLevelEx = DEBUG_CONTEXT_ALL;
|
|
|
|
err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
REGKEY_FAX_CLIENT,
|
|
0,
|
|
KEY_READ,
|
|
&hkey);
|
|
|
|
if (err != ERROR_SUCCESS)
|
|
return RetVal;
|
|
|
|
size = sizeof(DWORD);
|
|
err = RegQueryValueEx(hkey,
|
|
REGVAL_DBGLEVEL_EX,
|
|
0,
|
|
&type,
|
|
(LPBYTE)&RetVal,
|
|
&size);
|
|
|
|
if (err != ERROR_SUCCESS || type != REG_DWORD)
|
|
{
|
|
RetVal = 0;
|
|
}
|
|
|
|
size = sizeof(DWORD);
|
|
err = RegQueryValueEx(hkey,
|
|
REGVAL_DBGFORMAT_EX,
|
|
0,
|
|
&type,
|
|
(LPBYTE)&FaxFormatLevelEx,
|
|
&size);
|
|
|
|
if (err != ERROR_SUCCESS || type != REG_DWORD)
|
|
{
|
|
FaxFormatLevelEx = DBG_PRNT_ALL_TO_STD;
|
|
}
|
|
|
|
err = RegQueryValueEx(hkey,
|
|
REGVAL_DBGCONTEXT_EX,
|
|
0,
|
|
&type,
|
|
(LPBYTE)&FaxContextLevelEx,
|
|
&size);
|
|
|
|
if (err != ERROR_SUCCESS || type != REG_DWORD)
|
|
{
|
|
FaxContextLevelEx = DEBUG_CONTEXT_ALL;
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
return RetVal;
|
|
}
|
|
|
|
void dprintfex
|
|
(
|
|
DEBUG_MESSAGE_CONTEXT nMessageContext,
|
|
DEBUG_MESSAGE_TYPE nMessageType,
|
|
LPCTSTR lpctstrDbgFunctionName,
|
|
LPCTSTR lpctstrFile,
|
|
DWORD dwLine,
|
|
LPCTSTR lpctstrFormat,
|
|
...
|
|
)
|
|
{
|
|
TCHAR buf[2048] = {0};
|
|
DWORD len;
|
|
va_list arg_ptr;
|
|
TCHAR szExtFormat[2048] = {0};
|
|
LPTSTR lptstrMsgPrefix;
|
|
TCHAR szTimeBuff[10];
|
|
TCHAR szDateBuff[10];
|
|
DWORD dwInd = 0;
|
|
TCHAR bufLocalFile[MAX_PATH] = {0};
|
|
LPTSTR lptstrShortFile = NULL;
|
|
LPTSTR lptstrProject = NULL;
|
|
|
|
DWORD dwLastError = GetLastError();
|
|
|
|
static BOOL bChecked = FALSE;
|
|
|
|
if (!bChecked)
|
|
{
|
|
if (FaxDebugLevelEx==-1)
|
|
FaxDebugLevelEx = GetDebugLevelEx();
|
|
bChecked = TRUE;
|
|
}
|
|
|
|
if (FaxDebugLevelEx == 0)
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
if (!(nMessageType & FaxDebugLevelEx))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
if (!(nMessageContext & FaxContextLevelEx))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
switch (nMessageType)
|
|
{
|
|
case DEBUG_VER_MSG:
|
|
lptstrMsgPrefix=TEXT(" ");
|
|
break;
|
|
case DEBUG_WRN_MSG:
|
|
lptstrMsgPrefix=TEXT("WRN");
|
|
break;
|
|
case DEBUG_ERR_MSG:
|
|
lptstrMsgPrefix=TEXT("ERR");
|
|
break;
|
|
case DEBUG_FAX_TAPI_MSG:
|
|
lptstrMsgPrefix=TEXT("TAP");
|
|
break;
|
|
default:
|
|
_ASSERT(FALSE);
|
|
lptstrMsgPrefix=TEXT(" ");
|
|
break;
|
|
}
|
|
|
|
// Date & Time stamps
|
|
if( FaxFormatLevelEx & DBG_PRNT_TIME_STAMP )
|
|
{
|
|
dwInd += _stprintf(&szExtFormat[dwInd],
|
|
TEXT("[%-8s %-8s]"),
|
|
_tstrdate(szDateBuff),
|
|
_tstrtime(szTimeBuff));
|
|
}
|
|
// Tick Count
|
|
if( FaxFormatLevelEx & DBG_PRNT_TICK_COUNT )
|
|
{
|
|
dwInd += _stprintf(&szExtFormat[dwInd],
|
|
TEXT("[%09d]"),
|
|
GetTickCount());
|
|
}
|
|
// Thread ID
|
|
if( FaxFormatLevelEx & DBG_PRNT_THREAD_ID )
|
|
{
|
|
dwInd += _stprintf(&szExtFormat[dwInd],
|
|
TEXT("[0x%05x]"),
|
|
GetCurrentThreadId());
|
|
}
|
|
// Message type
|
|
if( FaxFormatLevelEx & DBG_PRNT_MSG_TYPE )
|
|
{
|
|
dwInd += _stprintf(&szExtFormat[dwInd],
|
|
TEXT("[%s]"),
|
|
lptstrMsgPrefix);
|
|
}
|
|
// filename & line number
|
|
if( FaxFormatLevelEx & DBG_PRNT_FILE_LINE )
|
|
{
|
|
_tcsncpy(bufLocalFile,lpctstrFile,MAX_PATH-1);
|
|
lptstrShortFile = _tcsrchr(bufLocalFile,_T('\\'));
|
|
if (lptstrShortFile)
|
|
{
|
|
(*lptstrShortFile) = _T('\0');
|
|
lptstrProject = _tcsrchr(bufLocalFile,_T('\\'));
|
|
(*lptstrShortFile) = _T('\\');
|
|
if (lptstrProject)
|
|
lptstrProject = _tcsinc(lptstrProject);
|
|
}
|
|
|
|
dwInd += _stprintf( &szExtFormat[dwInd],
|
|
TEXT("[%-20s][%-4ld]"),
|
|
lptstrProject,
|
|
dwLine);
|
|
}
|
|
// Module name
|
|
if( FaxFormatLevelEx & DBG_PRNT_MOD_NAME )
|
|
{
|
|
dwInd += _stprintf(&szExtFormat[dwInd],
|
|
TEXT("[%-20s]"),
|
|
lpctstrDbgFunctionName);
|
|
}
|
|
// Now comes the actual message
|
|
va_start(arg_ptr, lpctstrFormat);
|
|
_vsntprintf(buf, ARR_SIZE(buf) - 1, lpctstrFormat, arg_ptr);
|
|
len = _tcslen(buf);
|
|
_tcsncpy (&szExtFormat[dwInd], buf, ARR_SIZE(szExtFormat) - dwInd - 1);
|
|
dwInd += len;
|
|
//
|
|
// Limit index to szExtFormat size
|
|
//
|
|
if (dwInd > ARR_SIZE(szExtFormat)-3)
|
|
{
|
|
dwInd = ARR_SIZE(szExtFormat)-3;
|
|
}
|
|
|
|
_stprintf( &szExtFormat[dwInd],TEXT("\r\n"));
|
|
|
|
if( FaxFormatLevelEx & DBG_PRNT_TO_STD )
|
|
{
|
|
OutputDebugString( szExtFormat);
|
|
}
|
|
|
|
if ( FaxFormatLevelEx & DBG_PRNT_TO_FILE )
|
|
{
|
|
if (g_hLogFile!=INVALID_HANDLE_VALUE)
|
|
{
|
|
debugOutputFileString(szExtFormat);
|
|
}
|
|
}
|
|
|
|
exit:
|
|
SetLastError (dwLastError); // dprintfex will not change LastError
|
|
return;
|
|
}
|
|
|
|
BOOL debugOutputFileString(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 dwNumBytesWritten = 0;
|
|
DWORD dwNumOfBytesToWrite = strlen(sFileMsg);
|
|
if (!::WriteFile(g_hLogFile,sFileMsg,dwNumOfBytesToWrite,&dwNumBytesWritten,NULL))
|
|
{
|
|
return bRes;
|
|
}
|
|
|
|
if (dwNumBytesWritten!=dwNumOfBytesToWrite)
|
|
{
|
|
return bRes;
|
|
}
|
|
|
|
// ::FlushFileBuffers(g_hLogFile);
|
|
if (g_dwMaxSize != -1)
|
|
{ // There's a file size limitation, let's see if we exceeded it
|
|
debugCheckFileSize();
|
|
// Ignore return value - there's nothing we can do about it anyway
|
|
}
|
|
bRes = TRUE;
|
|
return bRes;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//* Name: debugCheckFileSize
|
|
//* Author: Jonathan Barner (t-jonb), August 2001
|
|
//*****************************************************************************
|
|
//* DESCRIPTION:
|
|
//* Checks whether the log file exceeded the maximum size specified
|
|
//* in debugOpenLogFile. If so, renames the file (overwriting the last
|
|
//* renamed file, if exists), and creates a new log file.
|
|
//*
|
|
//* PARAMETERS: none
|
|
//* RETURN VALUE: TRUE - success, FALSE - failure
|
|
//*
|
|
//*****************************************************************************
|
|
BOOL debugCheckFileSize()
|
|
{
|
|
DWORD dwSizeHigh=0, dwSizeLow=0;
|
|
|
|
dwSizeLow = GetFileSize(g_hLogFile, &dwSizeHigh);
|
|
|
|
if (dwSizeLow==INVALID_FILE_SIZE && (GetLastError()!=NO_ERROR))
|
|
{
|
|
return FALSE;
|
|
}
|
|
if (dwSizeHigh>0 || dwSizeLow>g_dwMaxSize)
|
|
{
|
|
TCHAR szPathToFileOld[MAX_PATH] = {0};
|
|
PTCHAR lpszDot = NULL;
|
|
|
|
_tcsncpy(szPathToFileOld, g_szPathToFile, MAX_PATH - 1);
|
|
|
|
// Change File.txt into FileOld.txt
|
|
lpszDot = _tcsrchr(szPathToFileOld, _T('.'));
|
|
if (lpszDot != NULL)
|
|
{
|
|
*lpszDot = _T('\0');
|
|
}
|
|
if (_tcslen(szPathToFileOld)+7 > MAX_PATH) // strlen("Old.txt") = 7
|
|
{
|
|
return FALSE;
|
|
}
|
|
_tcscat(szPathToFileOld, _T("Old.txt"));
|
|
|
|
if (! ::CloseHandle(g_hLogFile))
|
|
{
|
|
return FALSE;
|
|
}
|
|
g_hLogFile = INVALID_HANDLE_VALUE;
|
|
|
|
::MoveFileEx(g_szPathToFile, szPathToFileOld, MOVEFILE_REPLACE_EXISTING);
|
|
// MoveFileEx could fail if the old file is open. In this case, do nothing
|
|
|
|
g_hLogFile = ::SafeCreateFile(
|
|
g_szPathToFile,
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_WRITE | FILE_SHARE_READ,
|
|
NULL,
|
|
CREATE_ALWAYS, // overwrite old file
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
if (g_hLogFile==INVALID_HANDLE_VALUE)
|
|
{
|
|
// We closed the file and never opened it again - so we
|
|
// need to decrement reference count
|
|
InterlockedDecrement(&g_iLogFileRefCount);
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void
|
|
fax_dprintf(
|
|
LPCTSTR Format,
|
|
...
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Prints a debug string
|
|
|
|
Arguments:
|
|
|
|
format - printf() format string
|
|
... - Variable data
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
TCHAR buf[1024] = {0};
|
|
DWORD len;
|
|
va_list arg_ptr;
|
|
static BOOL bChecked = FALSE;
|
|
|
|
if (!bChecked) {
|
|
FaxDebugLevel = (INT) GetDebugLevel();
|
|
bChecked = TRUE;
|
|
}
|
|
|
|
if (!g_fIsSetupLogFileMode)
|
|
{
|
|
if (FaxDebugLevel <= 0)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
va_start(arg_ptr, Format);
|
|
|
|
_vsntprintf(buf, ARR_SIZE(buf) - 1, Format, arg_ptr);
|
|
len = min(_tcslen( buf ), ARR_SIZE(buf)-3);
|
|
if (buf[len-1] != TEXT('\n'))
|
|
{
|
|
buf[len] = TEXT('\r');
|
|
buf[len+1] = TEXT('\n');
|
|
buf[len+2] = 0;
|
|
}
|
|
OutputDebugString( buf );
|
|
if (g_fIsSetupLogFileMode)
|
|
{
|
|
DebugLogPrint(buf);
|
|
}
|
|
} // fax_dprintf
|
|
|
|
|
|
VOID
|
|
AssertError(
|
|
LPCTSTR Expression,
|
|
LPCTSTR File,
|
|
ULONG LineNumber
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Thie function is use together with the Assert MACRO.
|
|
It checks to see if an expression is FALSE. if the
|
|
expression is FALSE, then you end up here.
|
|
|
|
Arguments:
|
|
|
|
Expression - The text of the 'C' expression
|
|
File - The file that caused the assertion
|
|
LineNumber - The line number in the file.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
fax_dprintf(
|
|
TEXT("Assertion error: [%s] %s @ %d\n"),
|
|
Expression,
|
|
File,
|
|
LineNumber
|
|
);
|
|
|
|
#ifdef DEBUG
|
|
__try {
|
|
DebugBreak();
|
|
} __except (UnhandledExceptionFilter(GetExceptionInformation())) {
|
|
// Nothing to do in here.
|
|
}
|
|
#endif // DEBUG
|
|
}
|
|
|
|
void debugSetProperties(DWORD dwLevel,DWORD dwFormat,DWORD dwContext)
|
|
{
|
|
FaxDebugLevelEx = dwLevel;
|
|
FaxFormatLevelEx = dwFormat;
|
|
FaxContextLevelEx = dwContext;
|
|
}
|
|
|