|
|
/*++
Copyright (C) 1996-1999 Microsoft Corporation
Module Name:
log_text.c
Abstract:
<abstract>
--*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <mbctype.h>
#include <pdh.h>
#include "pdhidef.h"
#include "log_text.h"
#include "pdhmsg.h"
#include "strings.h"
#pragma warning ( disable : 4213)
#define TAB_DELIMITER '\t'
#define COMMA_DELIMITER ','
#define DOUBLE_QUOTE '\"'
#define VALUE_BUFFER_SIZE 32
LPCSTR PdhiszFmtTimeStamp = "\"%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d.%3.3d\""; LPCSTR PdhiszFmtStringValue = "%c\"%s\""; LPCSTR PdhiszFmtRealValue = "%c\"%.20g\""; TIME_ZONE_INFORMATION TimeZone; // LPCSTR PdhiszTimeStampLabel = " Sample Time\"";
// DWORD PdhidwTimeStampLabelLength = 13;
extern LPCSTR PdhiszRecordTerminator; extern DWORD PdhidwRecordTerminatorLength;
#define TEXTLOG_TYPE_ID_RECORD 1
#define TEXTLOG_HEADER_RECORD 1
#define TEXTLOG_FIRST_DATA_RECORD 2
#define TIME_FIELD_COUNT 7
#define TIME_FIELD_BUFF_SIZE 24
DWORD dwTimeFieldOffsetList[TIME_FIELD_COUNT] = {2, 5, 10, 13, 16, 19, 23};
#define MAX_TEXT_FILE_SIZE ((LONGLONG)0x0000000077FFFFFF)
PDH_FUNCTION PdhiBuildFullCounterPath( IN BOOL bMachine, IN PPDHI_COUNTER_PATH pCounterPath, IN LPWSTR szObjectName, IN LPWSTR szCounterName, IN LPWSTR szFullPath );
STATIC_BOOL PdhiDateStringToFileTimeA ( IN LPSTR szDateTimeString, IN LPFILETIME pFileTime );
STATIC_DWORD PdhiGetStringFromDelimitedListA ( IN LPSTR szInputString, IN DWORD dwItemIndex, IN CHAR cDelimiter, IN DWORD dwFlags, IN LPSTR szOutputString, IN DWORD cchBufferLength );
STATIC_PDH_FUNCTION PdhiReadOneTextLogRecord ( IN PPDHI_LOG pLog, IN DWORD dwRecordId, IN LPSTR szRecord, IN DWORD dwMaxSize );
STATIC_BOOL PdhiDateStringToFileTimeA ( IN LPSTR szDateTimeString, IN LPFILETIME pFileTime ) { CHAR mszTimeFields[TIME_FIELD_BUFF_SIZE]; DWORD dwThisField; LONG lValue; SYSTEMTIME st;
// make string into msz
lstrcpynA (mszTimeFields, szDateTimeString, TIME_FIELD_BUFF_SIZE); for (dwThisField = 0; dwThisField < TIME_FIELD_COUNT; dwThisField++) { mszTimeFields[dwTimeFieldOffsetList[dwThisField]] = 0; }
// read string into system time structure
dwThisField = 0; st.wDayOfWeek = 0; lValue = atol(&mszTimeFields[0]); st.wMonth = LOWORD(lValue); lValue = atol(&mszTimeFields[dwTimeFieldOffsetList[dwThisField++]+1]); st.wDay = LOWORD(lValue); lValue = atol(&mszTimeFields[dwTimeFieldOffsetList[dwThisField++]+1]); st.wYear = LOWORD(lValue); lValue = atol(&mszTimeFields[dwTimeFieldOffsetList[dwThisField++]+1]); st.wHour = LOWORD(lValue); lValue = atol(&mszTimeFields[dwTimeFieldOffsetList[dwThisField++]+1]); st.wMinute = LOWORD(lValue); lValue = atol(&mszTimeFields[dwTimeFieldOffsetList[dwThisField++]+1]); st.wSecond = LOWORD(lValue); lValue = atol(&mszTimeFields[dwTimeFieldOffsetList[dwThisField++]+1]); st.wMilliseconds = LOWORD(lValue);
return SystemTimeToFileTime (&st, pFileTime); }
#define PDHI_GSFDL_REMOVE_QUOTES 0x00000001
#define PDHI_GSFDL_REMOVE_NONPRINT 0x00000002
STATIC_DWORD PdhiGetStringFromDelimitedListA ( IN LPSTR szInputString, IN DWORD dwItemIndex, IN CHAR cDelimiter, IN DWORD dwFlags, IN LPSTR szOutputString, IN DWORD cchBufferLength ) { DWORD dwCurrentIndex = 0; LPSTR szCurrentItem; LPSTR szSrcPtr, szDestPtr; DWORD dwReturn = 0; BOOL bInsideQuote = FALSE;
// go to desired entry in string, 0 = first entry
szCurrentItem = szInputString;
while (dwCurrentIndex < dwItemIndex) { // goto next delimiter or terminator
while (* szCurrentItem != cDelimiter || bInsideQuote) { if (* szCurrentItem == 0) break; else if (* szCurrentItem == DOUBLEQUOTE_A) { bInsideQuote = ! bInsideQuote; } szCurrentItem ++; } if (* szCurrentItem != 0) szCurrentItem ++; dwCurrentIndex++; } if (*szCurrentItem != 0) { // then copy to the user's buffer, as long as it fits
szSrcPtr = szCurrentItem; szDestPtr = szOutputString; dwReturn = 0; bInsideQuote = FALSE;
while ( (dwReturn < cchBufferLength) && (* szSrcPtr != 0) && (* szSrcPtr != cDelimiter || bInsideQuote)) { if (* szSrcPtr == DOUBLEQUOTE_A) { bInsideQuote = ! bInsideQuote; if (dwFlags & PDHI_GSFDL_REMOVE_QUOTES) { // skip the quote
szSrcPtr ++; continue; } }
if (dwFlags & PDHI_GSFDL_REMOVE_NONPRINT) { if ((UCHAR) * szSrcPtr < (UCHAR) ' ') { // skip the control char
szSrcPtr ++; continue; } }
// copy character
* szDestPtr ++ = * szSrcPtr ++; dwReturn ++; // increment length
} if (dwReturn > 0) { * szDestPtr = 0; // add terminator char
} } return dwReturn; }
STATIC_PDH_FUNCTION PdhiReadOneTextLogRecord ( IN PPDHI_LOG pLog, IN DWORD dwRecordId, IN LPSTR szRecord, IN DWORD dwMaxSize ) // reads the specified record from the log file and returns it as an ANSI
// character string
{ LPSTR szTempBuffer; LPSTR szOldBuffer; LPSTR szTempBufferPtr; LPSTR szReturn; PDH_STATUS pdhStatus; int nFileError = 0; DWORD dwRecordLength; DWORD dwBytesRead = 0;
if (pLog->dwMaxRecordSize == 0) { // initialize with a default value
dwRecordLength = SMALL_BUFFER_SIZE; } else { // use current maz record size max.
dwRecordLength = pLog->dwMaxRecordSize; }
szTempBuffer = G_ALLOC (dwRecordLength); if (szTempBuffer == NULL) { return PDH_MEMORY_ALLOCATION_FAILURE; } // position file pointer to desired record;
if (dwRecordId == pLog->dwLastRecordRead) { // then return the current record from the cached buffer
if ((DWORD)lstrlenA((LPSTR)pLog->pLastRecordRead) < dwMaxSize) { lstrcpyA(szRecord, (LPSTR)pLog->pLastRecordRead); pdhStatus = ERROR_SUCCESS; } else { pdhStatus = PDH_MORE_DATA; } // free temp buffer
if (szTempBuffer != NULL) { G_FREE (szTempBuffer); } } else { if ((dwRecordId < pLog->dwLastRecordRead) || (pLog->dwLastRecordRead == 0)){ // the desired record is before the current position
// or the counter has been reset so we have to
// go to the beginning of the file and read up to the specified
// record.
pLog->dwLastRecordRead = 0; rewind (pLog->StreamFile); }
// free old buffer
if (pLog->pLastRecordRead != NULL) { G_FREE (pLog->pLastRecordRead); pLog->pLastRecordRead = NULL; }
// now seek to the desired entry
do { szReturn = fgets (szTempBuffer, dwRecordLength, pLog->StreamFile); if (szReturn == NULL) { if (!feof(pLog->StreamFile)) { nFileError = ferror (pLog->StreamFile); } break; // end of file
} else { // see if an entire record was read
dwBytesRead = lstrlenA(szTempBuffer); // see if the last char is a new line
if ((dwBytesRead > 0) && (szTempBuffer[dwBytesRead-1] != '\r') && (szTempBuffer[dwBytesRead-1] != '\n')) { // then if the record size is the same as the buffer
// or there's more text in this record...
// just to be safe, we'll realloc the buffer and try
// reading some more
while (dwBytesRead == dwRecordLength-1) { dwRecordLength += SMALL_BUFFER_SIZE; szOldBuffer = szTempBuffer; szTempBuffer = G_REALLOC (szOldBuffer, dwRecordLength); if (szTempBuffer == NULL) { G_FREE(szOldBuffer); pLog->dwLastRecordRead = 0; pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE; goto Cleanup; } // position read pointer at end of bytes already read
szTempBufferPtr = szTempBuffer + dwBytesRead;
szReturn = fgets (szTempBufferPtr, dwRecordLength - dwBytesRead, pLog->StreamFile); if (szReturn == NULL) { if (!feof(pLog->StreamFile)) { nFileError = ferror (pLog->StreamFile); } break; // end of file
} else { // the BytesRead value already includes the NULL
dwBytesRead += lstrlenA(szTempBufferPtr); } } // end while finding the end of the record
// update the record length
// add one byte to the length read to prevent entering the
// recalc loop on records of the same size
dwRecordLength = dwBytesRead + 1; szOldBuffer = szTempBuffer; szTempBuffer = G_REALLOC (szOldBuffer, dwRecordLength); if (szTempBuffer == NULL) { G_FREE(szOldBuffer); pLog->dwLastRecordRead = 0; pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE; goto Cleanup; } assert (szTempBuffer != NULL); } // else the whole record fit
}
} while (++pLog->dwLastRecordRead < dwRecordId);
// update the max record length for the log file.
if (dwRecordLength> pLog->dwMaxRecordSize) { pLog->dwMaxRecordSize = dwRecordLength; }
// if the desired one was found then return it
if (szReturn != NULL) { // then a record was read so update the cached values and return
// the data
pLog->pLastRecordRead = (LPVOID)szTempBuffer;
// copy to the caller's buffer
if (dwBytesRead < dwMaxSize) { lstrcpyA(szRecord, (LPSTR)pLog->pLastRecordRead); pdhStatus = ERROR_SUCCESS; } else { pdhStatus = PDH_MORE_DATA; } } else { // reset the pointers and buffers
pLog->dwLastRecordRead = 0; G_FREE (szTempBuffer); pdhStatus = PDH_END_OF_LOG_FILE; } }
Cleanup: return pdhStatus; }
PDH_FUNCTION PdhiGetTextLogCounterInfo ( IN PPDHI_LOG pLog, IN PPDHI_COUNTER pCounter ) { PDH_STATUS pdhStatus; LPSTR szReturn; CHAR cDelim; CHAR szTemp[4]; LPSTR szAnsiCounterPath = NULL; LPSTR szAnsiCounter = NULL; LPWSTR szUnicodeCounter = NULL; DWORD dwIndex; LPSTR szThisItem; DWORD dwPathLength; DWORD dwBufferLength; DWORD dwItemLength; DWORD dwInstanceId = 0; BOOL bNoMachine = FALSE;
if (lstrcmpiW(pCounter->pCounterPath->szMachineName, L"\\\\.") == 0) { bNoMachine = TRUE; }
// allocate extra space for DBCS characters
//
dwPathLength = lstrlenW(pCounter->pCounterPath->szMachineName) + 1 + lstrlenW(pCounter->pCounterPath->szObjectName) + 1 + lstrlenW(pCounter->pCounterPath->szParentName) + 4 + lstrlenW(pCounter->pCounterPath->szInstanceName) + 2 + lstrlenW(pCounter->pCounterPath->szCounterName) + 1; if ((lstrlenW(pCounter->szFullName) + 1) > (LONG) dwPathLength) { dwPathLength = lstrlenW(pCounter->szFullName) + 1; } szAnsiCounterPath = G_ALLOC(dwPathLength * 3 * sizeof(CHAR)); szAnsiCounter = G_ALLOC(dwPathLength * 3 * sizeof(CHAR)); szUnicodeCounter = G_ALLOC(dwPathLength * sizeof(WCHAR)); if (szAnsiCounterPath == NULL || szUnicodeCounter == NULL || szAnsiCounter == NULL) { pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE; goto Cleanup; } else { PdhiBuildFullCounterPath((bNoMachine ? FALSE : TRUE), pCounter->pCounterPath, pCounter->pCounterPath->szObjectName, pCounter->pCounterPath->szCounterName, szUnicodeCounter); WideCharToMultiByte(_getmbcp(), 0, pCounter->szFullName, lstrlenW(pCounter->szFullName), szAnsiCounterPath, dwPathLength, NULL, NULL); WideCharToMultiByte(_getmbcp(), 0, szUnicodeCounter, lstrlenW(szUnicodeCounter), szAnsiCounter, dwPathLength, NULL, NULL); }
szReturn = &szTemp[0]; // for starters
// read the log file's header record
pdhStatus = PdhiReadOneTextLogRecord ( pLog, TEXTLOG_HEADER_RECORD, szReturn, 1); // we're lying to prevent copying the record.
// what's in szReturn is not important since we'll be reading the
// data from the "last Record read" buffer
if (pLog->dwLastRecordRead == TEXTLOG_HEADER_RECORD) { cDelim = (CHAR)((LOWORD(pLog->dwLogFormat) == PDH_LOG_TYPE_CSV) ? COMMA_DELIMITER : TAB_DELIMITER);
// then the seek worked and we can use the buffer
dwBufferLength = lstrlenA((LPSTR)pLog->pLastRecordRead) + 1; szReturn = G_ALLOC (dwBufferLength * sizeof(CHAR)); if (szReturn != NULL) { lstrcpyA (szReturn, (LPSTR)pLog->pLastRecordRead); dwIndex = 0; szThisItem = NULL; while ((dwItemLength = PdhiGetStringFromDelimitedListA( (LPSTR)pLog->pLastRecordRead, ++dwIndex, cDelim, PDHI_GSFDL_REMOVE_QUOTES | PDHI_GSFDL_REMOVE_NONPRINT, szReturn, dwBufferLength)) != 0) { if (lstrcmpiA(szReturn, szAnsiCounterPath) == 0) { szThisItem = szReturn; break; } else if (lstrcmpiA(szReturn, szAnsiCounter) == 0) { // then this is the desired counter
if (dwInstanceId < pCounter->pCounterPath->dwIndex) { dwInstanceId ++; } else { szThisItem = szReturn; break; } } } if (szThisItem != NULL) { if (bNoMachine) { pCounter->pCounterPath->szMachineName = NULL; } // this is a valid counter so update the fields
// for Text logs, none of this info is used
pCounter->plCounterInfo.dwObjectId = 0; pCounter->plCounterInfo.lInstanceId = dwInstanceId; pCounter->plCounterInfo.szInstanceName = NULL; pCounter->plCounterInfo.dwParentObjectId = 0; pCounter->plCounterInfo.szParentInstanceName = NULL; // this data is used by the log file readers
pCounter->plCounterInfo.dwCounterId = dwIndex; pCounter->plCounterInfo.dwCounterType = PERF_DOUBLE_RAW; pCounter->plCounterInfo.dwCounterSize = 8; pdhStatus = ERROR_SUCCESS; } else { // counter not found
pdhStatus = PDH_CSTATUS_NO_COUNTER; } G_FREE (szReturn); } else { pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE; } } else { // unable to read header from log file
pdhStatus = PDH_UNABLE_READ_LOG_HEADER; }
Cleanup: if (szAnsiCounterPath) G_FREE(szAnsiCounterPath); if (szAnsiCounter) G_FREE(szAnsiCounter); if (szUnicodeCounter) G_FREE(szUnicodeCounter);
return pdhStatus; }
PDH_FUNCTION PdhiOpenInputTextLog ( IN PPDHI_LOG pLog ) { PDH_STATUS pdhStatus;
// open a stream handle for easy C RTL I/O
pLog->StreamFile = _wfopen (pLog->szLogFileName, (LPCWSTR)L"rt"); if (pLog->StreamFile == NULL || pLog->StreamFile == (FILE *)((DWORD_PTR)(-1))) { pLog->StreamFile = (FILE *)((DWORD_PTR) (-1)); pdhStatus = PDH_LOG_FILE_OPEN_ERROR; } else { pdhStatus = ERROR_SUCCESS; } return pdhStatus; }
PDH_FUNCTION PdhiOpenOutputTextLog ( IN PPDHI_LOG pLog ) { PDH_STATUS pdhStatus;
pLog->StreamFile = (FILE *)((DWORD_PTR)(-1)); pLog->dwRecord1Size = 0; pdhStatus = ERROR_SUCCESS;
return pdhStatus; }
PDH_FUNCTION PdhiCloseTextLog ( IN PPDHI_LOG pLog, IN DWORD dwFlags ) { PDH_STATUS pdhStatus;
UNREFERENCED_PARAMETER (dwFlags);
if (pLog->StreamFile != NULL && pLog->StreamFile != (FILE *)((DWORD_PTR)(-1))) { fclose (pLog->StreamFile); pLog->StreamFile = (FILE *)((DWORD_PTR)(-1)); } pdhStatus = ERROR_SUCCESS; return pdhStatus; }
PDH_FUNCTION PdhiWriteTextLogHeader ( IN PPDHI_LOG pLog, IN LPCWSTR szUserCaption ) { PDH_STATUS pdhStatus = ERROR_SUCCESS; PPDHI_COUNTER pThisCounter; CHAR cDelim; CHAR szLeadDelim[4]; DWORD dwLeadSize; CHAR szTrailDelim[4]; DWORD dwTrailSize; DWORD dwBytesWritten; LPSTR szCounterPath = NULL; LPWSTR wszCounterPath = NULL; LPSTR szLocalCaption = NULL; DWORD dwCaptionSize = 0; BOOL bDefaultCaption;
LPSTR szOutputString = NULL; LPSTR szTmpString; DWORD dwStringBufferSize = 0; DWORD dwStringBufferUsed = 0; DWORD dwNewStringLen;
szCounterPath = G_ALLOC(MEDIUM_BUFFER_SIZE * sizeof(CHAR)); wszCounterPath = G_ALLOC(MEDIUM_BUFFER_SIZE * sizeof(WCHAR)); szOutputString = G_ALLOC(MEDIUM_BUFFER_SIZE * sizeof(CHAR)); if (szCounterPath == NULL || wszCounterPath == NULL || szOutputString == NULL) { pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE; goto Cleanup; } dwStringBufferSize = MEDIUM_BUFFER_SIZE;
cDelim = (CHAR)((LOWORD(pLog->dwLogFormat) == PDH_LOG_TYPE_CSV) ? COMMA_DELIMITER : TAB_DELIMITER);
szLeadDelim[0] = cDelim; szLeadDelim[1] = DOUBLE_QUOTE; szLeadDelim[2] = 0; szLeadDelim[3] = 0; dwLeadSize = 2 * sizeof(szLeadDelim[0]);
szTrailDelim[0] = DOUBLE_QUOTE; szTrailDelim[1] = 0; szTrailDelim[2] = 0; szTrailDelim[3] = 0; dwTrailSize = 1 * sizeof(szTrailDelim[0]);
// we'll assume the buffer allocated is large enough to hold the timestamp
// and 1st counter name. After that we'll test the size first.
lstrcpyA(szOutputString, szTrailDelim); lstrcatA(szOutputString, (LOWORD(pLog->dwLogFormat) == PDH_LOG_TYPE_CSV ? szCsvLogFileHeader : szTsvLogFileHeader));
{ // Add TimeZone information
//
DWORD dwReturn = GetTimeZoneInformation(&TimeZone); CHAR strTimeZone[MAX_PATH];
if (dwReturn != TIME_ZONE_ID_INVALID) { if (dwReturn == TIME_ZONE_ID_DAYLIGHT) { sprintf(strTimeZone, " (%ws)(%d)", TimeZone.DaylightName, TimeZone.Bias + TimeZone.DaylightBias); } else { sprintf(strTimeZone, " (%ws)(%d)", TimeZone.StandardName, TimeZone.Bias + TimeZone.StandardBias); } lstrcatA(szOutputString, strTimeZone); pLog->dwRecord1Size = 1; } }
lstrcatA(szOutputString, szTrailDelim); lstrlenA(szOutputString);
// get buffer size here
dwStringBufferUsed = lstrlenA(szOutputString);
// check each counter in the list of counters for this query and
// write them to the file
// output the path names
pThisCounter = pLog->pQuery ? pLog->pQuery->pCounterListHead : NULL;
if (pThisCounter != NULL) { do { // get the counter path information from the counter
ZeroMemory(wszCounterPath, sizeof(WCHAR) * MEDIUM_BUFFER_SIZE); ZeroMemory(szCounterPath, sizeof(CHAR) * MEDIUM_BUFFER_SIZE);
PdhiBuildFullCounterPath(TRUE, pThisCounter->pCounterPath, pThisCounter->pCounterPath->szObjectName, pThisCounter->pCounterPath->szCounterName, wszCounterPath); WideCharToMultiByte(_getmbcp(), 0, wszCounterPath, lstrlenW(wszCounterPath), (LPSTR) szCounterPath, MEDIUM_BUFFER_SIZE, NULL, NULL); dwNewStringLen = lstrlenA(szCounterPath); dwNewStringLen += dwLeadSize; dwNewStringLen += dwTrailSize;
if ((dwNewStringLen + dwStringBufferUsed) >= dwStringBufferSize) { dwStringBufferSize += SMALL_BUFFER_SIZE; szTmpString = szOutputString; szOutputString = G_REALLOC (szTmpString, dwStringBufferSize); if (szOutputString == NULL) { G_FREE(szTmpString); pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE; break; // out of DO loop
} } else { // mem alloc ok, so continue
}
lstrcatA (szOutputString, szLeadDelim); if (pdhStatus == ERROR_SUCCESS) { lstrcatA (szOutputString, szCounterPath); } else { // just write the delimiters and no string inbetween
} lstrcatA (szOutputString, szTrailDelim);
dwStringBufferUsed += dwNewStringLen;
pThisCounter = pThisCounter->next.flink; // go to next in list
} while (pThisCounter != pLog->pQuery->pCounterListHead); }
// test to see if the caller wants to append user strings to the log
if (((pLog->dwLogFormat & PDH_LOG_OPT_MASK) == PDH_LOG_OPT_USER_STRING) && (pdhStatus == ERROR_SUCCESS)) { // they want to write user data so see if they've passed in a
// caption string
if (szUserCaption != NULL) { dwCaptionSize = lstrlenW (szUserCaption) + 1; // allocate larger buffer to accomodate DBCS characters
dwCaptionSize = dwCaptionSize * 3 * sizeof (CHAR);
szLocalCaption = (LPSTR) G_ALLOC (dwCaptionSize); if (szLocalCaption != NULL) { memset(szLocalCaption, 0, dwCaptionSize); dwCaptionSize = WideCharToMultiByte( _getmbcp(), 0, szUserCaption, lstrlenW(szUserCaption), szLocalCaption, dwCaptionSize, NULL, NULL); bDefaultCaption = FALSE; } else { bDefaultCaption = TRUE; } } else { bDefaultCaption = TRUE; }
if (bDefaultCaption) { szLocalCaption = (LPSTR)caszDefaultLogCaption; dwCaptionSize = lstrlenA (szLocalCaption); }
dwNewStringLen = (DWORD)dwCaptionSize; dwNewStringLen += dwLeadSize; dwNewStringLen += dwTrailSize;
if ((dwNewStringLen + dwStringBufferUsed) >= dwStringBufferSize) { dwStringBufferSize += SMALL_BUFFER_SIZE; szTmpString = szOutputString; szOutputString = G_REALLOC (szTmpString, dwStringBufferSize); if (szOutputString == NULL) { G_FREE(szTmpString); pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE; } } else { // mem alloc ok, so continue
}
if (pdhStatus == ERROR_SUCCESS) { lstrcatA (szOutputString, szLeadDelim); #pragma warning (disable : 4701 ) // szLocalCaption is initialized above
lstrcatA (szOutputString, szLocalCaption); #pragma warning (default : 4701)
lstrcatA (szOutputString, szTrailDelim);
}
dwStringBufferUsed += dwNewStringLen; if (!bDefaultCaption) { G_FREE (szLocalCaption); }
}
if (pdhStatus == ERROR_SUCCESS) {
if ((PdhidwRecordTerminatorLength + dwStringBufferUsed) >= dwStringBufferSize) { dwStringBufferSize += PdhidwRecordTerminatorLength; szTmpString = szOutputString; szOutputString = G_REALLOC (szTmpString, dwStringBufferSize); if (szOutputString == NULL) { G_FREE(szTmpString); pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE; } } else { // mem alloc ok, so continue
}
if (pdhStatus == ERROR_SUCCESS) {
lstrcatA (szOutputString, PdhiszRecordTerminator); dwStringBufferUsed += PdhidwRecordTerminatorLength;
// write the record
if (!WriteFile (pLog->hLogFileHandle, (LPCVOID)szOutputString, dwStringBufferUsed, &dwBytesWritten, NULL)) { pdhStatus = GetLastError(); } else if (pLog->pQuery->hLog == H_REALTIME_DATASOURCE || pLog->pQuery->hLog == H_WBEM_DATASOURCE) { FlushFileBuffers(pLog->hLogFileHandle); }
if (dwStringBufferUsed > pLog->dwMaxRecordSize) { // then update the buffer size
pLog->dwMaxRecordSize = dwStringBufferUsed; } } }
Cleanup: if (szCounterPath != NULL) G_FREE(szCounterPath); if (wszCounterPath != NULL) G_FREE(wszCounterPath); if (szOutputString != NULL) G_FREE(szOutputString);
return pdhStatus; }
PDH_FUNCTION PdhiWriteTextLogRecord ( IN PPDHI_LOG pLog, IN SYSTEMTIME *stTimeStamp, IN LPCWSTR szUserString ) { PDH_STATUS pdhStatus = ERROR_SUCCESS; PPDHI_COUNTER pThisCounter; CHAR cDelim; DWORD dwBytesWritten; DWORD dwBufferSize; CHAR szValueBuffer[VALUE_BUFFER_SIZE]; PDH_FMT_COUNTERVALUE pdhValue;
DWORD dwUserStringSize; LPSTR szLocalUserString = NULL; BOOL bDefaultUserString;
LPSTR szOutputString = NULL; DWORD dwStringBufferSize = 0; DWORD dwStringBufferUsed = 0; DWORD dwNewStringLen; SYSTEMTIME lstTimeStamp;
LARGE_INTEGER liFileSize;
dwStringBufferSize = (MEDIUM_BUFFER_SIZE > pLog->dwMaxRecordSize ? MEDIUM_BUFFER_SIZE : pLog->dwMaxRecordSize);
szOutputString = G_ALLOC (dwStringBufferSize); if (szOutputString == NULL) { return PDH_MEMORY_ALLOCATION_FAILURE; }
cDelim = (CHAR)((LOWORD(pLog->dwLogFormat) == PDH_LOG_TYPE_CSV) ? COMMA_DELIMITER : TAB_DELIMITER);
// format and write the time stamp title
lstTimeStamp = * stTimeStamp;
dwStringBufferUsed = sprintf (szOutputString, PdhiszFmtTimeStamp, lstTimeStamp.wMonth, lstTimeStamp.wDay, lstTimeStamp.wYear, lstTimeStamp.wHour, lstTimeStamp.wMinute, lstTimeStamp.wSecond, lstTimeStamp.wMilliseconds);
// check each counter in the list of counters for this query and
// write them to the file
pThisCounter = pLog->pQuery ? pLog->pQuery->pCounterListHead : NULL;
if (pThisCounter != NULL) { // lock the query while we read the data so the values
// written to the log will all be from the same sample
pdhStatus = WAIT_FOR_AND_LOCK_MUTEX(pThisCounter->pOwner->hMutex); if (pdhStatus == ERROR_SUCCESS) { do { // get the formatted value from the counter
// compute and format current value
pdhStatus = PdhiComputeFormattedValue ( pThisCounter->CalcFunc, pThisCounter->plCounterInfo.dwCounterType, pThisCounter->lScale, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &pThisCounter->ThisValue, &pThisCounter->LastValue, &pThisCounter->TimeBase, 0L, &pdhValue);
if ((pdhStatus == ERROR_SUCCESS) && ((pdhValue.CStatus == PDH_CSTATUS_VALID_DATA) || (pdhValue.CStatus == PDH_CSTATUS_NEW_DATA))) { // then this is a valid data value so print it
dwBufferSize = sprintf (szValueBuffer, PdhiszFmtRealValue, cDelim, pdhValue.doubleValue); } else { // invalid data so show a blank data value
dwBufferSize = sprintf (szValueBuffer, PdhiszFmtStringValue, cDelim, caszSpace); // reset error
pdhStatus = ERROR_SUCCESS; }
dwNewStringLen = dwBufferSize;
if ((dwNewStringLen+dwStringBufferUsed) >= dwStringBufferSize) { LPTSTR szNewString; dwStringBufferSize += SMALL_BUFFER_SIZE; szNewString = G_REALLOC (szOutputString, dwStringBufferSize); if (szNewString == NULL) { pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE; break; // out of DO loop
} else { szOutputString = szNewString; } }
if (pdhStatus != PDH_MEMORY_ALLOCATION_FAILURE) { lstrcatA (szOutputString, szValueBuffer); dwStringBufferUsed += dwNewStringLen; }
// goto the next counter in the list
pThisCounter = pThisCounter->next.flink; // go to next in list
} while (pThisCounter != pLog->pQuery->pCounterListHead); // free (i.e. unlock) the query
RELEASE_MUTEX(pThisCounter->pOwner->hMutex); } }
if (pdhStatus == PDH_MEMORY_ALLOCATION_FAILURE) // cannot go further
goto endLogText;
// test to see if the caller wants to append user strings to the log
if ((pLog->dwLogFormat & PDH_LOG_OPT_MASK) == PDH_LOG_OPT_USER_STRING) { // they want to write user data so see if they've passed in a
// display string
if (szUserString != NULL) { // get size in chars
dwUserStringSize = lstrlenW (szUserString) + 1; // allocate larger buffer to accomodate DBCS characters
dwUserStringSize = dwUserStringSize * 3 * sizeof(CHAR); szLocalUserString = (LPSTR) G_ALLOC (dwUserStringSize); if (szLocalUserString != NULL) { memset(szLocalUserString, 0, dwUserStringSize); dwUserStringSize = WideCharToMultiByte( _getmbcp(), 0, szUserString, lstrlenW(szUserString), szLocalUserString, dwUserStringSize, NULL, NULL); bDefaultUserString = FALSE; } else { bDefaultUserString = TRUE; } } else { bDefaultUserString = TRUE; }
if (bDefaultUserString) { szLocalUserString = (LPSTR)caszSpace; dwUserStringSize = lstrlenA (szLocalUserString); }
#pragma warning (disable : 4701) // szLocalUserString is init'd above
dwBufferSize = sprintf (szValueBuffer, PdhiszFmtStringValue, cDelim, szLocalUserString); #pragma warning (default : 4701)
dwNewStringLen = dwBufferSize;
if ((dwNewStringLen + dwStringBufferUsed) >= dwStringBufferSize) { LPTSTR szNewString;
dwStringBufferSize += SMALL_BUFFER_SIZE; szNewString = G_REALLOC (szOutputString, dwStringBufferSize); if (szNewString == NULL) { pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE; } else { szOutputString = szNewString; } }
if (pdhStatus != PDH_MEMORY_ALLOCATION_FAILURE) { lstrcatA (szOutputString, szValueBuffer); dwStringBufferUsed += dwNewStringLen; }
if (!bDefaultUserString) { G_FREE (szLocalUserString); }
}
if (pdhStatus == PDH_MEMORY_ALLOCATION_FAILURE) goto endLogText;
if ((PdhidwRecordTerminatorLength + dwStringBufferUsed) >= dwStringBufferSize) { LPTSTR szNewString; dwStringBufferSize += PdhidwRecordTerminatorLength; szNewString = G_REALLOC (szOutputString, dwStringBufferSize); if (szNewString == NULL) { pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE; } else { szOutputString = szNewString; } }
if (pdhStatus == ERROR_SUCCESS) { lstrcatA (szOutputString, PdhiszRecordTerminator); dwStringBufferUsed += PdhidwRecordTerminatorLength;
liFileSize.LowPart = GetFileSize ( pLog->hLogFileHandle, (LPDWORD)&liFileSize.HighPart); // add in new record to see if it will fit.
liFileSize.QuadPart += dwStringBufferUsed; // test for maximum allowable filesize
if (liFileSize.QuadPart <= MAX_TEXT_FILE_SIZE) {
// write the record terminator
if (!WriteFile (pLog->hLogFileHandle, (LPCVOID)szOutputString, dwStringBufferUsed, &dwBytesWritten, NULL)) { pdhStatus = GetLastError (); } else if (pLog->pQuery->hLog == H_REALTIME_DATASOURCE || pLog->pQuery->hLog == H_WBEM_DATASOURCE) { FlushFileBuffers(pLog->hLogFileHandle); } } else { pdhStatus = ERROR_LOG_FILE_FULL; }
if (dwStringBufferUsed> pLog->dwMaxRecordSize) { // then update the buffer size
pLog->dwMaxRecordSize = dwStringBufferUsed; } }
endLogText: G_FREE (szOutputString);
return pdhStatus; }
PDH_FUNCTION PdhiEnumMachinesFromTextLog ( PPDHI_LOG pLog, LPVOID pBuffer, LPDWORD lpdwBufferSize, BOOL bUnicodeDest ) { PDH_STATUS pdhStatus; PDH_STATUS pdhBuffStatus = ERROR_SUCCESS; LPSTR szBuffer; CHAR szTemp[4]; CHAR cDelim; PPDH_COUNTER_PATH_ELEMENTS_A pInfo; DWORD dwInfoBufferSize; DWORD dwBufferUsed; DWORD dwNewBuffer; DWORD dwIndex; DWORD dwItemLength; DWORD dwBufferLength; DWORD dwItemCount = 0; LPVOID LocalBuffer = NULL; LPVOID TempBuffer; DWORD LocalBufferSize = 0;
LocalBuffer = G_ALLOC(MEDIUM_BUFFER_SIZE); if (LocalBuffer == NULL) { return PDH_MEMORY_ALLOCATION_FAILURE; } LocalBufferSize = MEDIUM_BUFFER_SIZE; memset(LocalBuffer, 0, MEDIUM_BUFFER_SIZE); if (pBuffer) { memset(pBuffer, 0, * lpdwBufferSize); }
pInfo = (PPDH_COUNTER_PATH_ELEMENTS_A) G_ALLOC (MEDIUM_BUFFER_SIZE); if (pInfo == NULL) { G_FREE(LocalBuffer); return PDH_MEMORY_ALLOCATION_FAILURE; }
szBuffer = &szTemp[0];
// what's in szReturn is not important since we'll be reading the
// data from the "last Record read" buffer
pdhStatus = PdhiReadOneTextLogRecord ( pLog, TEXTLOG_HEADER_RECORD, szBuffer, 1); // we're lying to prevent copying the record.
if (pLog->dwLastRecordRead == TEXTLOG_HEADER_RECORD) { // then the seek worked and we can use the buffer
cDelim = (CHAR)((LOWORD(pLog->dwLogFormat) == PDH_LOG_TYPE_CSV) ? COMMA_DELIMITER : TAB_DELIMITER);
dwBufferLength = lstrlenA((LPSTR)pLog->pLastRecordRead)+1; szBuffer = G_ALLOC (dwBufferLength); if (szBuffer != NULL) { dwBufferUsed = 0; dwIndex = 0; while ((dwItemLength = PdhiGetStringFromDelimitedListA( (LPSTR)pLog->pLastRecordRead, ++dwIndex, cDelim, PDHI_GSFDL_REMOVE_QUOTES | PDHI_GSFDL_REMOVE_NONPRINT, szBuffer, dwBufferLength)) != 0) {
if (dwItemLength > 0) { dwInfoBufferSize = MEDIUM_BUFFER_SIZE; // parse the path, pull the machine name out and
memset(pInfo, 0, MEDIUM_BUFFER_SIZE); pdhStatus = PdhParseCounterPathA ( szBuffer, pInfo, &dwInfoBufferSize, 0);
if (pdhStatus == ERROR_SUCCESS) { if (szBuffer[1] != '\\') { pInfo->szMachineName[0] = '.'; pInfo->szMachineName[1] = '\0'; } // add it to the list if it will fit
if (pInfo->szMachineName != NULL) { // include sizeof delimiter char
dwNewBuffer = (lstrlenA (pInfo->szMachineName) + 1) * (bUnicodeDest ? sizeof(WCHAR) : sizeof(CHAR));
while ( LocalBufferSize < (dwBufferUsed + dwNewBuffer)) { TempBuffer = LocalBuffer; LocalBuffer = G_REALLOC(TempBuffer, LocalBufferSize + MEDIUM_BUFFER_SIZE); if (LocalBuffer == NULL) { G_FREE(szBuffer); G_FREE(TempBuffer); G_FREE(pInfo); return PDH_MEMORY_ALLOCATION_FAILURE; } LocalBufferSize += MEDIUM_BUFFER_SIZE; } dwNewBuffer = AddUniqueStringToMultiSz ( (LPVOID) LocalBuffer, pInfo->szMachineName, bUnicodeDest); } else { dwNewBuffer = 0; }
if (dwNewBuffer > 0) { // string was added so update size used.
dwBufferUsed = dwNewBuffer * (bUnicodeDest ? sizeof(WCHAR) : sizeof(CHAR)); dwItemCount++; } } } } if (dwItemCount > 0) { // then the routine was successful. Errors that occurred
// while scanning will be ignored as long as at least
// one entry was successfully read
pdhStatus = pdhBuffStatus; }
// update the buffer used or required.
if (pBuffer && dwBufferUsed <= * lpdwBufferSize) { RtlCopyMemory(pBuffer, LocalBuffer, dwBufferUsed); } else { if (pBuffer) RtlCopyMemory(pBuffer, LocalBuffer, * lpdwBufferSize); dwBufferUsed += (bUnicodeDest) ? sizeof(WCHAR) : sizeof(CHAR); pdhStatus = PDH_MORE_DATA; } *lpdwBufferSize = dwBufferUsed;
G_FREE (szBuffer); } else { pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE; } } else { // unable to read header record
pdhStatus = PDH_UNABLE_READ_LOG_HEADER; } G_FREE (pInfo); G_FREE(LocalBuffer); return pdhStatus; }
PDH_FUNCTION PdhiEnumObjectsFromTextLog ( IN PPDHI_LOG pLog, IN LPCWSTR szMachineName, IN LPVOID pBuffer, IN LPDWORD pcchBufferSize, IN DWORD dwDetailLevel, IN BOOL bUnicodeDest ) { PDH_STATUS pdhStatus; PDH_STATUS pdhBuffStatus = ERROR_SUCCESS; LPSTR szBuffer; CHAR szTemp[4]; CHAR cDelim; PPDH_COUNTER_PATH_ELEMENTS_A pInfo; DWORD dwInfoBufferSize; DWORD dwBufferUsed; DWORD dwNewBuffer; DWORD dwIndex; DWORD dwItemLength; DWORD dwBufferLength; WCHAR wszMachineName[MAX_PATH]; DWORD dwMachineNameLength; DWORD dwItemCount = 0; LPVOID LocalBuffer = NULL; LPVOID TempBuffer; DWORD LocalBufferSize = 0;
UNREFERENCED_PARAMETER (dwDetailLevel);
pInfo = (PPDH_COUNTER_PATH_ELEMENTS_A) G_ALLOC (MEDIUM_BUFFER_SIZE); if (pInfo == NULL) { return PDH_MEMORY_ALLOCATION_FAILURE; } szBuffer = &szTemp[0];
LocalBuffer = G_ALLOC(MEDIUM_BUFFER_SIZE); if (LocalBuffer == NULL) { G_FREE(pInfo); return PDH_MEMORY_ALLOCATION_FAILURE; } memset(LocalBuffer, 0, MEDIUM_BUFFER_SIZE); LocalBufferSize = MEDIUM_BUFFER_SIZE; if (pBuffer) { memset(pBuffer, 0, * pcchBufferSize); }
// what's in szReturn is not important since we'll be reading the
// data from the "last Record read" buffer
pdhStatus = PdhiReadOneTextLogRecord ( pLog, TEXTLOG_HEADER_RECORD, szBuffer, 1); // we're lying to prevent copying the record.
if (pLog->dwLastRecordRead == TEXTLOG_HEADER_RECORD) { // then the seek worked and we can use the buffer
cDelim = (CHAR)((LOWORD(pLog->dwLogFormat) == PDH_LOG_TYPE_CSV) ? COMMA_DELIMITER : TAB_DELIMITER);
dwBufferLength = lstrlenA((LPSTR)pLog->pLastRecordRead)+1; szBuffer = G_ALLOC (dwBufferLength); if (szBuffer != NULL) { dwBufferUsed = 0; dwIndex = 0; while ((dwItemLength = PdhiGetStringFromDelimitedListA( (LPSTR)pLog->pLastRecordRead, ++dwIndex, cDelim, PDHI_GSFDL_REMOVE_QUOTES | PDHI_GSFDL_REMOVE_NONPRINT, szBuffer, dwBufferLength)) != 0) {
if (dwItemLength > 0) { dwInfoBufferSize = MEDIUM_BUFFER_SIZE; // parse the path, pull the machine name out and
memset(pInfo, 0, MEDIUM_BUFFER_SIZE); pdhStatus = PdhParseCounterPathA ( szBuffer, pInfo, &dwInfoBufferSize, 0);
if (pdhStatus == ERROR_SUCCESS) { if (szBuffer[1] != '\\') { pInfo->szMachineName[0] = '.'; pInfo->szMachineName[1] = '\0'; } // add it to the list if it will fit and it's from
// the desired machine
memset(wszMachineName, 0, sizeof(WCHAR) * MAX_PATH); dwMachineNameLength = MAX_PATH; MultiByteToWideChar(_getmbcp(), 0, pInfo->szMachineName, lstrlenA(pInfo->szMachineName), (LPWSTR) wszMachineName, dwMachineNameLength); if (lstrcmpiW(szMachineName, wszMachineName) == 0) { dwNewBuffer = (lstrlenA (pInfo->szObjectName) + 1) * (bUnicodeDest ? sizeof(WCHAR) : sizeof(CHAR));
while ( LocalBufferSize < (dwBufferUsed + dwNewBuffer)) { TempBuffer = LocalBuffer; LocalBuffer = G_REALLOC(TempBuffer, LocalBufferSize + MEDIUM_BUFFER_SIZE); if (LocalBuffer == NULL) { G_FREE(szBuffer); G_FREE(TempBuffer); G_FREE(pInfo); return PDH_MEMORY_ALLOCATION_FAILURE; } LocalBufferSize += MEDIUM_BUFFER_SIZE; }
dwNewBuffer = AddUniqueStringToMultiSz ( (LPVOID) LocalBuffer, pInfo->szObjectName, bUnicodeDest);
if (dwNewBuffer > 0) { // string was added so update size used.
dwBufferUsed = dwNewBuffer * (bUnicodeDest ? sizeof(WCHAR) : sizeof(CHAR)); dwItemCount++; } } } } }
if (dwItemCount > 0) { // then the routine was successful. Errors that occurred
// while scanning will be ignored as long as at least
// one entry was successfully read
pdhStatus = pdhBuffStatus; }
// copy buffer size used or required
if (pBuffer && dwBufferUsed <= * pcchBufferSize) { RtlCopyMemory(pBuffer, LocalBuffer, dwBufferUsed); } else { if (pBuffer) RtlCopyMemory(pBuffer, LocalBuffer, * pcchBufferSize); dwBufferUsed += (bUnicodeDest) ? sizeof(WCHAR) : sizeof(CHAR); pdhStatus = PDH_MORE_DATA; }
* pcchBufferSize = dwBufferUsed;
G_FREE (szBuffer); } else { pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE; } } G_FREE (pInfo); G_FREE(LocalBuffer); return pdhStatus; }
ULONG HashCounter( LPWSTR szCounterName ) { ULONG h = 0; ULONG a = 31415; //a, b, k are primes
const ULONG k = 16381; const ULONG b = 27183; LPWSTR szThisChar;
if (szCounterName) { for (szThisChar = szCounterName; * szThisChar; szThisChar ++) { h = (a * h + ((ULONG) (* szThisChar))) % k; a = a * b % (k - 1); } } return (h % HASH_TABLE_SIZE); }
void PdhiInitCounterHashTable( IN PDHI_COUNTER_TABLE pTable ) { ZeroMemory(pTable, sizeof(PDHI_COUNTER_TABLE)); }
void PdhiResetInstanceCount( IN PDHI_COUNTER_TABLE pTable ) { PLIST_ENTRY pHeadInst; PLIST_ENTRY pNextInst; PPDHI_INSTANCE pInstance; PPDHI_INST_LIST pInstList; DWORD i;
for (i = 0; i < HASH_TABLE_SIZE; i ++) { pInstList = pTable[i]; while (pInstList != NULL) { if (! IsListEmpty(& pInstList->InstList)) { pHeadInst = & pInstList->InstList; pNextInst = pHeadInst->Flink; while (pNextInst != pHeadInst) { pInstance = CONTAINING_RECORD( pNextInst, PDHI_INSTANCE, Entry); pInstance->dwCount = 0; pNextInst = pNextInst->Flink; } } pInstList = pInstList->pNext; } } }
PDH_FUNCTION PdhiFindCounterInstList( IN PDHI_COUNTER_TABLE pHeadList, IN LPWSTR szCounter, OUT PPDHI_INST_LIST * pInstList ) { PDH_STATUS Status = ERROR_SUCCESS; ULONG lIndex = HashCounter(szCounter); PPDHI_INST_LIST pLocalList = pHeadList[lIndex]; PPDHI_INST_LIST pRtnList = NULL;
* pInstList = NULL; while (pLocalList != NULL) { if (lstrcmpiW(pLocalList->szCounter, szCounter) == 0) { pRtnList = pLocalList; break; } pLocalList = pLocalList->pNext; }
if (pRtnList == NULL) { pRtnList = G_ALLOC(sizeof(PDHI_INST_LIST) + sizeof(WCHAR) * (lstrlenW(szCounter) + 1)); if (pRtnList == NULL) { Status = PDH_MEMORY_ALLOCATION_FAILURE; goto Cleanup; } pRtnList->szCounter = (LPWSTR) (((LPBYTE) pRtnList) + sizeof(PDHI_INST_LIST)); lstrcpyW(pRtnList->szCounter, szCounter); InitializeListHead(& pRtnList->InstList);
pRtnList->pNext = pHeadList[lIndex]; pHeadList[lIndex] = pRtnList; }
Cleanup: if (Status == ERROR_SUCCESS) { * pInstList = pRtnList; } return Status; }
PDH_FUNCTION PdhiFindInstance( IN PLIST_ENTRY pHeadInst, IN LPWSTR szInstance, IN BOOLEAN bUpdateCount, OUT PPDHI_INSTANCE * pInstance ) { PDH_STATUS Status = ERROR_SUCCESS; PLIST_ENTRY pNextInst; PPDHI_INSTANCE pLocalInst; PPDHI_INSTANCE pRtnInst = NULL;
* pInstance = NULL;
if (! IsListEmpty(pHeadInst)) { pNextInst = pHeadInst->Flink; while (pNextInst != pHeadInst) { pLocalInst = CONTAINING_RECORD(pNextInst, PDHI_INSTANCE, Entry); if (lstrcmpiW(pLocalInst->szInstance, szInstance) == 0) { pRtnInst = pLocalInst; break; } pNextInst = pNextInst->Flink; } }
if (pRtnInst == NULL) { pRtnInst = G_ALLOC(sizeof(PDHI_INSTANCE) + sizeof(WCHAR) * (lstrlenW(szInstance) + 1)); if (pRtnInst == NULL) { Status = PDH_MEMORY_ALLOCATION_FAILURE; goto Cleanup; } pRtnInst->szInstance = (LPWSTR) (((LPBYTE) pRtnInst) + sizeof(PDHI_INSTANCE)); lstrcpyW(pRtnInst->szInstance, szInstance); pRtnInst->dwCount = pRtnInst->dwTotal = 0; InsertTailList(pHeadInst, & pRtnInst->Entry); }
if (bUpdateCount) { pRtnInst->dwCount ++; if (pRtnInst->dwCount > pRtnInst->dwTotal) { pRtnInst->dwTotal = pRtnInst->dwCount; } } else if (pRtnInst->dwCount == 0) { pRtnInst->dwCount = pRtnInst->dwTotal = 1; }
Cleanup: if (Status == ERROR_SUCCESS) { * pInstance = pRtnInst; } return Status; }
DWORD AddStringToMultiSz( IN LPVOID mszDest, IN LPWSTR szSource, IN BOOL bUnicodeDest ) { LPVOID szDestElem; DWORD dwReturnLength; LPSTR aszSource = NULL; DWORD dwLength;
if ((mszDest == NULL) || (szSource == NULL) || (* szSource == L'\0')) { return 0; }
if (!bUnicodeDest) { dwLength = lstrlenW(szSource) + 1; aszSource = G_ALLOC(dwLength * 3 * sizeof(CHAR)); if (aszSource != NULL) { WideCharToMultiByte(_getmbcp(), 0, szSource, lstrlenW(szSource), aszSource, dwLength, NULL, NULL); dwReturnLength = 1; } else { dwReturnLength = 0; } } else { dwReturnLength = 1; }
if (dwReturnLength > 0) { for (szDestElem = mszDest; (bUnicodeDest ? (* (LPWSTR) szDestElem != L'\0') : (* (LPSTR) szDestElem != '\0')); ) { if (bUnicodeDest) { szDestElem = (LPVOID) ((LPWSTR) szDestElem + (lstrlenW((LPCWSTR) szDestElem) + 1)); } else { szDestElem = (LPVOID) ((LPSTR) szDestElem + (lstrlenA((LPCSTR) szDestElem) + 1)); } }
if (bUnicodeDest) { lstrcpyW ((LPWSTR)szDestElem, szSource); szDestElem = (LPVOID)((LPWSTR)szDestElem + lstrlenW(szSource) + 1); * ((LPWSTR)szDestElem) = L'\0'; dwReturnLength = (DWORD)((LPWSTR)szDestElem - (LPWSTR)mszDest); } else { lstrcpyA ((LPSTR)szDestElem, aszSource); szDestElem = (LPVOID)((LPSTR)szDestElem + lstrlenA(szDestElem) + 1); * ((LPSTR)szDestElem) = '\0'; dwReturnLength = (DWORD)((LPSTR)szDestElem - (LPSTR)mszDest); } }
if (aszSource != NULL) { G_FREE (aszSource); }
return (DWORD) dwReturnLength; }
PDH_FUNCTION PdhiEnumObjectItemsFromTextLog ( IN PPDHI_LOG pLog, IN LPCWSTR szMachineName, IN LPCWSTR szObjectName, IN PDHI_COUNTER_TABLE CounterTable, IN DWORD dwDetailLevel, IN DWORD dwFlags ) { PDH_STATUS pdhStatus; PDH_STATUS pdhBuffStatus = ERROR_SUCCESS; LPSTR szBuffer; CHAR szTemp[4]; CHAR cDelim; PPDH_COUNTER_PATH_ELEMENTS_A pInfo = NULL; DWORD dwInfoBufferSize; DWORD dwIndex; DWORD dwItemLength; DWORD dwBufferLength; WCHAR wszMachineName[MAX_PATH]; WCHAR wszObjectName[MAX_PATH]; WCHAR wszCounterName[MAX_PATH]; WCHAR wszInstanceName[MAX_PATH]; CHAR szFullInstanceName[MAX_PATH]; DWORD dwMachineNameLength; DWORD dwObjectNameLength; DWORD dwCounterNameLength; DWORD dwInstanceNameLength; DWORD dwItemCount = 0; CHAR szIndexNumber[20];
PPDHI_INSTANCE pInstance; PPDHI_INST_LIST pInstList;
UNREFERENCED_PARAMETER (dwDetailLevel); UNREFERENCED_PARAMETER (dwFlags);
pInfo = (PPDH_COUNTER_PATH_ELEMENTS_A) G_ALLOC (MEDIUM_BUFFER_SIZE); if (pInfo == NULL) { pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE; goto Cleanup; }
szBuffer = & szTemp[0];
// what's in szReturn is not important since we'll be reading the
// data from the "last Record read" buffer
pdhStatus = PdhiReadOneTextLogRecord ( pLog, TEXTLOG_HEADER_RECORD, szBuffer, 1); // we're lying to prevent copying the record.
if (pLog->dwLastRecordRead == TEXTLOG_HEADER_RECORD) { // then the seek worked and we can use the buffer
cDelim = (CHAR)((LOWORD(pLog->dwLogFormat) == PDH_LOG_TYPE_CSV) ? COMMA_DELIMITER : TAB_DELIMITER);
dwBufferLength = pLog->dwMaxRecordSize+1; szBuffer = G_ALLOC (dwBufferLength); if (szBuffer != NULL) { dwIndex = 0; while ((dwItemLength = PdhiGetStringFromDelimitedListA( (LPSTR)pLog->pLastRecordRead, ++dwIndex, cDelim, PDHI_GSFDL_REMOVE_QUOTES | PDHI_GSFDL_REMOVE_NONPRINT, szBuffer, dwBufferLength)) != 0) { if (dwItemLength > 0) { dwInfoBufferSize = MEDIUM_BUFFER_SIZE; // parse the path, pull the machine name out and
memset(pInfo, 0, MEDIUM_BUFFER_SIZE); pdhStatus = PdhParseCounterPathA ( szBuffer, pInfo, &dwInfoBufferSize, 0);
if (pdhStatus == ERROR_SUCCESS) { if (szBuffer[1] != '\\') { pInfo->szMachineName[0] = '.'; pInfo->szMachineName[1] = '\0'; } // add it to the list if it will fit and it's from
// the desired machine
memset(wszMachineName, 0, sizeof(WCHAR) * MAX_PATH); dwMachineNameLength = MAX_PATH; MultiByteToWideChar(_getmbcp(), 0, pInfo->szMachineName, lstrlenA(pInfo->szMachineName), (LPWSTR) wszMachineName, dwMachineNameLength); if (lstrcmpiW(wszMachineName, szMachineName) == 0) { memset(wszObjectName, 0, sizeof(WCHAR) * MAX_PATH); dwObjectNameLength = MAX_PATH; MultiByteToWideChar(_getmbcp(), 0, pInfo->szObjectName, lstrlenA(pInfo->szObjectName), (LPWSTR) wszObjectName, dwObjectNameLength); if (lstrcmpiW(wszObjectName, szObjectName) == 0) { memset(wszCounterName, 0, sizeof(WCHAR) * MAX_PATH); dwCounterNameLength = MAX_PATH; MultiByteToWideChar(_getmbcp(), 0, pInfo->szCounterName, lstrlenA(pInfo->szCounterName), (LPWSTR) wszCounterName, dwCounterNameLength); pdhBuffStatus = PdhiFindCounterInstList( CounterTable, wszCounterName, & pInstList); if (pdhBuffStatus != ERROR_SUCCESS) { continue; }
if ( pInfo->szInstanceName != NULL && pInfo->szInstanceName[0] != '\0') { if (pInfo->szParentInstance == NULL) { // then the name is just the instance
szFullInstanceName[0] = 0; } else { // we need to build the instance string from
// the parent and the child
lstrcpyA (szFullInstanceName, pInfo->szParentInstance); lstrcatA (szFullInstanceName, caszSlash); }
lstrcatA (szFullInstanceName, pInfo->szInstanceName);
if ((LONG)pInfo->dwInstanceIndex > 0) { // append instance index to instance name if it's > 0
szIndexNumber[0] = POUNDSIGN_A; _ultoa (pInfo->dwInstanceIndex, &szIndexNumber[1], 10); lstrcatA (szFullInstanceName, szIndexNumber); }
memset(wszInstanceName, 0, sizeof(WCHAR) * MAX_PATH); dwInstanceNameLength = MAX_PATH; MultiByteToWideChar(_getmbcp(), 0, szFullInstanceName, lstrlenA(szFullInstanceName), (LPWSTR) wszInstanceName, dwInstanceNameLength); pdhBuffStatus = PdhiFindInstance( & pInstList->InstList, wszInstanceName, TRUE, & pInstance); }
if (pdhBuffStatus == ERROR_SUCCESS) { dwItemCount++; } } // else not this object
} // else not this machine
} } }
if (dwItemCount > 0) { // then the routine was successful. Errors that occurred
// while scanning will be ignored as long as at least
// one entry was successfully read
pdhStatus = pdhBuffStatus; }
G_FREE (szBuffer); } else { pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE; } }
Cleanup: if (pInfo) { G_FREE (pInfo); }
return pdhStatus; }
PDH_FUNCTION PdhiGetMatchingTextLogRecord ( IN PPDHI_LOG pLog, IN LONGLONG *pStartTime, IN LPDWORD pdwIndex ) { PDH_STATUS pdhStatus = ERROR_SUCCESS; CHAR szSmallBuffer[MAX_PATH]; DWORD dwRecordId = TEXTLOG_FIRST_DATA_RECORD; CHAR cDelim; FILETIME RecordTimeStamp; LONGLONG RecordTimeValue; LONGLONG LastTimeValue = 0;
// read the first data record in the log file
// note that the record read is not copied to the local buffer
// rather the internal buffer is used in "read-only" mode
cDelim = (CHAR)((LOWORD(pLog->dwLogFormat) == PDH_LOG_TYPE_CSV) ? COMMA_DELIMITER : TAB_DELIMITER);
if ((*pStartTime & 0xFFFFFFFF00000000) == 0xFFFFFFFF00000000) { dwRecordId = (DWORD)(*pStartTime & 0x00000000FFFFFFFF); LastTimeValue = *pStartTime; if (dwRecordId == 0) return PDH_ENTRY_NOT_IN_LOG_FILE; } else { dwRecordId = TEXTLOG_FIRST_DATA_RECORD; }
pdhStatus = PdhiReadOneTextLogRecord ( pLog, dwRecordId, szSmallBuffer, 1); // to prevent copying the record
while ( pdhStatus == ERROR_SUCCESS || pdhStatus == PDH_MORE_DATA || pdhStatus == PDH_INSUFFICIENT_BUFFER) { if (PdhiGetStringFromDelimitedListA( (LPSTR)pLog->pLastRecordRead, 0, // timestamp is first entry
cDelim, PDHI_GSFDL_REMOVE_QUOTES | PDHI_GSFDL_REMOVE_NONPRINT, szSmallBuffer, MAX_PATH) > 0) { // convert ASCII timestamp to LONGLONG value for comparison
PdhiDateStringToFileTimeA (szSmallBuffer, &RecordTimeStamp); RecordTimeValue = MAKELONGLONG(RecordTimeStamp.dwLowDateTime, RecordTimeStamp.dwHighDateTime); if ((*pStartTime == RecordTimeValue) || (*pStartTime == 0)) { // found the match so bail here
LastTimeValue = RecordTimeValue; break; } else if (RecordTimeValue > *pStartTime) { // then this is the first record > than the desired time
// so the desired value is the one before this one
// unless it's the first data record of the log
if (dwRecordId > TEXTLOG_FIRST_DATA_RECORD) { dwRecordId--; } else { // this hasnt' been initialized yet.
LastTimeValue = RecordTimeValue; } break; } else { // save value for next trip through loop
LastTimeValue = RecordTimeValue; // advance record counter and try the next entry
dwRecordId++; } } else { // no timestamp field so ignore this record.
} // read the next record in the file
pdhStatus = PdhiReadOneTextLogRecord ( pLog, dwRecordId, szSmallBuffer, 1); // to prevent copying the record
} if ( pdhStatus == ERROR_SUCCESS || pdhStatus == PDH_MORE_DATA || pdhStatus == PDH_INSUFFICIENT_BUFFER) { // then dwRecordId is the desired entry
*pdwIndex = dwRecordId; *pStartTime = LastTimeValue; pdhStatus = ERROR_SUCCESS; } else { pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE; } return pdhStatus; }
PDH_FUNCTION PdhiGetCounterValueFromTextLog ( IN PPDHI_LOG pLog, IN DWORD dwIndex, IN PERFLIB_COUNTER *pPath, IN PPDH_RAW_COUNTER pValue ) { PDH_STATUS pdhStatus = ERROR_SUCCESS; CHAR szSmallBuffer[MAX_PATH]; CHAR cDelim; FILETIME RecordTimeStamp; DOUBLE dValue;
memset (&RecordTimeStamp, 0, sizeof(RecordTimeStamp)); // read the first data record in the log file
// note that the record read is not copied to the local buffer
// rather the internal buffer is used in "read-only" mode
cDelim = (CHAR)((LOWORD(pLog->dwLogFormat) == PDH_LOG_TYPE_CSV) ? COMMA_DELIMITER : TAB_DELIMITER);
pdhStatus = PdhiReadOneTextLogRecord ( pLog, dwIndex, szSmallBuffer, 1); // to prevent copying the record
if ( pdhStatus == ERROR_SUCCESS || pdhStatus == PDH_MORE_DATA || pdhStatus == PDH_INSUFFICIENT_BUFFER) { // the specified entry in the log is the dwCounterId value
// in the perflib buffer
if (PdhiGetStringFromDelimitedListA ( (LPSTR)pLog->pLastRecordRead, 0, // timestamp is first entry
cDelim, PDHI_GSFDL_REMOVE_QUOTES | PDHI_GSFDL_REMOVE_NONPRINT, szSmallBuffer, MAX_PATH) > 0) { // convert time stamp string to FileTime value
PdhiDateStringToFileTimeA (szSmallBuffer, &RecordTimeStamp); } else { RecordTimeStamp.dwLowDateTime = 0; RecordTimeStamp.dwHighDateTime = 0; }
if (PdhiGetStringFromDelimitedListA( (LPSTR) pLog->pLastRecordRead, pPath->dwCounterId, cDelim, PDHI_GSFDL_REMOVE_QUOTES | PDHI_GSFDL_REMOVE_NONPRINT, szSmallBuffer, MAX_PATH) > 0) { // convert ASCII value to Double Float
if (szSmallBuffer[0] >= '0' && szSmallBuffer[0] <= '9') { dValue = atof(szSmallBuffer); pValue->CStatus = PDH_CSTATUS_VALID_DATA; } else { dValue = 0.0; pValue->CStatus = PDH_CSTATUS_NO_INSTANCE; } pdhStatus = ERROR_SUCCESS; pValue->TimeStamp = RecordTimeStamp; (double)pValue->FirstValue = dValue; pValue->SecondValue = 0; pValue->MultiCount = 1; } else { pdhStatus = ERROR_SUCCESS; // update counter buffer
pValue->CStatus = PDH_CSTATUS_INVALID_DATA; pValue->TimeStamp = RecordTimeStamp; (double)pValue->FirstValue = (double)0.0f; pValue->SecondValue = 0; pValue->MultiCount = 1; } } else { if (pdhStatus == PDH_END_OF_LOG_FILE) { pdhStatus = PDH_NO_MORE_DATA; } // unable to find entry in the log file
pValue->CStatus = PDH_CSTATUS_INVALID_DATA; pValue->TimeStamp = RecordTimeStamp; (double)pValue->FirstValue = (double)0.0f; pValue->SecondValue = 0; pValue->MultiCount = 1; } return pdhStatus; }
PDH_FUNCTION PdhiGetTimeRangeFromTextLog ( IN PPDHI_LOG pLog, IN LPDWORD pdwNumEntries, IN PPDH_TIME_INFO pInfo, IN LPDWORD pdwBufferSize ) /*++
the first entry in the buffer returned is the total time range covered in the file, if there are multiple time blocks in the log file, then subsequent entries will identify each segment in the file. --*/ { PDH_STATUS pdhStatus; LONGLONG llStartTime = MAX_TIME_VALUE; LONGLONG llEndTime = MIN_TIME_VALUE; LONGLONG llThisTime = 0; CHAR cDelim;
DWORD dwThisRecord = TEXTLOG_FIRST_DATA_RECORD; DWORD dwValidEntries = 0;
CHAR szSmallBuffer[MAX_PATH]; // read the first data record in the log file
// note that the record read is not copied to the local buffer
// rather the internal buffer is used in "read-only" mode
cDelim = (CHAR)((LOWORD(pLog->dwLogFormat) == PDH_LOG_TYPE_CSV) ? COMMA_DELIMITER : TAB_DELIMITER);
pdhStatus = PdhiReadOneTextLogRecord ( pLog, dwThisRecord, szSmallBuffer, 1); // to prevent copying the record
while (pdhStatus == ERROR_SUCCESS || pdhStatus == PDH_MORE_DATA || pdhStatus == PDH_INSUFFICIENT_BUFFER) { if (PdhiGetStringFromDelimitedListA ( (LPSTR)pLog->pLastRecordRead, 0, // timestamp is first entry
cDelim, PDHI_GSFDL_REMOVE_QUOTES | PDHI_GSFDL_REMOVE_NONPRINT, szSmallBuffer, MAX_PATH) > 0) { // convert ASCII timestamp to LONGLONG value for comparison
PdhiDateStringToFileTimeA (szSmallBuffer, (LPFILETIME)&llThisTime); if (llThisTime < llStartTime) { llStartTime = llThisTime; } if (llThisTime > llEndTime) { llEndTime = llThisTime; } dwValidEntries++; } else { // no timestamp field so ignore this record.
} // read the next record in the file
pdhStatus = PdhiReadOneTextLogRecord ( pLog, ++dwThisRecord, szSmallBuffer, 1); // to prevent copying the record
}
if (pdhStatus == PDH_END_OF_LOG_FILE) { // then the whole file was read so update the args.
if (*pdwBufferSize >= sizeof(PDH_TIME_INFO)) { *(LONGLONG *)(&pInfo->StartTime) = llStartTime; *(LONGLONG *)(&pInfo->EndTime) = llEndTime; pInfo->SampleCount = dwValidEntries; *pdwBufferSize = sizeof(PDH_TIME_INFO); *pdwNumEntries = 1; } else { pdhStatus = PDH_MORE_DATA; } pdhStatus = ERROR_SUCCESS; } else { pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE; }
return pdhStatus; }
PDH_FUNCTION PdhiReadRawTextLogRecord ( IN PPDHI_LOG pLog, IN FILETIME *ftRecord, IN PPDH_RAW_LOG_RECORD pBuffer, IN LPDWORD pdwBufferLength ) { PDH_STATUS pdhStatus = ERROR_SUCCESS; LONGLONG llStartTime; DWORD dwIndex = 0; DWORD dwSizeRequired; DWORD dwLocalRecordLength; // including terminating NULL
llStartTime = *(LONGLONG *)ftRecord;
pdhStatus = PdhiGetMatchingTextLogRecord ( pLog, &llStartTime, &dwIndex);
// copy results from internal log buffer if it'll fit.
if (pdhStatus == ERROR_SUCCESS) { dwLocalRecordLength = (lstrlenA ((LPSTR)pLog->pLastRecordRead)) * sizeof (CHAR); dwSizeRequired = sizeof (PDH_RAW_LOG_RECORD) - sizeof (UCHAR) + dwLocalRecordLength;
if (*pdwBufferLength >= dwSizeRequired) { pBuffer->dwRecordType = (DWORD)(LOWORD(pLog->dwLogFormat)); pBuffer->dwItems = dwLocalRecordLength; // copy it
memcpy (&pBuffer->RawBytes[0], pLog->pLastRecordRead, dwLocalRecordLength); pBuffer->dwStructureSize = dwSizeRequired;
} else { pdhStatus = PDH_MORE_DATA; }
*pdwBufferLength = dwSizeRequired; }
return pdhStatus; }
PDH_FUNCTION PdhiListHeaderFromTextLog ( IN PPDHI_LOG pLogFile, IN LPVOID pBufferArg, IN LPDWORD pcchBufferSize, IN BOOL bUnicode ) { LPVOID pTempBuffer = NULL; LPVOID pOldBuffer; DWORD dwTempBufferSize; CHAR szLocalPathBuffer[MAX_PATH];
DWORD dwIndex; DWORD dwBufferRemaining; LPVOID pNextChar; DWORD dwReturnSize;
CHAR cDelimiter;
PDH_STATUS pdhStatus = ERROR_SUCCESS; // read the header record and enum the machine name from the entries
if (pLogFile->dwMaxRecordSize == 0) { // no size is defined so start with 64K
pLogFile->dwMaxRecordSize = 0x010000; }
dwTempBufferSize = pLogFile->dwMaxRecordSize; pTempBuffer = G_ALLOC (dwTempBufferSize); assert (pTempBuffer != NULL); if (pTempBuffer == NULL) { assert (GetLastError() == ERROR_SUCCESS); return PDH_MEMORY_ALLOCATION_FAILURE; }
cDelimiter = (CHAR)((LOWORD(pLogFile->dwLogFormat) == PDH_LOG_TYPE_CSV) ? COMMA_DELIMITER : TAB_DELIMITER);
// read in the catalog record
while ((pdhStatus = PdhiReadOneTextLogRecord (pLogFile, TEXTLOG_HEADER_RECORD, pTempBuffer, dwTempBufferSize)) != ERROR_SUCCESS) { if ((pdhStatus == PDH_INSUFFICIENT_BUFFER) || (pdhStatus == PDH_MORE_DATA)){ // read the 1st WORD to see if this is a valid record
pLogFile->dwMaxRecordSize *= 2; // realloc a new buffer
pOldBuffer = pTempBuffer; pTempBuffer = G_REALLOC (pOldBuffer, dwTempBufferSize); assert (pTempBuffer != NULL);
if (pTempBuffer == NULL) { // return memory error
G_FREE(pOldBuffer); assert (GetLastError() == ERROR_SUCCESS); pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE; break; } } else { // some other error was returned so
// return error from read function
break; } }
if (pdhStatus == ERROR_SUCCESS) { // parse header record into MSZ
dwIndex = 1; dwBufferRemaining = *pcchBufferSize; pNextChar = pBufferArg; // initialize first character in buffer
if (bUnicode) { *(PWCHAR)pNextChar = 0; } else { *(LPBYTE)pNextChar = 0; }
do { dwReturnSize = PdhiGetStringFromDelimitedListA ( (LPSTR)pTempBuffer, dwIndex, cDelimiter, PDHI_GSFDL_REMOVE_QUOTES | PDHI_GSFDL_REMOVE_NONPRINT, szLocalPathBuffer, MAX_PATH); if (dwReturnSize > 0) { // copy to buffer
if (dwReturnSize < dwBufferRemaining) { if (bUnicode) { MultiByteToWideChar(_getmbcp(), 0, szLocalPathBuffer, lstrlenA(szLocalPathBuffer), (LPWSTR) pNextChar, dwReturnSize); pNextChar = (LPVOID)((PWCHAR)pNextChar + dwReturnSize); *(PWCHAR)pNextChar = 0; pNextChar = (LPVOID)((PWCHAR)pNextChar + 1); } else { lstrcpyA ((LPSTR)pNextChar, szLocalPathBuffer); pNextChar = (LPVOID)((LPBYTE)pNextChar + dwReturnSize); *(LPBYTE)pNextChar = 0; pNextChar = (LPVOID)((PCHAR)pNextChar + 1); } dwBufferRemaining -= dwReturnSize; } else { pdhStatus = PDH_MORE_DATA; } dwIndex++; } } while (dwReturnSize > 0); // end loop
// add MSZ terminator
if (1 < dwBufferRemaining) { if (bUnicode) { *(PWCHAR)pNextChar = 0; pNextChar = (LPVOID)((PWCHAR)pNextChar + 1); } else { *(LPBYTE)pNextChar = 0; pNextChar = (LPVOID)((PCHAR)pNextChar + 1); } dwBufferRemaining -= dwReturnSize; pdhStatus = ERROR_SUCCESS; } else { pdhStatus = PDH_MORE_DATA; } } if (pTempBuffer) G_FREE(pTempBuffer);
return pdhStatus; }
|