//----------------------------------------------------------------------------- // Util.cpp //----------------------------------------------------------------------------- #include #include #include #include #include #include CLogging::CLogging( LPCTSTR ps ) : m_psLogFile(NULL), m_psDefaultPath(NULL), m_bInitialized(false), m_hInstance(NULL), m_bSkipDefaultPath(false) { assert( ps ); if ( NULL != ps ) { m_psLogFile = new TCHAR[ _tcslen( ps ) + 1 ]; if( NULL != m_psLogFile ) { _tcscpy( m_psLogFile, ps ); } } } CLogging::CLogging( LPCTSTR ps, LPCTSTR psPath ) : m_psLogFile(NULL), m_psDefaultPath(NULL), m_bInitialized(false), m_hInstance(NULL), m_bSkipDefaultPath(false) { assert( ps ); if ( NULL != ps ) { m_psLogFile = new TCHAR[ _tcslen( ps ) + 1 ]; if(NULL != m_psLogFile) { _tcscpy( m_psLogFile, ps ); } } assert( psPath ); if ( NULL != psPath ) { //try to substitute any embedded environment variables DWORD dwRC = 0; DWORD dwSize = ExpandEnvironmentStrings( psPath, m_psDefaultPath, 0 ); if ( 0 != dwSize ) { m_psDefaultPath = new TCHAR[dwSize + 1]; dwRC = ExpandEnvironmentStrings( psPath, m_psDefaultPath, dwSize ); } if ( 0 == dwRC ) { dwSize = _tcslen( psPath ) + 1; m_psDefaultPath = new TCHAR[ dwSize ]; if(NULL != m_psDefaultPath) { _tcsncpy( m_psDefaultPath, psPath, dwSize ); } } } } CLogging::~CLogging () { if ( NULL != m_psLogFile ) delete m_psLogFile; if ( NULL != m_psDefaultPath ) delete m_psDefaultPath; } void CLogging::Init( HINSTANCE hinst ) { m_hInstance = hinst; } void CLogging::LogPrivate( LPCTSTR szBuffer ) { if (!m_bInitialized) Initialize(); if (!m_bInitialized) return; // always create/open the log file and close it after each write HANDLE hf = CreateFile( m_psLogFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if (hf != INVALID_HANDLE_VALUE) { // io DWORD dwWritten = 0; if (!SetFilePointer( hf, 0, NULL, FILE_END )) { #ifdef UNICODE // write UNICODE signature (only first time) unsigned char sig[2] = { 0xFF, 0xFE }; WriteFile (hf, (LPVOID)sig, 2, &dwWritten, NULL); #endif } // write data dwWritten = 0; WriteFile( hf, (LPVOID)szBuffer, sizeof(TCHAR)*_tcslen( szBuffer ), &dwWritten, NULL ); assert( dwWritten != 0 ); // write crlf (if nec) // add a new line if not present int nLen = _tcslen( szBuffer ); if ( nLen >=2 ) { if (szBuffer[nLen - 2] != _T('\r') || szBuffer[nLen - 1] != _T('\n')) WriteFile( hf, (LPVOID)_T("\r\n"), 2 * sizeof(TCHAR), &dwWritten, NULL ); } // close up (every time) CloseHandle( hf ); } } void CLogging::Initialize() { HRESULT hr = S_OK; // use default log file name if necessary if ( NULL == m_psLogFile ) { m_psLogFile = new TCHAR[32]; if ( NULL == m_psLogFile ) hr = E_OUTOFMEMORY; else _tcscpy( m_psLogFile, _T("LOGFILE.log")); } // skip default path for non-server running apps if( !m_bSkipDefaultPath ) { // create dir if not there already if ( NULL == m_psDefaultPath ) { DWORD dwSize = MAX_PATH; m_psDefaultPath = new TCHAR[MAX_PATH]; if ( NULL == m_psDefaultPath ) hr = E_OUTOFMEMORY; else { if ( 0 == GetModuleFileName( NULL, m_psDefaultPath, dwSize ) ) hr = HRESULT_FROM_WIN32( GetLastError() ); else { LPTSTR ps = _tcsrchr( m_psDefaultPath, _T( '\\' )); if ( NULL != ps ) *ps = NULL; } } } else { if ( 0 == CreateDirectory( m_psDefaultPath, NULL )) { DWORD dwRC = GetLastError(); if ( ERROR_ALREADY_EXISTS == dwRC ) hr = S_OK; else hr = HRESULT_FROM_WIN32(hr); } if ( !PathAppend( m_psDefaultPath, m_psLogFile )) hr = E_FAIL; delete [] m_psLogFile; //m_psLogFile = m_psDefaultPath; This causes double free in the destructor... m_psLogFile = new TCHAR[ _tcslen( m_psDefaultPath ) + 1 ]; if( NULL != m_psLogFile ) { _tcscpy( m_psLogFile, m_psDefaultPath ); } } } if SUCCEEDED( hr ) { m_bInitialized = TRUE; // write initial messages to file TCHAR szTime[50]; TCHAR szDate[50]; GetTimeFormat( LOCALE_USER_DEFAULT, TIME_NOSECONDS, NULL, NULL, szTime, 50 ); GetDateFormat( LOCALE_USER_DEFAULT, DATE_SHORTDATE, NULL, NULL, szDate, 50 ); Log( _T("\r\n%s %s"), szDate, szTime ); } } void __cdecl CLogging::Log( int iMessageId, ... ) { va_list ArgList; // to turn ellipses into va_list va_start( ArgList, iMessageId ); LPTSTR lpBuffer = NULL; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE, m_hInstance, iMessageId, 0, (LPTSTR)&lpBuffer, 0, &ArgList ); assert( lpBuffer ); if( lpBuffer ) { LogPrivate (lpBuffer); LocalFree (lpBuffer); } va_end(ArgList); } void __cdecl CLogging::Log( LPCTSTR lpszFormat, ... ) { // form the log string va_list args; va_start( args, lpszFormat ); TCHAR szBuffer[2048]; // 2KB max log string with room for new line and null termination _vsntprintf( szBuffer, 2047, lpszFormat, args ); szBuffer[2047]=0; va_end( args ); LogPrivate( szBuffer ); } void CLogging::Size( DWORD _FileSizeLow ) { if ( 0 != _FileSizeLow % 2 ) { assert( false ); // Even numbers required in case this is a UNICODE file return; } if ( 1 > static_cast( _FileSizeLow )) { assert( false ); // Need a positive number return; } if (m_bInitialized == FALSE) Initialize(); if (!m_bInitialized) return; WIN32_FIND_DATA stWfd; HANDLE hSearch; DWORD dwRC; PBYTE pbBuffer, pbBlankLine; DWORD dwRead = 0, dwWrite, dwWritten; BOOL bRC; pbBuffer = new BYTE[_FileSizeLow]; if ( pbBuffer == NULL ) { return; } ZeroMemory( pbBuffer, _FileSizeLow ); hSearch = FindFirstFile( m_psLogFile, &stWfd ); if ( hSearch != INVALID_HANDLE_VALUE ) { FindClose( hSearch ); if ( 0 < stWfd.nFileSizeHigh || _FileSizeLow < stWfd.nFileSizeLow ) { // Need to resize the file HANDLE hf = CreateFile( m_psLogFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (hf != INVALID_HANDLE_VALUE) { // Move the pointer to the end of the file - the size we want to truncate to dwRC = SetFilePointer( hf, _FileSizeLow * -1, NULL, FILE_END ); if ( INVALID_SET_FILE_POINTER != dwRC ) { bRC = ReadFile( hf, reinterpret_cast( pbBuffer ), _FileSizeLow, &dwRead, NULL ); CloseHandle( hf ); if ( bRC && 0 < dwRead ) { // Find the first blank line pbBlankLine = reinterpret_cast( _tcsstr( reinterpret_cast( pbBuffer ), _T( "\r\n\r\n" ))); if ( NULL != pbBlankLine ) pbBlankLine += 4 * sizeof( TCHAR ); else { // Let's just find the next crlf and write out the rest of the file pbBlankLine = reinterpret_cast( _tcsstr( reinterpret_cast( pbBuffer ), _T( "\r\n" ))); if ( NULL != pbBlankLine ) pbBlankLine += 2 * sizeof( TCHAR ); } if ( NULL == pbBlankLine ) { // I guess we should just write out the rest of the file pbBlankLine = pbBuffer; } HANDLE hf1 = CreateFile( m_psLogFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if (hf1 != INVALID_HANDLE_VALUE) { #ifdef UNICODE // write UNICODE signature (only first time) unsigned char sig[2] = { 0xFF, 0xFE }; WriteFile (hf1, (LPVOID)sig, 2, &dwWritten, NULL); #endif // write data dwWritten = 0; dwWrite = dwRead - static_cast(pbBlankLine - pbBuffer); WriteFile (hf1, pbBlankLine, dwWrite, &dwWritten, NULL); assert (dwWritten != 0); // close up (every time) CloseHandle (hf1); } } } CloseHandle(hf); } } } delete [] pbBuffer; } void CLogging::SetFile( LPCTSTR psLogFile ) { assert( !(NULL == psLogFile )); if ( NULL == psLogFile ) return; if ( NULL != m_psLogFile ) delete m_psLogFile; m_psLogFile = new TCHAR[ _tcslen( psLogFile ) + 1 ]; if ( NULL == m_psLogFile ) return; _tcscpy( m_psLogFile, psLogFile ); } void CLogging::SkipDefaultPath( void ) { m_bSkipDefaultPath = true; }