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.
 
 
 
 
 
 

1486 lines
39 KiB

//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 1997-2002 Microsoft Corporation
//
// Module Name:
// LogSrc.cpp
//
// Description:
// Logging utilities.
//
// Documentation:
// Spec\Admin\Debugging.ppt
//
// Maintained By:
// Galen Barbee (GalenB) 05-DEC-2000
//
// Note:
// THRs and TW32s should NOT be used in this module because they
// could cause an infinite loop.
//
//////////////////////////////////////////////////////////////////////////////
// #include <Pch.h> // should be included by includer of this file
#include <stdio.h>
#include <StrSafe.h> // in case it isn't included by header file
#include <windns.h>
#include "Common.h"
//****************************************************************************
//****************************************************************************
//
// Logging Functions
//
// These are in both DEBUG and RETAIL.
//
//****************************************************************************
//****************************************************************************
//
// Constants
//
static const int LOG_OUTPUT_BUFFER_SIZE = 1024;
static const int TIMESTAMP_BUFFER_SIZE = 25;
//
// Globals
//
static CRITICAL_SECTION * g_pcsLogging = NULL;
static HANDLE g_hLogFile = INVALID_HANDLE_VALUE;
static WCHAR g_szLogFilePath[ MAX_PATH ];
//////////////////////////////////////////////////////////////////////////////
//++
//
// PszLogFilePath
//
// Description:
// Returns the log file path that is currently used by the wizard.
//
// Arguments:
// None.
//
// Return Values:
// LPCWSTR - The log file path that is currently used by the wizard
//
//--
//////////////////////////////////////////////////////////////////////////////
LPCWSTR
PszLogFilePath( void )
{
return g_szLogFilePath;
} //*** PszLogFilePath
//////////////////////////////////////////////////////////////////////////////
//++
//
// HrGetLogFilePath
//
// Description:
// Takes in a directory path and appends module log file name to it and
// returns the full log file path.
//
// Arguments:
// pszPathIn - The directory where the log file will be created.
// pszFilePathOut - Log file path.
// pcchFilePathInout - Size of the log file path buffer.
//
// Return Values:
// S_OK - Success
// ERROR_MORE_DATA - If the output buffer is too small.
// Other HRESULTs
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrGetLogFilePath(
const WCHAR * pszPathIn
, WCHAR * pszFilePathOut
, size_t * pcchFilePathInout
, HINSTANCE hInstanceIn
)
{
HRESULT hr = S_OK;
WCHAR szModulePath[ MAX_PATH ];
DWORD dwLen;
LPWSTR psz;
//
// Create the directory tree.
//
dwLen = ExpandEnvironmentStringsW( pszPathIn, pszFilePathOut, static_cast< DWORD >( *pcchFilePathInout ) );
if ( dwLen > *pcchFilePathInout )
{
hr = HRESULT_FROM_WIN32( ERROR_MORE_DATA );
*pcchFilePathInout = dwLen;
goto Cleanup;
}
hr = HrCreateDirectoryPath( pszFilePathOut );
if ( FAILED( hr ) )
{
#if defined( DEBUG )
if ( !( g_tfModule & mtfOUTPUTTODISK ) )
{
DebugMsg( "*ERROR* Failed to create directory tree %s", pszFilePathOut );
} // if: not logging to disk
#endif
goto Cleanup;
} // if: failed
//
// Add filename.
//
dwLen = GetModuleFileNameW( hInstanceIn, szModulePath, ARRAYSIZE( szModulePath ) );
Assert( dwLen != 0 );
// Replace extension.
psz = wcsrchr( szModulePath, L'.' );
Assert( psz != NULL );
if ( psz == NULL )
{
hr = E_POINTER;
goto Cleanup;
}
THR( StringCchCopyW( psz, ( psz - szModulePath ) / sizeof( *psz ), L".log" ) );
// Copy resulting filename to output buffer.
psz = wcsrchr( szModulePath, L'\\' );
Assert( psz != NULL );
if ( psz == NULL )
{
hr = E_POINTER;
goto Cleanup;
}
THR( StringCchCatW( pszFilePathOut, *pcchFilePathInout, psz ) );
Cleanup:
return hr;
} //*** HrGetLogFilePath
//////////////////////////////////////////////////////////////////////////////
//++
//
// FormatTimeStamp
//
// Description:
// Format a string from the given time stamp.
//
// Arguments:
// pTimeStampIn
// The time stamp to format.
//
// pszTextOut
// A pointer to a buffer that receives the text. The caller must
// provide this buffer--the argument may not be null.
//
// cchTextIn
// The size of pszTextOut in characters.
//
// Return Values:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
static
inline
void
FormatTimeStamp(
const SYSTEMTIME * pTimeStampIn
, LPWSTR pszTextOut
, size_t cchTextIn
)
{
Assert( pTimeStampIn != NULL );
Assert( pszTextOut != NULL );
THR( StringCchPrintfW(
pszTextOut
, cchTextIn
, L"%04u-%02u-%02u %02u:%02u:%02u.%03u"
, pTimeStampIn->wYear
, pTimeStampIn->wMonth
, pTimeStampIn->wDay
, pTimeStampIn->wHour
, pTimeStampIn->wMinute
, pTimeStampIn->wSecond
, pTimeStampIn->wMilliseconds
) );
} //*** FormatTimeStamp
//////////////////////////////////////////////////////////////////////////////
//++
//
// WideCharToUTF8
//
// Description:
// Convert a wide character string to a UTF-8 encoded narrow string.
//
// Arguments:
// pwszSourceIn - The string to convert.
// cchDestIn - The maximum number of characters the destination can hold.
// paszDestOut - The destination for the converted string.
//
// Return Values:
// The number of characters in the converted string.
//
//--
//////////////////////////////////////////////////////////////////////////////
static
inline
size_t
WideCharToUTF8(
LPCWSTR pwszSourceIn
, size_t cchDestIn
, LPSTR paszDestOut
)
{
Assert( pwszSourceIn != NULL );
Assert( paszDestOut != NULL );
size_t cchUTF8 = 0;
cchUTF8 = WideCharToMultiByte(
CP_UTF8
, 0 // flags, must be zero for utf8
, pwszSourceIn
, -1 // calculate length automatically
, paszDestOut
, static_cast< int >( cchDestIn )
, NULL // default character, must be null for utf8
, NULL // default character used flag, must be null for utf8
);
return cchUTF8;
} //*** WideCharToUTF8
//////////////////////////////////////////////////////////////////////////////
//++
//
// HrInitializeLogLock
//
// Description:
// Create the spin lock that protects the log file from concurrent writes.
//
// Arguments:
// None.
//
// Return Values:
// S_OK
// E_OUTOFMEMORY
//
//--
//////////////////////////////////////////////////////////////////////////////
static
HRESULT
HrInitializeLogLock( void )
{
HRESULT hr = S_OK;
PCRITICAL_SECTION pNewCritSect =
(PCRITICAL_SECTION) HeapAlloc( GetProcessHeap(), 0, sizeof( CRITICAL_SECTION ) );
if ( pNewCritSect == NULL )
{
DebugMsg( "DEBUG: Out of Memory. Logging disabled." );
hr = E_OUTOFMEMORY;
goto Cleanup;
} // if: creation failed
if ( InitializeCriticalSectionAndSpinCount( pNewCritSect, 4000 ) == 0 ) // MSDN recommends 4000.
{
DWORD scError = GetLastError();
hr = HRESULT_FROM_WIN32( scError );
goto Cleanup;
}
// Make sure we only have one log critical section
InterlockedCompareExchangePointer( (PVOID *) &g_pcsLogging, pNewCritSect, 0 );
if ( g_pcsLogging != pNewCritSect )
{
DebugMsg( "DEBUG: Another thread already created the CS. Deleting this one." );
DeleteCriticalSection( pNewCritSect );
} // if: already have another critical section
else
{
pNewCritSect = NULL;
}
Cleanup:
if ( pNewCritSect != NULL )
{
HeapFree( GetProcessHeap(), 0, pNewCritSect );
}
return hr;
} //*** HrInitializeLogLock
//////////////////////////////////////////////////////////////////////////////
//++
//
// ScGetTokenInformation
//
// Description:
// Get the requested information from the passed in client token.
//
// Arguments:
// hClientTokenIn
// The client token to dump.
//
// ticRequestIn
//
// ppbOut
//
// Return Value:
// ERROR_SUCCESS for success.
//
// Other error codes.
//
//--
//////////////////////////////////////////////////////////////////////////////
static DWORD
ScGetTokenInformation(
HANDLE hClientTokenIn
, TOKEN_INFORMATION_CLASS ticRequestIn
, PBYTE * ppbOut
)
{
Assert( ppbOut != NULL );
PBYTE pb = NULL;
DWORD cb = 64;
DWORD sc = ERROR_SUCCESS;
int idx;
//
// Get the user information from the client token.
//
for ( idx = 0; idx < 10; idx++ )
{
pb = (PBYTE) TraceAlloc( 0, cb );
if ( pb == NULL )
{
sc = TW32( ERROR_OUTOFMEMORY );
goto Cleanup;
} // if:
if ( !GetTokenInformation( hClientTokenIn, ticRequestIn, pb, cb, &cb ) )
{
sc = GetLastError();
if ( sc == ERROR_INSUFFICIENT_BUFFER )
{
TraceFree( pb );
pb = NULL;
continue;
} // if:
TW32( sc );
goto Cleanup;
} // if:
else
{
*ppbOut = pb;
pb = NULL; // give away ownership
sc = ERROR_SUCCESS;
break;
} // else:
} // for:
//
// The loop should not exit because of idx == 10!
//
Assert( idx <= 9 );
Cleanup:
TraceFree( pb );
return sc;
} // *** ScGetTokenInformation
//////////////////////////////////////////////////////////////////////////////
//++
//
// ScGetDomainAndUserName
//
// Description:
// Get the domain user name for the logged on user.
//
// Arguments:
// pwszDomainAndUserNameOut
// This string should be at least DNS_MAX_NAME_BUFFER_LENGTH + 128 characters long.
//
// cchDomainAndUserNameIn
//
// Return Value:
// ERROR_SUCCESS for success.
//
// Other error codes.
//
//--
//////////////////////////////////////////////////////////////////////////////
static DWORD
ScGetDomainAndUserName(
LPWSTR pwszDomainAndUserNameOut
, size_t cchDomainAndUserNameIn
)
{
WCHAR * pwszUserName = pwszDomainAndUserNameOut + DNS_MAX_NAME_BUFFER_LENGTH;
WCHAR * pwszDomainName = pwszDomainAndUserNameOut;
DWORD cchUser = 128;
DWORD cchDomain = DNS_MAX_NAME_BUFFER_LENGTH;
HANDLE hClientToken = NULL;
DWORD sc = ERROR_SUCCESS;
TOKEN_USER * pTokenBuf = NULL;
WCHAR * pwszOperation;
SID_NAME_USE snuSidType;
if (cchDomainAndUserNameIn < cchUser + cchDomain)
{
pwszOperation = L"BufferTooSmall";
sc = TW32(ERROR_INSUFFICIENT_BUFFER);
goto Cleanup;
}
pwszOperation = L"OpenThreadToken";
if ( !OpenThreadToken( GetCurrentThread(), TOKEN_READ, FALSE, &hClientToken ) )
{
sc= GetLastError();
if ( sc == ERROR_NO_TOKEN )
{
pwszOperation = L"OpenProcessToken";
if ( !OpenProcessToken( GetCurrentProcess(), TOKEN_READ, &hClientToken ) )
{
sc = TW32( GetLastError() );
goto Cleanup;
} // if: OpenProcessToken failed
} // if: OpenThreadToken failed with ERROR_NO_TOKEN
else
{
TW32( sc );
goto Cleanup;
} // else:
} // if: OpenThreadToken failed
pwszOperation = L"GetTokenInformation";
sc = TW32( ScGetTokenInformation( hClientToken, TokenUser, (PBYTE *) &pTokenBuf ) );
if ( sc != ERROR_SUCCESS )
{
goto Cleanup;
} // if: failed to get token information
pwszOperation = L"LookupAccoundSid";
if ( !LookupAccountSidW( NULL, pTokenBuf->User.Sid, pwszUserName, &cchUser, pwszDomainName, &cchDomain, &snuSidType ) )
{
sc = TW32( GetLastError() );
goto Cleanup;
} // if: failed to lookup accound name
pwszDomainName[ cchDomain ] = L'\\';
MoveMemory( pwszDomainAndUserNameOut + cchDomain + 1, pwszUserName, ( cchUser + 1 ) * sizeof ( pwszUserName[0] ) );
Cleanup:
if ( hClientToken != NULL )
{
CloseHandle( hClientToken );
} // if: needed to close hClientToken
TraceFree( pTokenBuf );
if ( sc != ERROR_SUCCESS )
{
HRESULT hr;
hr = THR( StringCchPrintfW( pwszDomainAndUserNameOut, cchDomainAndUserNameIn, L"%ws failed with error %d", pwszOperation, sc ) );
if ( FAILED( hr ) )
{
; // the secondary error is not really interesting!
} // if:
} // else: report failure
return sc;
} //*** ScGetDomainAndUserName
//////////////////////////////////////////////////////////////////////////////
//++
//
// HrInitializeLogFile
//
// Description:
// Open the log file and prepare it for writing.
//
// Arguments:
// None.
//
// Return Values:
//
//--
//////////////////////////////////////////////////////////////////////////////
static
HRESULT
HrInitializeLogFile( void )
{
WCHAR szFilePath[ MAX_PATH ];
size_t cchPath = MAX_PATH - 1;
CHAR aszBuffer[ LOG_OUTPUT_BUFFER_SIZE ];
WCHAR wszBuffer[ LOG_OUTPUT_BUFFER_SIZE ];
WCHAR wszDomainAndUserName[ DNS_MAX_NAME_BUFFER_LENGTH + 128 ];
DWORD cbWritten = 0;
DWORD cbBytesToWrite = 0;
BOOL fReturn;
HRESULT hr = S_OK;
DWORD sc = ERROR_SUCCESS;
size_t cch;
SYSTEMTIME SystemTime;
hr = HrGetLogFilePath( L"%windir%\\system32\\LogFiles\\Cluster", szFilePath, &cchPath, g_hInstance );
if ( FAILED( hr ) )
{
goto Error;
}
//
// Create it
//
g_hLogFile = CreateFile(
szFilePath
, GENERIC_WRITE
, FILE_SHARE_READ | FILE_SHARE_WRITE
, NULL
, OPEN_ALWAYS
, FILE_FLAG_WRITE_THROUGH
, NULL
);
if ( g_hLogFile == INVALID_HANDLE_VALUE )
{
#if defined( DEBUG )
if ( !( g_tfModule & mtfOUTPUTTODISK ) )
{
DebugMsg( "*ERROR* Failed to create log at %s", szFilePath );
} // if: not logging to disk
#endif
sc = GetLastError();
hr = HRESULT_FROM_WIN32( sc );
//
// If we can not create the log file, try creating it under the alternate %TEMP% directory.
//
if ( ( sc == ERROR_ACCESS_DENIED ) || ( sc == ERROR_FILE_NOT_FOUND ) )
{
cch = ARRAYSIZE( szFilePath );
hr = HrGetLogFilePath( TEXT("%TEMP%"), szFilePath, &cch, g_hInstance );
if ( FAILED( hr ) )
{
goto Error;
}
//
// Create it
//
g_hLogFile = CreateFile(
szFilePath
, GENERIC_WRITE
, FILE_SHARE_READ | FILE_SHARE_WRITE
, NULL
, OPEN_ALWAYS
, FILE_FLAG_WRITE_THROUGH
, NULL
);
if ( g_hLogFile == INVALID_HANDLE_VALUE )
{
#if defined( DEBUG )
if ( !( g_tfModule & mtfOUTPUTTODISK ) )
{
DebugMsg( "*ERROR* Failed to create log at %s", szFilePath );
} // if: not logging to disk
#endif
hr = HRESULT_FROM_WIN32( GetLastError() );
goto Error;
} // if: ( g_hLogFile == INVALID_HANDLE_VALUE )
} // if: ( ( sc == ERROR_ACCESS_DENIED ) || ( sc == ERROR_FILE_NOT_FOUND ) )
else
{
goto Error;
} // else:
} // if: ( g_hLogFile == INVALID_HANDLE_VALUE )
//
// Copy which log file path we are using to g_szLogFilePath.
//
THR( StringCchCopyW( g_szLogFilePath, ARRAYSIZE( g_szLogFilePath ), szFilePath ) );
// If the file is empty, begin with UTF-8 byte-order mark.
{
LARGE_INTEGER liFileSize = { 0, 0 };
#if defined( DEBUG_SUPPORT_NT4 )
liFileSize.LowPart = GetFileSize( g_hLogFile, (LPDWORD) &liFileSize.HighPart );
if ( liFileSize.LowPart == INVALID_FILE_SIZE )
#else
fReturn = GetFileSizeEx( g_hLogFile, &liFileSize );
if ( fReturn == FALSE )
#endif
{
DWORD scError = GetLastError();
hr = HRESULT_FROM_WIN32( scError );
goto Error;
} // if: GetFileSizeEx failed
if ( liFileSize.QuadPart == 0 )
{
const char * aszUTF8ByteOrderMark = "\x0EF\x0BB\x0BF";
const size_t cchByteOrderMark = 3;
cbBytesToWrite = cchByteOrderMark * sizeof( aszUTF8ByteOrderMark[ 0 ] );
fReturn = WriteFile( g_hLogFile, aszUTF8ByteOrderMark, cbBytesToWrite, &cbWritten, NULL );
if ( fReturn == FALSE )
{
DWORD scError = GetLastError();
hr = HRESULT_FROM_WIN32( scError );
goto Error;
} // if: WriteFile failed
Assert( cbWritten == cbBytesToWrite );
} // if starting log file
else
{
// Seek to the end
SetFilePointer( g_hLogFile, 0, NULL, FILE_END );
}
} // put utf-8 mark at beginning of file
//
// When an error occurs a formatted error string is placed in wszDomainAndUserName.
//
TW32( ScGetDomainAndUserName( wszDomainAndUserName, RTL_NUMBER_OF( wszDomainAndUserName ) ) );
//
// Write the time/date the log was (re)openned.
//
GetLocalTime( &SystemTime );
THR( StringCchPrintfW(
wszBuffer
, ARRAYSIZE( wszBuffer )
, L"*\r\n* %04u-%02u-%02u %02u:%02u:%02u.%03u (%ws)\r\n*\r\n"
, SystemTime.wYear
, SystemTime.wMonth
, SystemTime.wDay
, SystemTime.wHour
, SystemTime.wMinute
, SystemTime.wSecond
, SystemTime.wMilliseconds
, wszDomainAndUserName
) );
WideCharToUTF8( wszBuffer, ARRAYSIZE( aszBuffer), aszBuffer );
cbBytesToWrite = static_cast< DWORD >( strlen( aszBuffer ) * sizeof( aszBuffer[ 0 ] ) );
fReturn = WriteFile( g_hLogFile, aszBuffer, cbBytesToWrite, &cbWritten, NULL );
if ( ! fReturn )
{
hr = HRESULT_FROM_WIN32( GetLastError() );
goto Error;
} // if: failed
Assert( cbWritten == cbBytesToWrite );
DebugMsg( "DEBUG: Created log at %s", szFilePath );
Cleanup:
return hr;
Error:
DebugMsg( "HrInitializeLogFile: Failed hr = 0x%08x", hr );
if ( g_hLogFile != INVALID_HANDLE_VALUE )
{
CloseHandle( g_hLogFile );
g_hLogFile = INVALID_HANDLE_VALUE;
} // if: handle was open
goto Cleanup;
} //*** HrInitializeLogFile
//////////////////////////////////////////////////////////////////////////////
//++
//
// HrLogOpen
//
// Description:
// This function:
// - initializes the log critical section
// - enters the log critical section assuring only one thread is
// writing to the log at a time
// - creates the directory tree to the log file (if needed)
// - initializes the log file by:
// - creating a new log file if one doesn't exist.
// - opens an existing log file (for append)
// - appends a time/date stamp that the log was (re)opened.
//
// Use LogClose() to exit the log critical section.
//
// If there is a failure inside this function, the log critical
// section will be released before returning.
//
// Arguments:
// None.
//
// Return Values:
// S_OK - log critical section held and log open successfully
// Otherwize HRESULT error code.
//
//--
//////////////////////////////////////////////////////////////////////////////
inline
HRESULT
HrLogOpen( void )
{
HRESULT hr = S_OK;
// If lock has not been initialized, initialize it.
if ( g_pcsLogging == NULL )
{
hr = HrInitializeLogLock();
if ( FAILED( hr ) )
{
goto Cleanup;
}
}
// Grab lock.
Assert( g_pcsLogging != NULL );
EnterCriticalSection( g_pcsLogging );
// If file has not been initialized, initialize it.
if ( g_hLogFile == INVALID_HANDLE_VALUE )
{
hr = HrInitializeLogFile();
}
Cleanup:
return hr;
} //*** HrLogOpen
//////////////////////////////////////////////////////////////////////////////
//++
//
// HrLogRelease
//
// Description:
// This actually just leaves the log critical section.
//
// Arguments:
// None.
//
// Return Values:
// S_OK always.
//
//--
//////////////////////////////////////////////////////////////////////////////
inline
HRESULT
HrLogRelease( void )
{
if ( g_pcsLogging != NULL )
{
LeaveCriticalSection( g_pcsLogging );
}
return S_OK;
} //*** HrLogRelease
//////////////////////////////////////////////////////////////////////////////
//++
//
// LogFormattedText
//
// Description:
// Convert a wide string to UTF-8 and write it to the log file.
//
// Arguments:
// fTimeStampIn
// fNewlineIn
// nLogEntryTypeIn
// pwszTextIn
//
// Return Values:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
static
void
LogFormattedText(
BOOL fTimeStampIn
, BOOL fNewlineIn
, DWORD nLogEntryTypeIn
, LPCWSTR pwszTextIn
)
{
char aszTimeStamp[ TIMESTAMP_BUFFER_SIZE ];
char aszLogText[ LOG_OUTPUT_BUFFER_SIZE ];
char * paszLogEntryType;
size_t cchTimeStamp = 0;
size_t cchLogText = 0;
DWORD cbWritten;
DWORD cbToWrite;
HRESULT hr = S_OK;
BOOL fSuccess;
Assert( pwszTextIn != NULL );
// Format time stamp (and convert to UTF-8) if requested.
if ( fTimeStampIn )
{
WCHAR szCurrentTime[ TIMESTAMP_BUFFER_SIZE ];
SYSTEMTIME stCurrentTime;
GetLocalTime( &stCurrentTime );
FormatTimeStamp( &stCurrentTime, szCurrentTime, ARRAYSIZE( szCurrentTime ) );
cchTimeStamp = WideCharToUTF8( szCurrentTime, ARRAYSIZE( aszTimeStamp ), aszTimeStamp );
} // if: time stamp requested
// Convert formatted text to UTF-8.
cchLogText = WideCharToUTF8( pwszTextIn, ARRAYSIZE( aszLogText ), aszLogText );
// Grab file.
hr = THR( HrLogOpen() );
if ( FAILED( hr ) )
{
goto Cleanup;
}
// Write time stamp to log if requested.
if ( fTimeStampIn )
{
cbToWrite = static_cast< DWORD >( cchTimeStamp * sizeof( aszTimeStamp[ 0 ] ) );
fSuccess = WriteFile( g_hLogFile, aszTimeStamp, cbToWrite, &cbWritten, NULL );
if ( fSuccess == FALSE )
{
TW32( GetLastError() );
}
else
{
Assert( cbWritten == cbToWrite );
}
} // if: timestamp requested
// Write the log entry type.
if ( nLogEntryTypeIn != LOGTYPE_NONE )
{
if ( nLogEntryTypeIn == LOGTYPE_DEBUG )
{
paszLogEntryType = "[DBG ] ";
}
else if ( ( nLogEntryTypeIn == LOGTYPE_INFO ) || ( nLogEntryTypeIn == S_OK ) )
{
paszLogEntryType = "[INFO] ";
}
else if ( ( nLogEntryTypeIn == LOGTYPE_WARNING ) )
{
paszLogEntryType = "[WARN] ";
}
else if ( ( nLogEntryTypeIn == LOGTYPE_ERROR ) || FAILED( nLogEntryTypeIn ) )
{
paszLogEntryType = "[ERR ] ";
}
else
{
// Can't do the other warning test here because LOGTYPE_WARNING would
// cause the FAILED() macro to return TRUE, and therefore the code
// would be treated as an error type.
paszLogEntryType = "[WARN] ";
}
cbToWrite = static_cast< DWORD >( strlen( paszLogEntryType ) );
fSuccess = WriteFile( g_hLogFile, paszLogEntryType, cbToWrite, &cbWritten, NULL );
if ( fSuccess == FALSE )
{
TW32( GetLastError() );
}
else
{
Assert( cbWritten == cbToWrite );
}
} // if: log entry type requested
// Write UTF-8 to log.
cbToWrite = static_cast< DWORD >( cchLogText );
fSuccess = WriteFile( g_hLogFile, aszLogText, cbToWrite, &cbWritten, NULL );
if ( fSuccess == FALSE )
{
TW32( GetLastError() );
}
else
{
Assert( cbWritten == cbToWrite );
}
// Write newline to log if requested.
if ( fNewlineIn )
{
cbToWrite = SIZEOF_ASZ_NEWLINE;
fSuccess = WriteFile( g_hLogFile, ASZ_NEWLINE, cbToWrite, &cbWritten, NULL );
if ( fSuccess == FALSE )
{
TW32( GetLastError() );
}
else
{
Assert( cbWritten == cbToWrite );
}
}
Cleanup:
// Release file.
hr = THR( HrLogRelease() );
return;
} //*** LogFormattedText
//////////////////////////////////////////////////////////////////////////////
//++
//
// LogUnformattedText
//
// Description:
// Format a string and pass it on to LogFormattedText.
//
// Arguments:
// fTimeStampIn
// fNewlineIn
// nLogEntryTypeIn
// pwszFormatIn
// pvlFormatArgsIn
//
// Return Values:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
static
inline
void
LogUnformattedText(
BOOL fTimeStampIn
, BOOL fNewlineIn
, DWORD nLogEntryTypeIn
, LPCWSTR pwszFormatIn
, va_list * pvlFormatArgsIn
)
{
WCHAR wszFormatted[ LOG_OUTPUT_BUFFER_SIZE ];
Assert( pwszFormatIn != NULL );
Assert( pvlFormatArgsIn != NULL );
// Format string.
THR( StringCchVPrintfW( wszFormatted, ARRAYSIZE( wszFormatted ), pwszFormatIn, *pvlFormatArgsIn ) );
// Pass formatted string through to LogFormattedText.
LogFormattedText( fTimeStampIn, fNewlineIn, nLogEntryTypeIn, wszFormatted );
} //*** LogUnformattedText
//////////////////////////////////////////////////////////////////////////////
//++
//
// HrLogClose
//
// Description:
// Close the file. This function expects the critical section to have
// already been released.
//
// Arguments:
// None.
//
// Return Values:
// S_OK always.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrLogClose( void )
{
TraceFunc( "" );
HRESULT hr = S_OK;
if ( g_pcsLogging != NULL )
{
DeleteCriticalSection( g_pcsLogging );
HeapFree( GetProcessHeap(), 0, g_pcsLogging );
g_pcsLogging = NULL;
} // if:
if ( g_hLogFile != INVALID_HANDLE_VALUE )
{
CloseHandle( g_hLogFile );
g_hLogFile = INVALID_HANDLE_VALUE;
} // if: handle was open
HRETURN( hr );
} //*** HrLogClose
//////////////////////////////////////////////////////////////////////////////
//++
//
// ASCII
//
// LogMsgNoNewline
//
// Description:
// Logs a message to the log file without adding a newline.
//
// Arguments:
// paszFormatIn - A printf format string to be printed.
// ,,, - Arguments for the printf string.
//
// Return Values:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
void
__cdecl
LogMsgNoNewline(
LPCSTR paszFormatIn,
...
)
{
va_list valist;
WCHAR wszFormat[ LOG_OUTPUT_BUFFER_SIZE ];
Assert( paszFormatIn != NULL );
size_t cchWideFormat = MultiByteToWideChar(
CP_ACP
, MB_PRECOMPOSED
, paszFormatIn
, -1
, wszFormat
, ARRAYSIZE( wszFormat )
);
if ( cchWideFormat > 0 )
{
va_start( valist, paszFormatIn );
LogUnformattedText( FALSE, FALSE, LOGTYPE_NONE, wszFormat, &valist );
va_end( valist );
}
} //*** LogMsgNoNewline ASCII
//////////////////////////////////////////////////////////////////////////////
//++
//
// ASCII
//
// LogMsgNoNewline
//
// Description:
// Logs a message to the log file without adding a newline.
//
// Arguments:
// nLogEntryTypeIn - Log entry type.
// paszFormatIn - A printf format string to be printed.
// ,,, - Arguments for the printf string.
//
// Return Values:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
void
__cdecl
LogMsgNoNewline(
DWORD nLogEntryTypeIn
, LPCSTR paszFormatIn
, ...
)
{
va_list valist;
WCHAR wszFormat[ LOG_OUTPUT_BUFFER_SIZE ];
Assert( paszFormatIn != NULL );
size_t cchWideFormat = MultiByteToWideChar(
CP_ACP
, MB_PRECOMPOSED
, paszFormatIn
, -1
, wszFormat
, ARRAYSIZE( wszFormat )
);
if ( cchWideFormat > 0 )
{
va_start( valist, paszFormatIn );
LogUnformattedText( FALSE, FALSE, nLogEntryTypeIn, wszFormat, &valist );
va_end( valist );
}
} //*** LogMsgNoNewline ASCII
//////////////////////////////////////////////////////////////////////////////
//++
//
// UNICODE
//
// LogMsgNoNewline
//
// Description:
// Logs a message to the log file without adding a newline.
//
// Arguments:
// pszFormatIn - A printf format string to be printed.
// ,,, - Arguments for the printf string.
//
// Return Values:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
void
__cdecl
LogMsgNoNewline(
LPCWSTR pszFormatIn,
...
)
{
va_list valist;
Assert( pszFormatIn != NULL );
va_start( valist, pszFormatIn );
LogUnformattedText( FALSE, FALSE, LOGTYPE_NONE, pszFormatIn, &valist );
va_end( valist );
} //*** LogMsgNoNewline UNICODE
//////////////////////////////////////////////////////////////////////////////
//++
//
// UNICODE
//
// LogMsgNoNewline
//
// Description:
// Logs a message to the log file without adding a newline.
//
// Arguments:
// nLogEntryTypeIn - Log entry type.
// pszFormatIn - A printf format string to be printed.
// ,,, - Arguments for the printf string.
//
// Return Values:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
void
__cdecl
LogMsgNoNewline(
DWORD nLogEntryTypeIn
, LPCWSTR pszFormatIn
, ...
)
{
va_list valist;
Assert( pszFormatIn != NULL );
va_start( valist, pszFormatIn );
LogUnformattedText( FALSE, FALSE, nLogEntryTypeIn, pszFormatIn, &valist );
va_end( valist );
} //*** LogMsgNoNewline UNICODE
//////////////////////////////////////////////////////////////////////////////
//++
//
// ASCII
//
// LogMsg
//
// Description:
// Logs a message to the log file and adds a newline.
//
// Arguments:
// paszFormatIn - A printf format string to be printed.
// ,,, - Arguments for the printf string.
//
// Return Values:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
void
__cdecl
LogMsg(
LPCSTR paszFormatIn,
...
)
{
va_list valist;
WCHAR wszFormat[ LOG_OUTPUT_BUFFER_SIZE ];
size_t cchWideFormat = 0;
Assert( paszFormatIn != NULL );
cchWideFormat = MultiByteToWideChar(
CP_ACP
, MB_PRECOMPOSED
, paszFormatIn
, -1
, wszFormat
, ARRAYSIZE( wszFormat )
);
if ( cchWideFormat > 0 )
{
va_start( valist, paszFormatIn );
LogUnformattedText( TRUE, TRUE, LOGTYPE_INFO, wszFormat, &valist );
va_end( valist );
}
} //*** LogMsg ASCII
//////////////////////////////////////////////////////////////////////////////
//++
//
// ASCII
//
// LogMsg
//
// Description:
// Logs a message to the log file and adds a newline.
//
// Arguments:
// nLogEntryTypeIn - Log entry type.
// paszFormatIn - A printf format string to be printed.
// ,,, - Arguments for the printf string.
//
// Return Values:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
void
__cdecl
LogMsg(
DWORD nLogEntryTypeIn
, LPCSTR paszFormatIn
, ...
)
{
va_list valist;
WCHAR wszFormat[ LOG_OUTPUT_BUFFER_SIZE ];
size_t cchWideFormat = 0;
Assert( paszFormatIn != NULL );
cchWideFormat = MultiByteToWideChar(
CP_ACP
, MB_PRECOMPOSED
, paszFormatIn
, -1
, wszFormat
, ARRAYSIZE( wszFormat )
);
if ( cchWideFormat > 0 )
{
va_start( valist, paszFormatIn );
LogUnformattedText( TRUE, TRUE, nLogEntryTypeIn, wszFormat, &valist );
va_end( valist );
}
} //*** LogMsg ASCII
//////////////////////////////////////////////////////////////////////////////
//++
//
// UNICODE
//
// LogMsg
//
// Description:
// Logs a message to the log file and adds a newline.
//
// Arguments:
// pszFormatIn - A printf format string to be printed.
// ,,, - Arguments for the printf string.
//
// Return Values:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
void
__cdecl
LogMsg(
LPCWSTR pszFormatIn
, ...
)
{
va_list valist;
Assert( pszFormatIn != NULL );
va_start( valist, pszFormatIn );
LogUnformattedText( TRUE, TRUE, LOGTYPE_INFO, pszFormatIn, &valist );
va_end( valist );
} //*** LogMsg UNICODE
//////////////////////////////////////////////////////////////////////////////
//++
//
// UNICODE
//
// LogMsg
//
// Description:
// Logs a message to the log file and adds a newline.
//
// Arguments:
// nLogEntryTypeIn - Log entry type.
// pszFormatIn - A printf format string to be printed.
// ,,, - Arguments for the printf string.
//
// Return Values:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
void
__cdecl
LogMsg(
DWORD nLogENtryTypeIn
, LPCWSTR pszFormatIn
, ...
)
{
va_list valist;
Assert( pszFormatIn != NULL );
va_start( valist, pszFormatIn );
LogUnformattedText( TRUE, TRUE, nLogENtryTypeIn, pszFormatIn, &valist );
va_end( valist );
} //*** LogMsg UNICODE
//////////////////////////////////////////////////////////////////////////////
//++
//
// LogStatusReport
//
// Description:
// Writes a status report to the log file.
//
// Arugments:
// pstTimeIn -
// pcszNodeNameIn -
// clsidTaskMajorIn -
// clsidTaskMinorIn -
// ulMinIn -
// ulMaxIn -
// ulCurrentIn -
// hrStatusIn -
// pcszDescriptionIn -
// pcszUrlIn -
//
// Return Values:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
void
LogStatusReport(
SYSTEMTIME * pstTimeIn,
const WCHAR * pcszNodeNameIn,
CLSID clsidTaskMajorIn,
CLSID clsidTaskMinorIn,
ULONG ulMinIn,
ULONG ulMaxIn,
ULONG ulCurrentIn,
HRESULT hrStatusIn,
const WCHAR * pcszDescriptionIn,
const WCHAR * pcszUrlIn
)
{
SYSTEMTIME stCurrent;
SYSTEMTIME stReport;
WCHAR szCurrent[ TIMESTAMP_BUFFER_SIZE ];
WCHAR szReport[ TIMESTAMP_BUFFER_SIZE ];
const size_t cchGuid = 40;
WCHAR wszMajorGuid[ cchGuid ];
WCHAR wszMinorGuid[ cchGuid ];
WCHAR wszFormattedReport[ LOG_OUTPUT_BUFFER_SIZE ];
GetLocalTime( &stCurrent );
if ( pstTimeIn )
{
memcpy( &stReport, pstTimeIn, sizeof( stReport ) );
}
else
{
memset( &stReport, 0, sizeof( stReport) );
}
FormatTimeStamp( &stCurrent, szCurrent, ARRAYSIZE( szCurrent ) );
FormatTimeStamp( &stReport, szReport, ARRAYSIZE( szReport ) );
StringFromGUID2( clsidTaskMajorIn, wszMajorGuid, cchGuid );
StringFromGUID2( clsidTaskMinorIn, wszMinorGuid, cchGuid );
THR( StringCchPrintfW(
wszFormattedReport
, ARRAYSIZE( wszFormattedReport )
, L"%ws - %ws %ws, %ws (%2d / %2d .. %2d ) <%ws> hr=%08X %ws %ws"
, szCurrent
, szReport
, wszMajorGuid
, wszMinorGuid
, ulCurrentIn
, ulMinIn
, ulMaxIn
, pcszNodeNameIn
, hrStatusIn
, pcszDescriptionIn
, pcszUrlIn
) );
LogFormattedText( FALSE, TRUE, hrStatusIn, wszFormattedReport );
} //*** LogStatusReport