////////////////////////////////////////////////////////////////////////////// // // 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 // should be included by includer of this file #include #include // in case it isn't included by header file #include #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