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
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
|