|
|
// WMDMLogger.cpp : Implementation of CWMDMLogger
//
#include "stdafx.h"
#include "wmdmlog.h"
#include "WMDMLogger.h"
#define STRSAFE_NO_DEPRECATE
#include <strsafe.h>
#define REGKEY_WMDM_ROOT "Software\\Microsoft\\Windows Media Device Manager"
#define REGVAL_LOGENABLED "Log.Enabled"
#define REGVAL_LOGFILE "Log.Filename"
#define REGVAL_MAXSIZE "Log.MaxSize"
#define REGVAL_SHRINKTOSIZE "Log.ShrinkToSize"
#define MUTEX_REGISTRY "WMDMLogger.Registry.Mutex"
#define MUTEX_LOGFILE "WMDMLogger.LogFile.Mutex"
#define READ_BUF_SIZE 4*1024
#define CRLF "\r\n"
/////////////////////////////////////////////////////////////////////
//
// CWMDMLogger
//
/////////////////////////////////////////////////////////////////////
CWMDMLogger::CWMDMLogger() { HRESULT hr;
// Save instance handle for easy access
//
m_hInst = _Module.GetModuleInstance(); if( !m_hInst ) { ExitOnFail( hr = E_FAIL ); }
// Create the mutex'es for coordinating access to
// shared resources.
//
m_hMutexRegistry = CreateMutex( NULL, FALSE, MUTEX_REGISTRY ); if( !m_hMutexRegistry ) { ExitOnFail( hr = E_FAIL ); } m_hMutexLogFile = CreateMutex( NULL, FALSE, MUTEX_LOGFILE ); if( !m_hMutexLogFile ) { ExitOnFail( hr = E_FAIL ); }
// Get the initial values from the registry. For values that
// don't exist in the registry, the defaults will be used
//
hr = hrLoadRegistryValues();
lExit:
// Save the return code from the constructor so it can be checked
// in public methods.
//
m_hrInit = hr; }
CWMDMLogger::~CWMDMLogger() { // Close the mutex handles
//
if( NULL != m_hMutexRegistry ) { CloseHandle( m_hMutexRegistry ); } if( NULL != m_hMutexLogFile ) { CloseHandle( m_hMutexLogFile ); } }
HRESULT CWMDMLogger::hrWaitForAccess( HANDLE hMutex ) { HRESULT hr; DWORD dwWaitRetVal; static DWORD dwTimeout = 0; static BOOL fHaveTimeout = FALSE;
if( !fHaveTimeout ) { hr = hrGetResourceDword( IDS_MUTEX_TIMEOUT, &dwTimeout ); ExitOnFail( hr );
fHaveTimeout = TRUE; }
if( 0 == dwTimeout ) { dwTimeout = INFINITE; }
dwWaitRetVal = WaitForSingleObject( hMutex, dwTimeout );
if( WAIT_FAILED == dwWaitRetVal ) { ExitOnFail( hr = E_FAIL ); } if( WAIT_TIMEOUT == dwWaitRetVal ) { ExitOnFail( hr = E_ABORT ); }
hr = S_OK;
lExit:
return hr; }
HRESULT CWMDMLogger::hrGetResourceDword( UINT uStrID, LPDWORD pdw ) { HRESULT hr; CHAR szDword[64];
// Check params
//
if( !pdw ) { hr = E_INVALIDARG; ExitOnFail( hr ); }
LoadString( m_hInst, uStrID, szDword, sizeof(szDword) );
*pdw = (DWORD) atol( szDword );
hr = S_OK;
lExit:
return hr; }
HRESULT CWMDMLogger::hrGetDefaultFileName( LPSTR szFilename, DWORD cchFilename ) { HRESULT hr; UINT uRet; CHAR szLogFile[MAX_PATH];
uRet = GetSystemDirectory( szFilename, cchFilename ); if( 0 == uRet ) { ExitOnFail( hr = E_FAIL ); }
LoadString( m_hInst, IDS_DEF_LOGFILE, szLogFile, sizeof(szLogFile) );
AddPath( szFilename, szLogFile );
hr = S_OK;
lExit:
return hr; }
HRESULT CWMDMLogger::hrLoadRegistryValues() { HRESULT hr = S_OK; BOOL fMutex = FALSE; HKEY hKey = NULL; LONG lRetVal; DWORD dwType; DWORD dwDataLen; DWORD dwEnabled;
// Coordinate access to the shared registry value
//
hr = hrWaitForAccess( m_hMutexRegistry ); ExitOnFail( hr );
fMutex = TRUE;
// Open the root WMDM registry key
//
lRetVal = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REGKEY_WMDM_ROOT, 0, KEY_QUERY_VALUE | KEY_SET_VALUE, &hKey ); if( ERROR_SUCCESS != lRetVal ) { ExitOnFail( hr = HRESULT_FROM_WIN32(lRetVal) ); }
// Get the enabled status of the logfile
//
dwDataLen = sizeof( dwEnabled );
lRetVal = RegQueryValueEx( hKey, REGVAL_LOGENABLED, NULL, &dwType, (LPBYTE)&dwEnabled, &dwDataLen ); if( ERROR_SUCCESS != lRetVal || dwType != REG_DWORD ) { // No existing value, use the default
//
hr = hrGetResourceDword( IDS_DEF_LOGENABLED, &dwEnabled ); ExitOnFail( hr ); }
m_fEnabled = ( dwEnabled != 0 );
// Check if the log filename value already exists
//
dwDataLen = sizeof( m_szFilename );
lRetVal = RegQueryValueEx( hKey, REGVAL_LOGFILE, NULL, &dwType, (LPBYTE)m_szFilename, &dwDataLen ); if( ERROR_SUCCESS != lRetVal || dwType != REG_SZ ) { CHAR szDefLogFile[MAX_PATH];
// No existing value, so form the default log filename
//
hr = hrGetDefaultFileName( szDefLogFile, sizeof(szDefLogFile) ); ExitOnFail( hr );
// Set the default log filename
//
hr = hrSetLogFileName( szDefLogFile ); ExitOnFail( hr ); }
// Get the maximum size for the logfile
//
dwDataLen = sizeof( m_dwMaxSize );
lRetVal = RegQueryValueEx( hKey, REGVAL_MAXSIZE, NULL, &dwType, (LPBYTE)&m_dwMaxSize, &dwDataLen ); if( ERROR_SUCCESS != lRetVal || dwType != REG_DWORD ) { // No existing value, use the default
//
hr = hrGetResourceDword( IDS_DEF_MAXSIZE, &m_dwMaxSize ); ExitOnFail( hr ); }
// Get the shrink-to size for the logfile
//
dwDataLen = sizeof( m_dwShrinkToSize );
lRetVal = RegQueryValueEx( hKey, REGVAL_SHRINKTOSIZE, NULL, &dwType, (LPBYTE)&m_dwShrinkToSize, &dwDataLen ); if( ERROR_SUCCESS != lRetVal || dwType != REG_DWORD ) { // No existing value, use the default
//
hr = hrGetResourceDword( IDS_DEF_SHRINKTOSIZE, &m_dwShrinkToSize ); ExitOnFail( hr ); }
// Set the file size params
//
hr = hrSetSizeParams( m_dwMaxSize, m_dwShrinkToSize ); ExitOnFail( hr );
hr = S_OK;
lExit:
if( hKey ) { RegCloseKey( hKey ); }
// Release the mutex
//
if( fMutex ) { ReleaseMutex( m_hMutexRegistry ); }
return hr; }
HRESULT CWMDMLogger::hrSetLogFileName( LPSTR pszFilename ) { HRESULT hr = S_OK; BOOL fMutex = FALSE; HKEY hKey = NULL; LONG lRetVal;
//
// Make sure that the new file name can be copied; if it fails we want to retain the old file
// name and fail the call.
//
if(lstrlen(pszFilename) >= MAX_PATH ) { return E_INVALIDARG; } // Coordinate access to the shared registry value
//
hr = hrWaitForAccess( m_hMutexRegistry ); ExitOnFail( hr );
fMutex = TRUE;
// Open the root WMDM registry key
//
lRetVal = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REGKEY_WMDM_ROOT, 0, KEY_SET_VALUE, &hKey ); if( ERROR_SUCCESS != lRetVal ) { ExitOnFail( hr = HRESULT_FROM_WIN32(lRetVal) ); }
// Set the LogFilename value
//
lRetVal = RegSetValueEx( hKey, REGVAL_LOGFILE, 0L, REG_SZ, (LPBYTE)pszFilename, lstrlen(pszFilename)+1 ); if( ERROR_SUCCESS != lRetVal ) { ExitOnFail( hr = HRESULT_FROM_WIN32(lRetVal) ); }
// Set the local member data to the new log filename
//
hr = StringCbCopy(m_szFilename, sizeof(m_szFilename), pszFilename); if(FAILED(hr)) { // we need to undo the registry setting.
goto lExit; }
lExit:
if( hKey ) { RegCloseKey( hKey ); }
// Release the mutex
//
if( fMutex ) { ReleaseMutex( m_hMutexRegistry ); }
return S_OK; }
HRESULT CWMDMLogger::hrCheckFileSize( void ) { HRESULT hr; BOOL fMutex = FALSE; HANDLE hFile = INVALID_HANDLE_VALUE; HANDLE hFileTemp = INVALID_HANDLE_VALUE; LPBYTE lpbData = NULL; DWORD dwSize; CHAR szTempPath[MAX_PATH]; CHAR szTempFile[MAX_PATH];
// Coordinate access to the shared logfile
//
hr = hrWaitForAccess( m_hMutexLogFile ); ExitOnFail( hr );
fMutex = TRUE;
// Open the logfile
//
hFile = CreateFile( m_szFilename, GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if( INVALID_HANDLE_VALUE == hFile ) { ExitOnFail( hr = E_ACCESSDENIED ); }
// Get the current size of the logfile
//
dwSize = GetFileSize( hFile, NULL ); // Check if file needs to be trimmed
//
if( dwSize > m_dwMaxSize ) { // Trim file to approximately m_dwShrinkToSize bytes
//
DWORD dwTrimBytes = dwSize - m_dwShrinkToSize; DWORD dwRead; DWORD dwWritten;
// Get the temp directory
//
if( 0 == GetTempPath(sizeof(szTempPath), szTempPath) ) { ExitOnFail( hr = E_FAIL ); }
// Create a temp filename
//
if( 0 == GetTempFileName(szTempPath, "WMDM", 0, szTempFile) ) { ExitOnFail( hr = E_FAIL ); }
// Open the temp file for writing
//
hFileTemp = CreateFile( szTempFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if( INVALID_HANDLE_VALUE == hFileTemp ) { ExitOnFail( hr = E_ACCESSDENIED ); }
// Set the read pointer of the existing logfile to the
// approximate trim position
///
SetFilePointer( hFile, dwTrimBytes, NULL, FILE_BEGIN );
// Allocate buffer for file reads
//
lpbData = (LPBYTE) CoTaskMemAlloc( READ_BUF_SIZE ); if( !lpbData ) { ExitOnFail( hr = E_OUTOFMEMORY ); }
// Read in the first chunk of the file, and search for the end of
// the current line (a CRLF). Write everything after that CRLF to
// the temp file. If thee is no CRLF, then write the entire packet
// to the temp file.
//
if( ReadFile(hFile, lpbData, READ_BUF_SIZE, &dwRead, NULL) && dwRead > 0 ) { LPBYTE lpb = lpbData;
while( ((DWORD_PTR)lpb-(DWORD_PTR)lpbData < dwRead-1) && (*lpb != '\r' && *(lpb+1) != '\n') ) { lpb++; } if( (DWORD_PTR)lpb-(DWORD_PTR)lpbData < dwRead-1 ) { // Must have found a CRLF... skip it
lpb += 2; } else { // No CRLF found... write entire packet to temp file
lpb = lpbData; } WriteFile( hFileTemp, lpb, (DWORD)(dwRead - ( (DWORD_PTR)lpb - (DWORD_PTR)lpbData )), &dwWritten, NULL ); }
// Read the rest of the logfile and write it to the temp file
//
while( ReadFile(hFile, lpbData, READ_BUF_SIZE, &dwRead, NULL) && dwRead > 0 ) { WriteFile( hFileTemp, lpbData, dwRead, &dwWritten, NULL ); }
// Close the open file handles
//
CloseHandle( hFile ); hFile = INVALID_HANDLE_VALUE;
CloseHandle( hFileTemp ); hFileTemp = INVALID_HANDLE_VALUE;
// Replace the current logfile with the temp file
//
DeleteFile( m_szFilename ); MoveFile( szTempFile, m_szFilename ); }
hr = S_OK;
lExit:
// Close any open file handles
//
if( INVALID_HANDLE_VALUE != hFile ) { CloseHandle( hFile ); } if( INVALID_HANDLE_VALUE != hFileTemp ) { CloseHandle( hFileTemp ); }
// Free any allocated memory
//
if( lpbData ) { CoTaskMemFree( lpbData ); }
// Release the mutex
//
if( fMutex ) { ReleaseMutex( m_hMutexLogFile ); }
return hr; }
HRESULT CWMDMLogger::hrSetSizeParams( DWORD dwMaxSize, DWORD dwShrinkToSize ) { HRESULT hr = S_OK; BOOL fMutex = FALSE; HKEY hKey = NULL; LONG lRetVal;
// Coordinate access to the shared registry value
//
hr = hrWaitForAccess( m_hMutexRegistry ); ExitOnFail( hr );
fMutex = TRUE;
// Open the root WMDM registry key
//
lRetVal = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REGKEY_WMDM_ROOT, 0, KEY_SET_VALUE, &hKey ); if( ERROR_SUCCESS != lRetVal ) { ExitOnFail( hr = HRESULT_FROM_WIN32(lRetVal) ); }
// Set the MaxSize value
//
lRetVal = RegSetValueEx( hKey, REGVAL_MAXSIZE, 0L, REG_DWORD, (LPBYTE)&dwMaxSize, sizeof(dwMaxSize) ); if( ERROR_SUCCESS != lRetVal ) { ExitOnFail( hr = HRESULT_FROM_WIN32(lRetVal) ); }
// Set the ShrinkToSize value
//
lRetVal = RegSetValueEx( hKey, REGVAL_SHRINKTOSIZE, 0L, REG_DWORD, (LPBYTE)&dwShrinkToSize, sizeof(dwShrinkToSize) ); if( ERROR_SUCCESS != lRetVal ) { ExitOnFail( hr = HRESULT_FROM_WIN32(lRetVal) ); }
// Set the local member data
//
m_dwMaxSize = dwMaxSize; m_dwShrinkToSize = dwShrinkToSize;
hr = S_OK;
lExit:
if( hKey ) { RegCloseKey( hKey ); }
// Release the mutex
//
if( fMutex ) { ReleaseMutex( m_hMutexRegistry ); }
return S_OK; }
HRESULT CWMDMLogger::hrEnable( BOOL fEnable ) { HRESULT hr = S_OK; BOOL fMutex = FALSE; HKEY hKey = NULL; DWORD dwEnable = ( fEnable ? 1L : 0L ); LONG lRetVal;
// Coordinate access to the shared registry value
//
hr = hrWaitForAccess( m_hMutexRegistry ); ExitOnFail( hr );
fMutex = TRUE;
// Open the root WMDM registry key
//
lRetVal = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REGKEY_WMDM_ROOT, 0, KEY_SET_VALUE, &hKey ); if( ERROR_SUCCESS != lRetVal ) { ExitOnFail( hr = HRESULT_FROM_WIN32(lRetVal) ); }
// Set the Enabled value
//
lRetVal = RegSetValueEx( hKey, REGVAL_LOGENABLED, 0L, REG_DWORD, (LPBYTE)&dwEnable, sizeof(dwEnable) ); if( ERROR_SUCCESS != lRetVal ) { ExitOnFail( hr = HRESULT_FROM_WIN32(lRetVal) ); }
// Set the local member data
//
m_fEnabled = fEnable;
hr = S_OK;
lExit:
if( hKey ) { RegCloseKey( hKey ); }
// Release the mutex
//
if( fMutex ) { ReleaseMutex( m_hMutexRegistry ); }
return S_OK; }
/////////////////////////////////////////////////////////////////////
//
// IWMDMLogger Methods
//
/////////////////////////////////////////////////////////////////////
HRESULT CWMDMLogger::GetLogFileName( LPSTR pszFilename, UINT nMaxChars ) { HRESULT hr;
// Check init error status
//
ExitOnFail( hr = m_hrInit );
// Check for invalid arguments
//
if( !pszFilename ) { ExitOnFail( hr = E_INVALIDARG ); }
// Make sure the log filename will fit in the output buffer
//
if( (UINT)lstrlen(m_szFilename)+1 > nMaxChars ) { //BUGBUG: better return code
ExitOnFail( hr = E_FAIL ); }
// Copy the log filename to output buffer
//
lstrcpy( pszFilename, m_szFilename );
hr = S_OK;
lExit:
return hr; }
HRESULT CWMDMLogger::SetLogFileName( LPSTR pszFilename ) { HRESULT hr;
// Check init error status
//
ExitOnFail( hr = m_hrInit );
// Check for invalid arguments
//
if( !pszFilename ) { ExitOnFail( hr = E_INVALIDARG ); }
hr = hrSetLogFileName( pszFilename );
lExit:
return hr; }
HRESULT CWMDMLogger::GetSizeParams( LPDWORD pdwMaxSize, LPDWORD pdwShrinkToSize ) { HRESULT hr;
// Check init error status
//
ExitOnFail( hr = m_hrInit );
if( pdwMaxSize ) { *pdwMaxSize = m_dwMaxSize; } if( pdwShrinkToSize ) { *pdwShrinkToSize = m_dwShrinkToSize; }
hr = S_OK;
lExit:
return hr; }
HRESULT CWMDMLogger::SetSizeParams( DWORD dwMaxSize, DWORD dwShrinkToSize ) { HRESULT hr;
// Check init error status
//
ExitOnFail( hr = m_hrInit );
// Check params
//
if( dwShrinkToSize >= dwMaxSize ) { ExitOnFail( hr = E_INVALIDARG ); }
hr = hrSetSizeParams( dwMaxSize, dwShrinkToSize );
lExit:
return hr; }
HRESULT CWMDMLogger::IsEnabled( BOOL *pfEnabled ) { HRESULT hr;
// Check init error status
//
ExitOnFail( hr = m_hrInit );
if( pfEnabled ) { *pfEnabled = m_fEnabled; }
hr = S_OK;
lExit:
return hr; }
HRESULT CWMDMLogger::Enable( BOOL fEnable ) { HRESULT hr;
// Check init error status
//
ExitOnFail( hr = m_hrInit );
hr = hrEnable( fEnable );
lExit:
return hr; }
HRESULT CWMDMLogger::LogString( DWORD dwFlags, LPSTR pszSrcName, LPSTR pszLog ) { HRESULT hr; BOOL fMutex = FALSE; HANDLE hFile = INVALID_HANDLE_VALUE; DWORD dwWritten; CHAR szPreLog[MAX_PATH];
// Check init error status
//
ExitOnFail( hr = m_hrInit );
// Coordinate access to the shared logfile
//
hr = hrWaitForAccess( m_hMutexLogFile ); ExitOnFail( hr );
fMutex = TRUE;
// Check the file size params and adjust the file appropriately
//
hr = hrCheckFileSize(); ExitOnFail( hr );
// Open the logfile
//
hFile = CreateFile( m_szFilename, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if( INVALID_HANDLE_VALUE == hFile ) { ExitOnFail( hr = E_ACCESSDENIED ); }
// Seek to the end of the logfile
//
SetFilePointer( hFile, 0, NULL, FILE_END );
// Put timestamp on log entry unless the flags say not to
//
if( !(dwFlags & WMDM_LOG_NOTIMESTAMP) ) { CHAR szFormat[MAX_PATH]; SYSTEMTIME sysTime;
GetLocalTime( &sysTime );
LoadString( m_hInst, IDS_LOG_DATETIME, szFormat, sizeof(szFormat) );
wsprintf( szPreLog, szFormat, sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour, sysTime.wMinute, sysTime.wSecond );
WriteFile( hFile, szPreLog, lstrlen(szPreLog), &dwWritten, NULL ); }
// Log the component name
//
if( pszSrcName ) { CHAR szFormat[MAX_PATH];
LoadString( m_hInst, IDS_LOG_SRCNAME, szFormat, sizeof(szFormat) ); wsprintf( szPreLog, szFormat, pszSrcName );
WriteFile( hFile, szPreLog, lstrlen(szPreLog), &dwWritten, NULL ); }
// Log the severity
//
if( dwFlags & WMDM_LOG_SEV_ERROR ) { LoadString( m_hInst, IDS_LOG_SEV_ERROR, szPreLog, sizeof(szPreLog) ); } else if( dwFlags & WMDM_LOG_SEV_WARN ) { LoadString( m_hInst, IDS_LOG_SEV_WARN, szPreLog, sizeof(szPreLog) ); } else if( dwFlags & WMDM_LOG_SEV_INFO ) { LoadString( m_hInst, IDS_LOG_SEV_INFO, szPreLog, sizeof(szPreLog) ); } else { *szPreLog = '\0'; }
WriteFile( hFile, szPreLog, lstrlen(szPreLog), &dwWritten, NULL );
// Write the logstring to the logfile followed by a CRLF
//
if( pszLog ) { WriteFile( hFile, pszLog, lstrlen(pszLog), &dwWritten, NULL ); }
// End with a carriage return and line feed
//
WriteFile( hFile, CRLF, lstrlen(CRLF), &dwWritten, NULL );
hr = S_OK;
lExit:
if( INVALID_HANDLE_VALUE != hFile ) { CloseHandle( hFile ); }
// Release the mutex
//
if( fMutex ) { ReleaseMutex( m_hMutexLogFile ); }
return hr; }
HRESULT CWMDMLogger::LogDword( DWORD dwFlags, LPSTR pszSrcName, LPSTR pszLogFormat, DWORD dwLog ) { HRESULT hr; LPSTR pszLog = NULL;
// Check init error status
//
ExitOnFail( hr = m_hrInit );
// Check params
//
if( !pszLogFormat ) { ExitOnFail( hr = E_INVALIDARG ); }
// Allocate space for the final log text
//
pszLog = (LPSTR) CoTaskMemAlloc( MAX_WSPRINTF_BUF ); if( !pszLog ) { ExitOnFail( hr = E_OUTOFMEMORY ); }
// Create log string
//
wsprintf( pszLog, pszLogFormat, dwLog );
// Log the string
//
hr = LogString( dwFlags, pszSrcName, pszLog );
lExit:
if( pszLog ) { CoTaskMemFree( pszLog ); }
return hr; }
HRESULT CWMDMLogger::Reset( void ) { HRESULT hr; BOOL fMutex = FALSE; HANDLE hFile = INVALID_HANDLE_VALUE;
// Check init error status
//
ExitOnFail( hr = m_hrInit );
// Coordinate access to the shared logfile
//
hr = hrWaitForAccess( m_hMutexLogFile ); ExitOnFail( hr );
fMutex = TRUE;
// Open the logfile with CREATE_ALWAYS to truncate the file
//
hFile = CreateFile( m_szFilename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if( INVALID_HANDLE_VALUE == hFile ) { ExitOnFail( hr = E_ACCESSDENIED ); }
hr = S_OK;
lExit:
if( INVALID_HANDLE_VALUE != hFile ) { CloseHandle( hFile ); }
// Release the mutex
//
if( fMutex ) { ReleaseMutex( m_hMutexLogFile ); }
return hr; }
|