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.
325 lines
12 KiB
325 lines
12 KiB
/*++
|
|
|
|
Copyright (c) 2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
log.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the implementation of factory specific logging functions.
|
|
|
|
Author:
|
|
|
|
Adrian Cosma (acosma) - 2/14/2001
|
|
|
|
Revision History:
|
|
|
|
|
|
Details:
|
|
|
|
There are 3 logging functions:
|
|
|
|
1) DWORD FacLogFile(DWORD dwLogOpt, UINT uFormat, ...)
|
|
- This takes a variable list of arguments and a resource ID for the error message, followed by
|
|
strings to fill in any fields specified int the resource string. The format sepcifiers are the
|
|
standard C printf() format specifiers.
|
|
|
|
2) DWORD FacLogFileStr(DWORD dwLogOpt, LPTSTR lpFormat, ...)
|
|
- This takes a variable list of arguments and a string for the error message followed by a variable
|
|
number of strings to fill in any fields specified in the error string. The format sepcifiers are the
|
|
standard C printf() format specifiers.
|
|
|
|
|
|
3) DWORD FacLogFileLst(LPCTSTR lpFileName, DWORD dwLogOpt, LPTSTR lpFormat, va_list lpArgs)
|
|
- This takes a variable list of arguments as a va_list. Normally you should not call this function directly.
|
|
|
|
|
|
|
|
Logging options in dwLogOpt - these flags are defined in factoryp.h.
|
|
|
|
#define LOG_DEBUG 0x00000003 // Only log in debug builds if this is specified. (Debug Level for logging.)
|
|
#define LOG_MSG_BOX 0x00000010 // Also display a message box with the error message if this is enabled.
|
|
#define LOG_ERR 0x00000020 // Prefix the logged string with "Error:" if the message is level 0,
|
|
// or "WARNx" if the message is at level x > 0.
|
|
#define LOG_TIME 0x00000040 // Log time if this is enabled
|
|
#define LOG_NO_NL 0x00000080 // Don't add new Line to the end of log string if this is set.
|
|
( A '\n' is appended by default to all strings logged if there is no
|
|
terminating '\n'.)
|
|
|
|
The LogLevel can be set through the winbom through LogLevel=N in the [Factory] section. The default LogLevel in free builds is 0, and the default LogLevel in
|
|
checked builds is LOG_DEBUG (3). The maximum log level in free builds is 2. Any message at MessageLogLevel <= LogLevel
|
|
will be logged.
|
|
|
|
Return value: DWORD - number of bytes written to the log file (this is twice the number of chars in case of UNICODE).
|
|
|
|
Examples:
|
|
|
|
FacLogFileStr(3 | LOG_TIME, _T("Starting to format %c:."), pCur->cDriveLetter);
|
|
- Only log this in Debug builds (3), log the time along with the error message.
|
|
|
|
|
|
FacLogFile(0 | LOG_ERR, IDS_ERR_HUGE_ERROR, dwErrorCode);
|
|
- Always log this error. IDS_ERR_HUGE_ERROR must be defined as a resource in this image.
|
|
IDS_ERR_HUGE_ERROR should look something like this: "Huge Error! Error code: %d". Note the %d is
|
|
for the dwErrorCode.
|
|
|
|
--*/
|
|
|
|
//
|
|
// Includes
|
|
//
|
|
|
|
#include "factoryp.h"
|
|
|
|
|
|
//
|
|
// Defines
|
|
//
|
|
|
|
#ifdef CHR_NEWLINE
|
|
#undef CHR_NEWLINE
|
|
#endif // CHR_NEWLINE
|
|
#define CHR_NEWLINE _T('\n')
|
|
|
|
|
|
#ifdef CHR_CR
|
|
#undef CHR_CR
|
|
#endif // CHR_CR
|
|
#define CHR_CR _T('\r')
|
|
|
|
|
|
//
|
|
// NTRAID#NTBUG9-549770-2002/02/26-acosma - Buffer overruns everywhere in this code. lstrcpy, lstrcat, wsprintf, etc.
|
|
//
|
|
|
|
//
|
|
// Function Implementations
|
|
//
|
|
|
|
DWORD FacLogFileLst(LPCTSTR lpFileName, DWORD dwLogOpt, LPTSTR lpFormat, va_list lpArgs)
|
|
{
|
|
LPTSTR lpAppName = NULL;
|
|
LPTSTR lpPreOut = NULL;
|
|
LPTSTR lpOut = NULL;
|
|
DWORD dwSize = 1024;
|
|
TCHAR szPreLog[MAX_PATH] = NULLSTR;
|
|
HANDLE hFile;
|
|
DWORD dwWritten = 0;
|
|
DWORD cbAppName = 0;
|
|
DWORD dwLogLevel = (DWORD) (dwLogOpt & LOG_LEVEL_MASK);
|
|
|
|
|
|
if ( ( dwLogLevel <= g_dwDebugLevel) && lpFormat )
|
|
{
|
|
// Get the application title from resource.
|
|
//
|
|
lpAppName = AllocateString(g_hInstance, IDS_APPNAME);
|
|
|
|
// Build the output string.
|
|
//
|
|
if ( lpAppName )
|
|
{
|
|
// Create the prefix string
|
|
//
|
|
lstrcpyn(szPreLog, lpAppName, AS ( szPreLog ) );
|
|
if ( FAILED ( StringCchCat ( szPreLog, AS ( szPreLog ), _T("::")) ) )
|
|
{
|
|
FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), szPreLog, _T("::") ) ;
|
|
}
|
|
}
|
|
|
|
// This is for skipping the App Name prefix when printing to the log file
|
|
//
|
|
cbAppName = lstrlen(szPreLog);
|
|
|
|
if ( GET_FLAG(dwLogOpt, LOG_ERR) )
|
|
{
|
|
if ( 0 == dwLogLevel )
|
|
{
|
|
if ( FAILED ( StringCchCat ( szPreLog, AS ( szPreLog ), _T("ERROR: ")) ) )
|
|
{
|
|
FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), szPreLog, _T("ERROR: ") ) ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( FAILED ( StringCchPrintfW ( szPreLog + cbAppName, AS ( szPreLog ) - cbAppName, _T("WARN%d: "), dwLogLevel) ) )
|
|
{
|
|
FacLogFileStr(3, _T("StringCchPrintfW failed %s WARN%d: \n"), szPreLog, dwLogLevel ) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( GET_FLAG(dwLogOpt, LOG_TIME) )
|
|
{
|
|
TCHAR szTime[100] = NULLSTR;
|
|
|
|
GetTimeFormat(LOCALE_SYSTEM_DEFAULT, TIME_FORCE24HOURFORMAT, NULL, _T("'['HH':'mm':'ss'] '"), szTime, AS(szTime));
|
|
|
|
if ( FAILED ( StringCchCat ( szPreLog, AS ( szPreLog ), szTime) ) )
|
|
{
|
|
FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), szPreLog, szTime ) ;
|
|
}
|
|
|
|
}
|
|
|
|
// Replace all the parameters in the Error string. Allocate more memory if necessary.
|
|
// In case something goes seriously wrong here, cap memory allocation at 1 megabyte.
|
|
//
|
|
for ( lpPreOut = (LPTSTR) MALLOC((dwSize) * sizeof(TCHAR));
|
|
lpPreOut && ( FAILED ( StringCchVPrintfW(lpPreOut, dwSize, lpFormat, lpArgs)) ) && dwSize < (1024 * 1024);
|
|
FREE(lpPreOut), lpPreOut = (LPTSTR) MALLOC((dwSize *= 2) * sizeof(TCHAR))
|
|
);
|
|
|
|
//
|
|
// We now have the Error string and the prefix string. Copy this to the final
|
|
// string that we need to output.
|
|
//
|
|
|
|
if ( lpPreOut )
|
|
{
|
|
|
|
// Allocate another string that will be the final output string.
|
|
// We need 1 extra TCHAR for NULL terminator and 2 extra for
|
|
// an optional NewLine + Linefeed TCHAR pair that may be added.
|
|
//
|
|
dwSize = lstrlen(szPreLog) + lstrlen(lpPreOut) + 3;
|
|
lpOut = (LPTSTR) MALLOC( (dwSize) * sizeof(TCHAR) );
|
|
|
|
if ( lpOut )
|
|
{
|
|
lstrcpyn(lpOut, szPreLog, dwSize);
|
|
if ( FAILED ( StringCchCat ( lpOut, dwSize, lpPreOut) ) )
|
|
{
|
|
FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), lpOut, lpPreOut ) ;
|
|
}
|
|
|
|
|
|
// Make sure that string is terminated by NewLine unless the caller doesn't want to.
|
|
//
|
|
if ( !GET_FLAG(dwLogOpt, LOG_NO_NL) )
|
|
{
|
|
LPTSTR lpNL = lpOut;
|
|
TCHAR szCRLF[] = _T("\r\n");
|
|
BOOL bStringOk = FALSE;
|
|
|
|
// Find the end of the string.
|
|
//
|
|
lpNL = lpNL + lstrlen(lpNL);
|
|
|
|
// Make sure the string is terminated by "\r\n".
|
|
//
|
|
// There are three cases here:
|
|
// 1. The string is already terminated by \r\n. Leave it alone.
|
|
// 2. String is terminated by \n. Replace \n with \r\n.
|
|
// 3. String is not terminated by anything. Append string with \r\n.
|
|
//
|
|
|
|
if ( CHR_NEWLINE == *(lpNL = (CharPrev(lpOut, lpNL))) )
|
|
{
|
|
if ( CHR_CR != *(CharPrev(lpOut, lpNL)) )
|
|
{
|
|
*(lpNL) = NULLCHR;
|
|
}
|
|
else
|
|
{
|
|
bStringOk = TRUE;
|
|
}
|
|
}
|
|
|
|
// If there is a need to, fix up the string
|
|
//
|
|
if ( !bStringOk )
|
|
{
|
|
if ( FAILED ( StringCchCat ( lpOut, dwSize, szCRLF) ) )
|
|
{
|
|
FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), lpOut, szCRLF ) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Write the error to the file and close the file.
|
|
// Skip the "AppName::" at the beginning of the string when printing to the file.
|
|
//
|
|
if ( lpFileName && lpFileName[0] &&
|
|
( INVALID_HANDLE_VALUE != (hFile = CreateFile(g_szLogFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)))
|
|
)
|
|
{
|
|
if ( INVALID_SET_FILE_POINTER != SetFilePointer(hFile, 0, 0, FILE_END) )
|
|
{
|
|
WriteFile(hFile, (lpOut + cbAppName), lstrlen(lpOut + cbAppName) * sizeof(TCHAR), &dwWritten, NULL);
|
|
}
|
|
CloseHandle(hFile);
|
|
}
|
|
|
|
// Output the string to the debugger and free it.
|
|
//
|
|
OutputDebugString(lpOut);
|
|
FREE(lpOut);
|
|
}
|
|
|
|
// Put up the MessageBox if specified. This only allows message boxes
|
|
// to be log level 0.
|
|
//
|
|
if ( !GET_FLAG(g_dwFactoryFlags, FLAG_QUIET_MODE) &&
|
|
GET_FLAG(dwLogOpt, LOG_MSG_BOX) &&
|
|
(0 == dwLogLevel)
|
|
)
|
|
MessageBox(NULL, lpPreOut, lpAppName, MB_OK | MB_SYSTEMMODAL |
|
|
(GET_FLAG(dwLogOpt, LOG_ERR) ? MB_ICONERROR : MB_ICONWARNING) );
|
|
|
|
// Free the error string
|
|
//
|
|
FREE(lpPreOut);
|
|
}
|
|
}
|
|
|
|
|
|
// Return the number of bytes written to the file.
|
|
//
|
|
return dwWritten;
|
|
}
|
|
|
|
|
|
DWORD FacLogFile(DWORD dwLogOpt, UINT uFormat, ...)
|
|
{
|
|
va_list lpArgs;
|
|
DWORD dwWritten = 0;
|
|
LPTSTR lpFormat = NULL;
|
|
|
|
// Initialize the lpArgs parameter with va_start().
|
|
//
|
|
va_start(lpArgs, uFormat);
|
|
|
|
if ( lpFormat = AllocateString(NULL, uFormat) )
|
|
{
|
|
dwWritten = FacLogFileLst(g_szLogFile, dwLogOpt, lpFormat, lpArgs);
|
|
}
|
|
|
|
// Free the format string.
|
|
//
|
|
FREE(lpFormat);
|
|
|
|
// Return the value saved from the previous function call.
|
|
//
|
|
return dwWritten;
|
|
}
|
|
|
|
|
|
DWORD FacLogFileStr(DWORD dwLogOpt, LPTSTR lpFormat, ...)
|
|
{
|
|
va_list lpArgs;
|
|
DWORD dwWritten = 0;
|
|
|
|
// Initialize the lpArgs parameter with va_start().
|
|
//
|
|
va_start(lpArgs, lpFormat);
|
|
|
|
dwWritten = FacLogFileLst(g_szLogFile, dwLogOpt, lpFormat, lpArgs);
|
|
|
|
// Return the value saved from the previous function call.
|
|
//
|
|
return dwWritten;
|
|
}
|