/*++ Copyright (C) 1996-1999 Microsoft Corporation Module Name: log_wmi.c Abstract: --*/ #include #include #include #include #include #include #include #include #include "pdhidef.h" #include "perfdata.h" #include "log_bin.h" #include "log_wmi.h" #include "strings.h" #include "pdhmsg.h" #pragma warning ( disable : 4201 ) #include #include #include #pragma warning ( default : 4201 ) GUID PdhTransactionGuid = // 933f3bb3-943e-490d-9ced-3cbb14c14479 { 0x933f3bb3, 0x943e, 0x490d, 0x9c, 0xed, 0x3c, 0xbb, 0x14, 0xc1, 0x44, 0x79 }; PDHI_BINARY_LOG_RECORD_HEADER PdhNullCounterHeader = { BINLOG_TYPE_DATA_PSEUDO, 48 }; PDH_RAW_COUNTER PdhNullCounter = { 0, // CStatus { 0, 0 }, // TimeStamp 0, // FirstValue 0, // SecondValue 0 // MultiCount }; #define PDH_MAX_LOGFILES 32 #define PDH_MAX_PATH 1024 #define PDH_BLOCK_BUFFER_SIZE 8000 #define PDH_WMI_BUFFER_SIZE 64 #define PDH_WMI_BUFFER_SIZE_BYTE 64 * 1024 #define PDH_LOG_HEADER_EVENT 0x20 #define PDH_LOG_DATA_BLOCK_EVENT 0x22 #define PDH_LOG_CATALOG_LIST_EVENT 0x23 #define PDH_LOG_COUNTER_STRING_EVENT 0x24 #define PDH_EVENT_VERSION 60 #define PDH_WMI_MAX_BUFFERS 512 #define PDH_WMI_DEFAULT_BUFFERS 32 #define PDH_WMI_BUFFER_INCREMENT 16 #define PDH_RESOURCE_NAME L"MofResource" #define TIME_DELTA 100000 TRACEHANDLE PdhTraceRegistrationHandle = (TRACEHANDLE) 0; // For PDH WMI event trace logfile output // typedef struct _PDH_WMI_LOG_INFO { DWORD dwLogVersion; // version stamp DWORD dwFlags; // option flags } PDH_WMI_LOG_INFO, *PPDH_WMI_LOG_INFO; typedef struct _PDH_EVENT_TRACE_PROPERTIES { EVENT_TRACE_PROPERTIES LoggerInfo; WCHAR LoggerName[PDH_MAX_PATH]; WCHAR LogFileName[PDH_MAX_PATH]; GUID LogFileGuid; LONGLONG TimeStamp; LPWSTR MachineList; DWORD MachineListSize; BOOLEAN bHeaderEvent; } PDH_EVENT_TRACE_PROPERTIES, * PPDH_EVENT_TRACE_PROPERTIES; typedef struct _PDH_WMI_EVENT_TRACE { EVENT_TRACE_HEADER EventHeader; MOF_FIELD MofFields[4]; } PDH_WMI_EVENT_TRACE, * PPDH_WMI_EVENT_TRACE; // For PDH WMI event trace logfile input // typedef enum _PDH_PROCESS_TRACE_STATE { PdhProcessTraceNormal, PdhProcessTraceRewind, PdhProcessTraceComplete, PdhProcessTraceEnd, PdhProcessTraceExit } PDH_PROCESS_TRACE_STATE; typedef struct _PDH_WMI_PERF_MACHINE { LIST_ENTRY Entry; LIST_ENTRY LogObjectList; LPWSTR pszBuffer; DWORD dwLastId; DWORD dwBufSize; LPWSTR * ptrStrAry; } PDH_WMI_PERF_MACHINE, * PPDH_WMI_PERF_MACHINE; typedef struct _PDH_WMI_PERF_OBJECT { LIST_ENTRY Entry; DWORD dwObjectId; LPWSTR szObjectName; PVOID ptrBuffer; } PDH_WMI_PERF_OBJECT, * PPDH_WMI_PERF_OBJECT; typedef struct _PDH_COUNTER_PATH { LIST_ENTRY Entry; ULONGLONG TimeStamp; PVOID CounterPathBuffer; ULONG CounterPathSize; ULONG CounterCount; } PDH_COUNTER_PATH, * PPDH_COUNTER_PATH; typedef struct _PDH_WMI_LOGFILE_INFO { GUID LogFileGuid; LIST_ENTRY CounterPathList; LIST_ENTRY PerfMachineList; ULONGLONG TimeStart; ULONGLONG TimeEnd; ULONGLONG TimeFreq; ULONGLONG TimePrev; PVOID DataBlock; ULONG ValidEntries; ULONG DataBlockSize; ULONG DataBlockAlloc; ULONG ulNumDataBlocks; ULONG ulDataBlocksCopied; ULONG ulCounters; } PDH_WMI_LOGFILE_INFO, * PPDH_WMI_LOGFILE_INFO; typedef struct _PDH_LOGGER_CONTEXT { PDH_WMI_LOGFILE_INFO LogInfo[PDH_MAX_LOGFILES]; TRACEHANDLE LogFileHandle[PDH_MAX_LOGFILES]; LPWSTR LogFileName[PDH_MAX_LOGFILES]; ULONGLONG TimeFreq; HANDLE hThreadWork; HANDLE hSyncPDH; HANDLE hSyncWMI; PVOID CounterPathBuffer; PVOID tmpBuffer; PDH_PROCESS_TRACE_STATE LoggerState; ULONG LogFileCount; ULONG LoggerCount; ULONG RefCount; DWORD dwThread; BOOLEAN bCounterPathChanged; BOOLEAN bFirstDataBlockRead; BOOLEAN bDataBlockProcessed; BOOLEAN bFirstRun; } PDH_LOGGER_CONTEXT, * PPDH_LOGGER_CONTEXT; PPDH_LOGGER_CONTEXT ContextTable[PDH_MAX_LOGFILES]; DWORD ContextCount = 0; HANDLE hPdhContextMutex; typedef struct _PDH_DATA_BLOCK_TRANSFER { ULONGLONG CurrentTime; PVOID pRecord; DWORD dwCurrentSize; PDH_STATUS Status; } PDH_DATA_BLOCK_TRANSFER, * PPDH_DATA_BLOCK_TRANSFER; PDH_DATA_BLOCK_TRANSFER DataBlockInfo = { 0, NULL, 0, ERROR_SUCCESS }; void GuidToString(PWCHAR s, LPGUID piid) { swprintf(s, L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", piid->Data1, piid->Data2, piid->Data3, piid->Data4[0], piid->Data4[1], piid->Data4[2], piid->Data4[3], piid->Data4[4], piid->Data4[5], piid->Data4[6], piid->Data4[7]); } PPDH_LOGGER_CONTEXT PdhWmiGetCurrentContext( IN DWORD dwLine) { PPDH_LOGGER_CONTEXT CurrentContext = NULL; DWORD dwThread = GetCurrentThreadId(); DWORD i; if (WAIT_FOR_AND_LOCK_MUTEX(hPdhContextMutex) == ERROR_SUCCESS) { for (i = 0; i < ContextCount; i ++) { if (ContextTable[i]->dwThread == dwThread) { CurrentContext = ContextTable[i]; break; } } RELEASE_MUTEX(hPdhContextMutex); } return CurrentContext; } DWORD PdhWmiGetLoggerContext( IN DWORD dwLine, IN PPDH_LOGGER_CONTEXT pLoggerContext) { DWORD i = ContextCount; if (pLoggerContext != NULL) { if (WAIT_FOR_AND_LOCK_MUTEX(hPdhContextMutex) == ERROR_SUCCESS) { for (i = 0; i < ContextCount; i ++) { if (ContextTable[i] == pLoggerContext) { break; } } RELEASE_MUTEX(hPdhContextMutex); } } return i; } #define GetCurrentContext() PdhWmiGetCurrentContext(__LINE__) #define GetLoggerContext(X) PdhWmiGetLoggerContext(__LINE__,X) #if 0 PDH_FUNCTION PdhiBuildEmptyBlock( IN PPDHI_LOG pLog, IN LONGLONG TimeStamp, OUT ULONG * lenMofData, OUT PVOID * ptrMofData) { PDH_STATUS pdhStatus = ERROR_SUCCESS; PPDHI_COUNTER pThisCounter; PPDHI_BINARY_LOG_RECORD_HEADER pLogCounterBuffer = NULL; PPDHI_BINARY_LOG_RECORD_HEADER pThisLogCounter = NULL; PPDH_RAW_COUNTER pSingleCounter; PPDHI_RAW_COUNTER_ITEM_BLOCK pMultiCounter; PPERF_DATA_BLOCK pObjectCounter; DWORD dwBufSize = 0; if (pLog->pQuery == NULL || pLog->pQuery->pCounterListHead == NULL) { pdhStatus = PDH_NO_DATA; goto Cleanup; } pThisCounter = pLog->pQuery->pCounterListHead; do { DWORD dwType = (pThisCounter->dwFlags & PDHIC_COUNTER_OBJECT) ? (PDHIC_COUNTER_OBJECT) : ( (pThisCounter->dwFlags & PDHIC_MULTI_INSTANCE) ? (PDHIC_MULTI_INSTANCE) : (0)); DWORD dwCtrBufSize = sizeof(PDHI_BINARY_LOG_RECORD_HEADER); DWORD dwNewSize; int nItem; switch (dwType) { case PDHIC_MULTI_INSTANCE: dwCtrBufSize += sizeof(PDHI_RAW_COUNTER_ITEM_BLOCK); break; case PDHIC_COUNTER_OBJECT: dwCtrBufSize += sizeof(PERF_DATA_BLOCK); break; default: dwCtrBufSize += sizeof(PDH_RAW_COUNTER); break; } if (pLogCounterBuffer == NULL) { dwBufSize = (dwCtrBufSize + sizeof(PDHI_BINARY_LOG_RECORD_HEADER)); pLogCounterBuffer = G_ALLOC(dwBufSize); if (pLogCounterBuffer == NULL) { pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE; break; } pThisLogCounter = (PPDHI_BINARY_LOG_RECORD_HEADER) ( ((PUCHAR) pLogCounterBuffer) + sizeof(PDHI_BINARY_LOG_RECORD_HEADER)); } else { PPDHI_BINARY_LOG_RECORD_HEADER ptrTemp = pLogCounterBuffer; dwNewSize = (dwBufSize + dwCtrBufSize); pLogCounterBuffer = G_REALLOC(ptrTemp, dwNewSize); if (pLogCounterBuffer == NULL) { G_FREE(ptrTemp); pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE; break; } pThisLogCounter = (PPDHI_BINARY_LOG_RECORD_HEADER) ((LPBYTE) pLogCounterBuffer + dwBufSize); dwBufSize += (USHORT) dwCtrBufSize; } assert (dwCtrBufSize < 0x00010000); pThisLogCounter->dwLength = LOWORD(dwCtrBufSize); if (dwType == PDHIC_COUNTER_OBJECT) { FILETIME tmpFileTime; pThisLogCounter->dwType = BINLOG_TYPE_DATA_LOC_OBJECT; pObjectCounter = (PPERF_DATA_BLOCK) ((LPBYTE) pThisLogCounter + sizeof(PDHI_BINARY_LOG_RECORD_HEADER)); pObjectCounter->Signature[0] = L'P'; pObjectCounter->Signature[1] = L'E'; pObjectCounter->Signature[2] = L'R'; pObjectCounter->Signature[3] = L'F'; pObjectCounter->LittleEndian = TRUE; pObjectCounter->Version = PERF_DATA_VERSION; pObjectCounter->Revision = PERF_DATA_REVISION; pObjectCounter->TotalByteLength = sizeof(PERF_DATA_BLOCK); pObjectCounter->NumObjectTypes = 1; pObjectCounter->DefaultObject = pThisCounter->plCounterInfo.dwObjectId; pObjectCounter->SystemNameLength = 0; pObjectCounter->SystemNameOffset = 0; pObjectCounter->HeaderLength = sizeof(PERF_DATA_BLOCK); pObjectCounter->PerfTime.QuadPart = 0; pObjectCounter->PerfFreq.QuadPart = 0; pObjectCounter->PerfTime100nSec.QuadPart = 0; tmpFileTime.dwLowDateTime = LODWORD(TimeStamp); tmpFileTime.dwHighDateTime = HIDWORD(TimeStamp); FileTimeToSystemTime(& tmpFileTime, & pObjectCounter->SystemTime); } else if (dwType == PDHIC_MULTI_INSTANCE) { pThisLogCounter->dwType = BINLOG_TYPE_DATA_MULTI; pMultiCounter = (PPDHI_RAW_COUNTER_ITEM_BLOCK) ((LPBYTE) pThisLogCounter + sizeof(PDHI_BINARY_LOG_RECORD_HEADER)); ZeroMemory(pMultiCounter, sizeof(PDHI_RAW_COUNTER_ITEM_BLOCK)); pMultiCounter->CStatus = ERROR_SUCCESS; pMultiCounter->TimeStamp.dwLowDateTime = LODWORD(TimeStamp); pMultiCounter->TimeStamp.dwHighDateTime = HIDWORD(TimeStamp); } else { pThisLogCounter->dwType = BINLOG_TYPE_DATA_SINGLE; pSingleCounter = (PPDH_RAW_COUNTER) ((LPBYTE) pThisLogCounter + sizeof(PDHI_BINARY_LOG_RECORD_HEADER)); ZeroMemory(pSingleCounter, sizeof(PDH_RAW_COUNTER)); pSingleCounter->CStatus = ERROR_SUCCESS; pSingleCounter->TimeStamp.dwLowDateTime = LODWORD(TimeStamp); pSingleCounter->TimeStamp.dwHighDateTime = HIDWORD(TimeStamp); } pThisCounter = pThisCounter->next.flink; // go to next in list } while (pThisCounter != pLog->pQuery->pCounterListHead); if (pLogCounterBuffer) { pLogCounterBuffer->dwType = BINLOG_TYPE_DATA; pLogCounterBuffer->dwLength = dwBufSize; } Cleanup: * lenMofData = dwBufSize; * ptrMofData = pLogCounterBuffer; return pdhStatus; } #endif PDH_FUNCTION PdhWmiTraceEvent( IN PPDHI_LOG pLog, IN ULONG PdhEventType, IN ULONGLONG TimeStamp, IN ULONG lenMofData, IN PVOID ptrMofData); PDH_FUNCTION PdhiBuildPerfCounterList( IN PPDHI_LOG pLog, IN PPDH_EVENT_TRACE_PROPERTIES LoggerInfo, IN PPDHI_COUNTER pCounter) { PDH_STATUS Status = ERROR_SUCCESS; PPERF_MACHINE pMachine = pCounter->pQMachine->pMachine; LPWSTR * pString = pMachine->szPerfStrings; BYTE * pType = pMachine->typePerfStrings; DWORD dwLastId = pMachine->dwLastPerfString; DWORD i; DWORD dwBufSize = 0; LPWSTR pszBuffer = NULL; LPWSTR pszCurrent; BOOLEAN bNewEvent = TRUE; if (LoggerInfo->MachineList != NULL) { pszCurrent = LoggerInfo->MachineList; while (* pszCurrent != L'\0') { if (lstrcmpiW(pszCurrent, pMachine->szName) == 0) { // Machine Perf Counter List already there, bail out. // goto Cleanup; } pszCurrent += (lstrlenW(pszCurrent) + 1); } } if (LoggerInfo->MachineList != NULL) { LPWSTR pszTemp = LoggerInfo->MachineList; LoggerInfo->MachineList = G_REALLOC( pszTemp, sizeof(WCHAR) * (LoggerInfo->MachineListSize + (lstrlenW(pMachine->szName) + 1))); if (LoggerInfo->MachineList != NULL) { pszCurrent = LoggerInfo->MachineList + (LoggerInfo->MachineListSize - 1); LoggerInfo->MachineListSize += (lstrlenW(pMachine->szName) + 1); } else { G_FREE(pszTemp); } } else { LoggerInfo->MachineListSize = (lstrlenW(pMachine->szName) + 2); LoggerInfo->MachineList = G_ALLOC(sizeof(WCHAR) * LoggerInfo->MachineListSize); if (LoggerInfo->MachineList != NULL) { pszCurrent = LoggerInfo->MachineList; } } if (LoggerInfo->MachineList == NULL) { Status = PDH_MEMORY_ALLOCATION_FAILURE; goto Cleanup; } lstrcpyW(pszCurrent, pMachine->szName); dwBufSize = sizeof(WCHAR) * (lstrlenW(pMachine->szName) + 1); pszBuffer = (LPWSTR) G_ALLOC(PDH_BLOCK_BUFFER_SIZE); if (pszBuffer == NULL) { Status = PDH_MEMORY_ALLOCATION_FAILURE; goto Cleanup; } __try { WCHAR szIndex[10]; DWORD dwNewSize = 0; for (i = 0; i < dwLastId; i ++) { if (pString[i] == NULL || pType[i] != STR_COUNTER) continue; ZeroMemory(szIndex, sizeof(WCHAR) * 10); _ltow(i, szIndex, 10); dwNewSize = sizeof(WCHAR) * ( lstrlenW(szIndex) + 1 + lstrlenW(pString[i]) + 1); if (dwBufSize + dwNewSize >= PDH_BLOCK_BUFFER_SIZE) { Status = PdhWmiTraceEvent(pLog, PDH_LOG_COUNTER_STRING_EVENT, LoggerInfo->TimeStamp - 1, dwBufSize, pszBuffer); bNewEvent = TRUE; } if (bNewEvent) { ZeroMemory(pszBuffer, PDH_BLOCK_BUFFER_SIZE); lstrcpyW(pszBuffer, pMachine->szName); pszCurrent = pszBuffer + (lstrlenW(pszBuffer) + 1); dwBufSize = sizeof(WCHAR) * (lstrlenW(pMachine->szName) + 1); bNewEvent = FALSE; } lstrcpyW(pszCurrent, szIndex); pszCurrent += (lstrlenW(pszCurrent) + 1); lstrcpyW(pszCurrent, pString[i]); pszCurrent += (lstrlenW(pszCurrent) + 1); dwBufSize += dwNewSize; } Status = PdhWmiTraceEvent(pLog, PDH_LOG_COUNTER_STRING_EVENT, LoggerInfo->TimeStamp - 1, dwBufSize, pszBuffer); } __except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); } Cleanup: if (pszBuffer != NULL) { G_FREE(pszBuffer); } return Status; } PDH_FUNCTION PdhiBuildLogHeaderBlock( IN PPDHI_LOG pLog, IN PPDH_EVENT_TRACE_PROPERTIES LoggerInfo) { PDH_STATUS Status = ERROR_SUCCESS; PVOID ptrOutBuffer = NULL; PVOID ptrTemp; PPDH_WMI_LOG_INFO pLogInfo = NULL; DWORD SizeAlloc = sizeof(PDH_WMI_LOG_INFO); DWORD NewSizeAlloc; PPDHI_COUNTER pThisCounter; PPDHI_COUNTER pThisCounterHead; DWORD dwPathBufSize; PPDHI_LOG_COUNTER_PATH pLogCounter; LONG lBufOffset; PWCHAR pBufferBase; ptrOutBuffer = G_ALLOC(sizeof(PDH_WMI_LOG_INFO)); if (ptrOutBuffer == NULL) { Status = PDH_MEMORY_ALLOCATION_FAILURE; goto Cleanup; } pLogInfo = (PPDH_WMI_LOG_INFO) ptrOutBuffer; pLogInfo->dwLogVersion = WMILOG_VERSION; pLogInfo->dwFlags = pLog->dwLogFormat; pThisCounter = pThisCounterHead = (pLog->pQuery) ? (pLog->pQuery->pCounterListHead) : (NULL); if (pThisCounter != NULL) { do { dwPathBufSize = sizeof(PDHI_LOG_COUNTER_PATH) + sizeof(DWORD); if (pThisCounter->pCounterPath->szMachineName != NULL) { dwPathBufSize += sizeof(WCHAR) * (1 + lstrlenW(pThisCounter->pCounterPath->szMachineName)); } if (pThisCounter->pCounterPath->szObjectName != NULL) { dwPathBufSize += sizeof(WCHAR) * (1 + lstrlenW(pThisCounter->pCounterPath->szObjectName)); } if (pThisCounter->dwFlags & PDHIC_COUNTER_OBJECT) { Status = PdhiBuildPerfCounterList( pLog, LoggerInfo, pThisCounter); if (Status != ERROR_SUCCESS) { goto Cleanup; } } if (pThisCounter->pCounterPath->szInstanceName != NULL) { dwPathBufSize += sizeof(WCHAR) * (1 + lstrlenW(pThisCounter->pCounterPath->szInstanceName)); } if (pThisCounter->pCounterPath->szParentName != NULL) { dwPathBufSize += sizeof(WCHAR) * (1 + lstrlenW(pThisCounter->pCounterPath->szParentName)); } if (pThisCounter->pCounterPath->szCounterName != NULL) { dwPathBufSize += sizeof(WCHAR) * (1 + lstrlenW(pThisCounter->pCounterPath->szCounterName)); } dwPathBufSize = QWORD_MULTIPLE(dwPathBufSize); NewSizeAlloc = SizeAlloc + dwPathBufSize; ptrTemp = ptrOutBuffer; ptrOutBuffer = G_REALLOC(ptrTemp, NewSizeAlloc); if (ptrOutBuffer == NULL) { G_FREE(ptrTemp); Status = PDH_MEMORY_ALLOCATION_FAILURE; goto Cleanup; } pLogCounter = (PPDHI_LOG_COUNTER_PATH) (((LPBYTE) ptrOutBuffer) + SizeAlloc); SizeAlloc = NewSizeAlloc; RtlZeroMemory(pLogCounter, dwPathBufSize); pLogCounter->dwLength = dwPathBufSize; pLogCounter->dwFlags = pThisCounter->dwFlags; pLogCounter->dwUserData = pThisCounter->dwUserData; if (pThisCounter->dwFlags & PDHIC_COUNTER_OBJECT) { pLogCounter->dwCounterType = PDHIC_COUNTER_OBJECT; pLogCounter->lDefaultScale = 0; pLogCounter->dwIndex = 0; } else { pLogCounter->dwCounterType = pThisCounter->plCounterInfo.dwCounterType; pLogCounter->lDefaultScale = pThisCounter->plCounterInfo.lDefaultScale; pLogCounter->dwIndex = pThisCounter->pCounterPath->dwIndex; } pLogCounter->llTimeBase = pThisCounter->TimeBase; // if this is a wild card path, then move the strings up // 1 dword in the buffer allowing the first DWORD of the // the buffer to contain the offset into the catalog // of the instances found in this log file. This list // will be built after the log is closed. lBufOffset = 0; // in WORDS (not bytes) if (pThisCounter->pCounterPath->szInstanceName != NULL) { if (* pThisCounter->pCounterPath->szInstanceName == SPLAT_L) { lBufOffset = sizeof(DWORD); } } #if DBG if (lBufOffset > 0) * (LPDWORD) (& pLogCounter->Buffer[0]) = 0x12345678; #endif if (pThisCounter->pCounterPath->szMachineName != NULL) { pLogCounter->lMachineNameOffset = lBufOffset; pBufferBase = (PWCHAR) ((LPBYTE) & pLogCounter->Buffer[0] + lBufOffset); lstrcpyW(pBufferBase, pThisCounter->pCounterPath->szMachineName); lBufOffset += sizeof(WCHAR) * (1 + lstrlenW(pThisCounter->pCounterPath->szMachineName)); } else { pLogCounter->lMachineNameOffset = (LONG) -1; } if (pThisCounter->pCounterPath->szObjectName != NULL) { pLogCounter->lObjectNameOffset = lBufOffset; pBufferBase = (PWCHAR) ((LPBYTE) & pLogCounter->Buffer[0] + lBufOffset); lstrcpyW(pBufferBase, pThisCounter->pCounterPath->szObjectName); lBufOffset += sizeof(WCHAR) * (1 + lstrlenW(pThisCounter->pCounterPath->szObjectName)); } else { pLogCounter->lObjectNameOffset = (LONG) -1; } if (pThisCounter->pCounterPath->szInstanceName != NULL) { pLogCounter->lInstanceOffset = lBufOffset; pBufferBase = (PWCHAR) ((LPBYTE) & pLogCounter->Buffer[0] + lBufOffset); lstrcpyW(pBufferBase, pThisCounter->pCounterPath->szInstanceName); lBufOffset += sizeof(WCHAR) * (1 + lstrlenW(pThisCounter->pCounterPath->szInstanceName)); } else { pLogCounter->lInstanceOffset = (LONG) -1; } if (pThisCounter->pCounterPath->szParentName != NULL) { pLogCounter->lParentOffset = lBufOffset; pBufferBase = (PWCHAR) ((LPBYTE) & pLogCounter->Buffer[0] + lBufOffset); lstrcpyW(pBufferBase, pThisCounter->pCounterPath->szParentName); lBufOffset += sizeof(WCHAR) * (1 + lstrlenW(pThisCounter->pCounterPath->szParentName)); } else { pLogCounter->lParentOffset = (LONG) -1; } if (pThisCounter->pCounterPath->szCounterName != NULL) { pLogCounter->lCounterOffset = lBufOffset; pBufferBase = (PWCHAR) ((LPBYTE) & pLogCounter->Buffer[0] + lBufOffset); lstrcpyW(pBufferBase, pThisCounter->pCounterPath->szCounterName); lBufOffset += sizeof(WCHAR) * (1 + lstrlenW(pThisCounter->pCounterPath->szCounterName)); } else { pLogCounter->lCounterOffset = (LONG) -1; } pThisCounter = pThisCounter->next.flink; } while (pThisCounter != pThisCounterHead); } if (Status == ERROR_SUCCESS) { Status = PdhWmiTraceEvent(pLog, PDH_LOG_HEADER_EVENT, LoggerInfo->TimeStamp - 1, SizeAlloc, ptrOutBuffer); } Cleanup: if (ptrOutBuffer) { G_FREE(ptrOutBuffer); } return Status; } PDH_FUNCTION PdhWmiTraceEvent( IN PPDHI_LOG pLog, IN ULONG PdhEventType, IN ULONGLONG TimeStamp, IN ULONG lenMofData, IN PVOID ptrMofData) { PDH_STATUS Status = PDH_INVALID_HANDLE; if ( (pLog->dwLogFormat & PDH_LOG_WRITE_ACCESS) && ((TRACEHANDLE) pLog->hLogFileHandle != (TRACEHANDLE) 0)) { PDH_WMI_EVENT_TRACE Wnode; PPDH_EVENT_TRACE_PROPERTIES LoggerInfo = (PPDH_EVENT_TRACE_PROPERTIES) pLog->lpMappedFileBase; DWORD dwNumEvents = (lenMofData / PDH_BLOCK_BUFFER_SIZE); DWORD dwCurrentEvent = 1; PVOID ptrCurrentMof = ptrMofData; BOOL bIncreaseBuffer = TRUE; if (lenMofData > PDH_BLOCK_BUFFER_SIZE * dwNumEvents) { dwNumEvents ++; } for (Status = ERROR_SUCCESS, dwCurrentEvent = 1; (Status == ERROR_SUCCESS) && (dwCurrentEvent <= dwNumEvents); dwCurrentEvent ++) { USHORT sMofLen = (lenMofData > PDH_BLOCK_BUFFER_SIZE) ? (PDH_BLOCK_BUFFER_SIZE) : ((USHORT) lenMofData); RtlZeroMemory(& Wnode, sizeof(PDH_WMI_EVENT_TRACE)); Wnode.EventHeader.Size = sizeof(PDH_WMI_EVENT_TRACE); Wnode.EventHeader.Class.Type = (UCHAR) PdhEventType; Wnode.EventHeader.Class.Version = PDH_EVENT_VERSION; Wnode.EventHeader.GuidPtr = (ULONGLONG) & PdhTransactionGuid; Wnode.EventHeader.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_GUID_PTR | WNODE_FLAG_USE_MOF_PTR | WNODE_FLAG_USE_TIMESTAMP; if ( PdhEventType == PDH_LOG_HEADER_EVENT || PdhEventType == PDH_LOG_COUNTER_STRING_EVENT) { Wnode.EventHeader.Flags |= WNODE_FLAG_PERSIST_EVENT; } Wnode.EventHeader.TimeStamp.QuadPart = TimeStamp; Wnode.MofFields[0].Length = sizeof(GUID); Wnode.MofFields[0].DataPtr = (ULONGLONG) & LoggerInfo->LogFileGuid; Wnode.MofFields[1].Length = sizeof(DWORD); Wnode.MofFields[1].DataPtr = (ULONGLONG) & dwCurrentEvent; Wnode.MofFields[2].Length = sizeof(DWORD); Wnode.MofFields[2].DataPtr = (ULONGLONG) & dwNumEvents; Wnode.MofFields[3].Length = sMofLen; Wnode.MofFields[3].DataPtr = (ULONGLONG) ptrCurrentMof; bIncreaseBuffer = TRUE; while (bIncreaseBuffer == TRUE) { Status = TraceEvent((TRACEHANDLE) pLog->hLogFileHandle, (PEVENT_TRACE_HEADER) & Wnode); if (Status == ERROR_NOT_ENOUGH_MEMORY) { if (LoggerInfo->LoggerInfo.MaximumBuffers >= PDH_WMI_MAX_BUFFERS) { bIncreaseBuffer = FALSE; } else { EVENT_TRACE_PROPERTIES tmpLoggerInfo; LoggerInfo->LoggerInfo.MaximumBuffers += PDH_WMI_BUFFER_INCREMENT; RtlCopyMemory(& tmpLoggerInfo, & LoggerInfo->LoggerInfo, sizeof(EVENT_TRACE_PROPERTIES)); tmpLoggerInfo.Wnode.BufferSize = sizeof(EVENT_TRACE_PROPERTIES); tmpLoggerInfo.LoggerNameOffset = 0; tmpLoggerInfo.LogFileNameOffset = 0; Status = ControlTraceW((TRACEHANDLE) pLog->hLogFileHandle, LoggerInfo->LoggerName, (PEVENT_TRACE_PROPERTIES) & tmpLoggerInfo, EVENT_TRACE_CONTROL_UPDATE); DebugPrint((1, "UpdateTrace(0x%08X,%d)(%d,0x%08X)\n", pLog->hLogFileHandle, LoggerInfo->LoggerInfo.MaximumBuffers, Status, Status)); bIncreaseBuffer = (Status == ERROR_SUCCESS || Status == ERROR_MORE_DATA) ? (TRUE) : (FALSE); } } else { bIncreaseBuffer = FALSE; } } if (Status != ERROR_SUCCESS) { DebugPrint((1, "PdhWmiTraceEvent(0x%08X,%d,%d/%d,%d,0x%08X,%I64d) fails (%d,0x%08X)\n", pLog->hLogFileHandle, PdhEventType, dwCurrentEvent, dwNumEvents, sMofLen, Wnode.EventHeader.Flags, Wnode.EventHeader.TimeStamp.QuadPart, Status, Status)); } if (Status == ERROR_SUCCESS) { lenMofData -= sMofLen; ptrCurrentMof = (PVOID) (((LPBYTE) ptrCurrentMof) + sMofLen); } } } return Status; } ULONG whextoi(WCHAR *s) { long len; ULONG num, base, hex; if (s == NULL || s[0] == L'\0') { return 0; } len = (long) wcslen(s); // we expect all strings to be less than MAXSTR if (len == 0) { return 0; } hex = 0; base = 1; num = 0; while (-- len >= 0) { if (s[len] >= L'0' && s[len] <= L'9') num = s[len] - L'0'; else if (s[len] >= L'a' && s[len] <= L'f') num = (s[len] - L'a') + 10; else if (s[len] >= L'A' && s[len] <= L'F') num = (s[len] - L'A') + 10; else continue; hex += num * base; base = base * 16; } return hex; } PDH_FUNCTION PdhiCheckWmiLogFileType( IN LPCWSTR LogFileName, IN LPDWORD LogFileType) { PDH_STATUS pdhStatus = ERROR_SUCCESS; HANDLE hFile = NULL; hFile = CreateFileW(LogFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == NULL || hFile == INVALID_HANDLE_VALUE) { pdhStatus = PDH_LOG_FILE_OPEN_ERROR; } else { BYTE TraceBuffer[PDH_WMI_BUFFER_SIZE_BYTE]; ULONG ByteRead = 0; INT bResult = ReadFile(hFile, (LPVOID) TraceBuffer, PDH_WMI_BUFFER_SIZE_BYTE, & ByteRead, NULL); if (bResult > 0 && ByteRead == PDH_WMI_BUFFER_SIZE_BYTE) { PWMI_BUFFER_HEADER BufferHeader; PTRACE_LOGFILE_HEADER LogFileHeader; BufferHeader = (PWMI_BUFFER_HEADER) TraceBuffer; LogFileHeader = (PTRACE_LOGFILE_HEADER) (TraceBuffer + sizeof(WMI_BUFFER_HEADER) + sizeof(SYSTEM_TRACE_HEADER)); if ( BufferHeader->Wnode.BufferSize == PDH_WMI_BUFFER_SIZE_BYTE && LogFileHeader->BufferSize == PDH_WMI_BUFFER_SIZE_BYTE) { // preassume that this is PDH event trace counter logfile // * LogFileType = PDH_LOG_TYPE_BINARY; } else { * LogFileType = PDH_LOG_TYPE_UNDEFINED; } } } return pdhStatus; } PDH_FUNCTION PdhWmiGetLoggerName( IN PPDHI_LOG pLog, IN PPDH_EVENT_TRACE_PROPERTIES LoggerInfo) { PDH_STATUS Status = ERROR_SUCCESS; BYTE TraceBuffer[PDH_WMI_BUFFER_SIZE_BYTE]; // read in the first trace buffer HANDLE hFile; ULONG ByteRead = 0; hFile = CreateFileW(LoggerInfo->LogFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == NULL || hFile == INVALID_HANDLE_VALUE) { Status = PDH_LOG_FILE_OPEN_ERROR; } else { INT bResult = ReadFile(hFile, (LPVOID) TraceBuffer, PDH_WMI_BUFFER_SIZE_BYTE, & ByteRead, NULL); if (bResult == 0 || ByteRead != PDH_WMI_BUFFER_SIZE_BYTE) { Status = PDH_LOG_FILE_OPEN_ERROR; } CloseHandle(hFile); } if (Status == ERROR_SUCCESS) { PTRACE_LOGFILE_HEADER pHeader = (PTRACE_LOGFILE_HEADER) (TraceBuffer + sizeof(WMI_BUFFER_HEADER) + sizeof(SYSTEM_TRACE_HEADER)); if (pHeader->BuffersWritten > 1) { UINT i; WCHAR strTmp[PDH_MAX_PATH]; LPWSTR LoggerName = (LPWSTR) (((LPBYTE) pHeader) + sizeof(TRACE_LOGFILE_HEADER)); lstrcpynW(LoggerInfo->LoggerName, LoggerName, PDH_MAX_PATH); wcsncpy(strTmp, LoggerName, 8); strTmp[8] = L'\0'; LoggerInfo->LogFileGuid.Data1 = whextoi(strTmp); wcsncpy(strTmp, & LoggerName[9], 4); strTmp[4] = L'\0'; LoggerInfo->LogFileGuid.Data2 = (USHORT) whextoi(strTmp); wcsncpy(strTmp, & LoggerName[14], 4); strTmp[4] = L'\0'; LoggerInfo->LogFileGuid.Data3 = (USHORT) whextoi(strTmp); for (i = 0; i < 2; i ++) { wcsncpy(strTmp, & LoggerName[19 + (i * 2)], 2); strTmp[2] = L'\0'; LoggerInfo->LogFileGuid.Data4[i] = (UCHAR) whextoi(strTmp); } for (i = 2; i < 8; i ++) { wcsncpy(strTmp, & LoggerName[20 + (i * 2)], 2); strTmp[2] = L'\0'; LoggerInfo->LogFileGuid.Data4[i] = (UCHAR) whextoi(strTmp); } } else { // Only 1 trace buffer written, no PDH events yet. // It is safe to discard this one and create a new one. // Status = PDH_LOG_FILE_OPEN_ERROR; DebugPrint((1,"PdhWmiGetLoggerName(0x%08X,0x%08X,0x%08X,\"%ws\")\n", Status, pLog, LoggerInfo, LoggerInfo->LogFileName)); } } return Status; } PDH_FUNCTION PdhiOpenOutputWmiLog( IN PPDHI_LOG pLog) { PDH_STATUS Status = PDH_LOG_FILE_CREATE_ERROR; PPDH_EVENT_TRACE_PROPERTIES LoggerInfo; pLog->lpMappedFileBase = G_ALLOC(sizeof(PDH_EVENT_TRACE_PROPERTIES)); if (pLog->lpMappedFileBase == NULL) { Status = PDH_MEMORY_ALLOCATION_FAILURE; goto Cleanup; } LoggerInfo = (PPDH_EVENT_TRACE_PROPERTIES) pLog->lpMappedFileBase; RtlZeroMemory(LoggerInfo, sizeof(PDH_EVENT_TRACE_PROPERTIES)); // Start PDH kernel logger // LoggerInfo->LoggerInfo.Wnode.BufferSize = sizeof(PDH_EVENT_TRACE_PROPERTIES); LoggerInfo->LoggerInfo.Wnode.Flags = WNODE_FLAG_TRACED_GUID; LoggerInfo->LoggerInfo.Wnode.ClientContext = EVENT_TRACE_CLOCK_SYSTEMTIME; LoggerInfo->LoggerInfo.BufferSize = PDH_WMI_BUFFER_SIZE; LoggerInfo->LoggerInfo.LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); LoggerInfo->LoggerInfo.LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(WCHAR) * PDH_MAX_PATH; _wfullpath(LoggerInfo->LogFileName, pLog->szLogFileName, PDH_MAX_PATH); if ( !(pLog->dwLogFormat & PDH_LOG_OPT_CIRCULAR) && (pLog->dwLogFormat & PDH_LOG_OPT_APPEND)) { Status = PdhWmiGetLoggerName(pLog, LoggerInfo); if (Status != ERROR_SUCCESS) { // if cannot get LogFileGuid from logfile, erase the old one // and create new one // RPC_STATUS rpcStatus = UuidCreate(& LoggerInfo->LogFileGuid); GuidToString(LoggerInfo->LoggerName, & LoggerInfo->LogFileGuid); } else { LoggerInfo->LoggerInfo.LogFileMode |= EVENT_TRACE_FILE_MODE_APPEND; } } else { RPC_STATUS rpcStatus = UuidCreate(& LoggerInfo->LogFileGuid); GuidToString(LoggerInfo->LoggerName, & LoggerInfo->LogFileGuid); } if (pLog->dwLogFormat & PDH_LOG_OPT_CIRCULAR) { LoggerInfo->LoggerInfo.LogFileMode |= EVENT_TRACE_FILE_MODE_CIRCULAR; } else { LoggerInfo->LoggerInfo.LogFileMode |= EVENT_TRACE_FILE_MODE_SEQUENTIAL; } LoggerInfo->LoggerInfo.LogFileMode |= EVENT_TRACE_USE_PAGED_MEMORY; if (pLog->llMaxSize == 0) { LoggerInfo->LoggerInfo.MaximumFileSize = 0; } else { LoggerInfo->LoggerInfo.MaximumFileSize = (ULONG) ((pLog->llMaxSize / 1024) / 1024); } LoggerInfo->LoggerInfo.MaximumBuffers = PDH_WMI_DEFAULT_BUFFERS; LoggerInfo->bHeaderEvent = FALSE; Status = StartTraceW((PTRACEHANDLE) & pLog->hLogFileHandle, LoggerInfo->LoggerName, (PEVENT_TRACE_PROPERTIES) LoggerInfo); if (Status != ERROR_SUCCESS) { DebugPrint((1, "StartTraceW(%ws,%ws,0x%08X,%I64d) fails (0x%08X,%c)\n", LoggerInfo->LoggerName, LoggerInfo->LogFileName, LoggerInfo->LoggerInfo.LogFileMode, pLog->llMaxSize, Status, LoggerInfo->bHeaderEvent ? 'T' : 'F')); } Cleanup: if (Status != ERROR_SUCCESS) { if (pLog->lpMappedFileBase) { G_FREE(pLog->lpMappedFileBase); pLog->lpMappedFileBase = NULL; } Status = PDH_LOG_FILE_CREATE_ERROR; } return Status; } PDH_FUNCTION PdhiWriteWmiLogRecord ( IN PPDHI_LOG pLog, IN SYSTEMTIME * stTimeStamp, IN LPCWSTR szUserString ) { PDH_STATUS pdhStatus = ERROR_SUCCESS; PPDHI_BINARY_LOG_RECORD_HEADER pLogCounterBuffer = NULL; PPDHI_BINARY_LOG_RECORD_HEADER pThisLogCounter = NULL; PPDH_RAW_COUNTER pSingleCounter; PPDHI_RAW_COUNTER_ITEM_BLOCK pMultiCounter; PPDHI_COUNTER pThisCounter; PPERF_DATA_BLOCK pObjectCounter; DWORD dwBufSize = 0; ULONGLONG TimeStamp = 0; FILETIME tFileTime; PPDH_EVENT_TRACE_PROPERTIES LoggerInfo = (PPDH_EVENT_TRACE_PROPERTIES) pLog->lpMappedFileBase; DBG_UNREFERENCED_PARAMETER(szUserString); SystemTimeToFileTime(stTimeStamp, & tFileTime); pThisCounter = pLog->pQuery ? pLog->pQuery->pCounterListHead : NULL; if (pThisCounter == NULL) { return PDH_NO_DATA; } do { DWORD dwType = (pThisCounter->dwFlags & PDHIC_COUNTER_OBJECT) ? (PDHIC_COUNTER_OBJECT) : ( (pThisCounter->dwFlags & PDHIC_MULTI_INSTANCE) ? (PDHIC_MULTI_INSTANCE) : (0)); DWORD dwCtrBufSize = sizeof(PDHI_BINARY_LOG_RECORD_HEADER); DWORD dwNewSize; int nItem; switch (dwType) { case PDHIC_MULTI_INSTANCE: if (pThisCounter->pThisRawItemList) { dwCtrBufSize += pThisCounter->pThisRawItemList->dwLength; } else { dwCtrBufSize += sizeof(PDHI_RAW_COUNTER_ITEM_BLOCK); } break; case PDHIC_COUNTER_OBJECT: if (pThisCounter->pThisObject) { dwCtrBufSize += pThisCounter->pThisObject->TotalByteLength; } else { dwCtrBufSize += sizeof(PERF_DATA_BLOCK); } break; default: dwCtrBufSize += sizeof(PDH_RAW_COUNTER); break; } if (dwCtrBufSize > 0) { // extend buffer to accomodate this new counter // if (pLogCounterBuffer == NULL) { // add in room for the master record header // then allocate the first one // dwBufSize = (dwCtrBufSize + sizeof(PDHI_BINARY_LOG_RECORD_HEADER)); pLogCounterBuffer = G_ALLOC(dwBufSize); // set counter data pointer to just after the master // record header // if (pLogCounterBuffer == NULL) { pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE; break; } pThisLogCounter = (PPDHI_BINARY_LOG_RECORD_HEADER) ( ((PUCHAR) pLogCounterBuffer) + sizeof(PDHI_BINARY_LOG_RECORD_HEADER)); assert (dwCtrBufSize < 0x00010000); pThisLogCounter->dwLength = LOWORD(dwCtrBufSize); } else { PPDHI_BINARY_LOG_RECORD_HEADER ptrTemp = pLogCounterBuffer; dwNewSize = (dwBufSize + dwCtrBufSize); pLogCounterBuffer = G_REALLOC(ptrTemp, dwNewSize); if (pLogCounterBuffer == NULL) { G_FREE(ptrTemp); pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE; break; } pThisLogCounter = (PPDHI_BINARY_LOG_RECORD_HEADER) ((LPBYTE) pLogCounterBuffer + dwBufSize); dwBufSize += dwCtrBufSize; assert (dwCtrBufSize < 0x00010000); pThisLogCounter->dwLength = LOWORD(dwCtrBufSize); } } if (dwType == PDHIC_COUNTER_OBJECT) { FILETIME LocFileTime; pThisLogCounter->dwType = BINLOG_TYPE_DATA_LOC_OBJECT; pObjectCounter = (PPERF_DATA_BLOCK) ((LPBYTE) pThisLogCounter + sizeof(PDHI_BINARY_LOG_RECORD_HEADER)); if (pThisCounter->pThisObject) { RtlCopyMemory(pObjectCounter, pThisCounter->pThisObject, pThisCounter->pThisObject->TotalByteLength); SystemTimeToFileTime(& pThisCounter->pThisObject->SystemTime, & LocFileTime); } else { if (TimeStamp != 0) { LocFileTime.dwLowDateTime = LODWORD(TimeStamp); LocFileTime.dwHighDateTime = HIDWORD(TimeStamp); } else { LocFileTime = tFileTime; } pObjectCounter->Signature[0] = L'P'; pObjectCounter->Signature[1] = L'E'; pObjectCounter->Signature[2] = L'R'; pObjectCounter->Signature[3] = L'F'; pObjectCounter->LittleEndian = TRUE; pObjectCounter->Version = PERF_DATA_VERSION; pObjectCounter->Revision = PERF_DATA_REVISION; pObjectCounter->TotalByteLength = sizeof(PERF_DATA_BLOCK); pObjectCounter->NumObjectTypes = 1; pObjectCounter->DefaultObject = pThisCounter->plCounterInfo.dwObjectId; pObjectCounter->SystemNameLength = 0; pObjectCounter->SystemNameOffset = 0; pObjectCounter->HeaderLength = sizeof(PERF_DATA_BLOCK); pObjectCounter->PerfTime.QuadPart = 0; pObjectCounter->PerfFreq.QuadPart = 0; pObjectCounter->PerfTime100nSec.QuadPart = 0; FileTimeToSystemTime(& LocFileTime, & pObjectCounter->SystemTime); } TimeStamp = MAKELONGLONG(LocFileTime.dwLowDateTime, LocFileTime.dwHighDateTime); } else if (dwType == PDHIC_MULTI_INSTANCE) { // multiple counter // pThisLogCounter->dwType = BINLOG_TYPE_DATA_MULTI; pMultiCounter = (PPDHI_RAW_COUNTER_ITEM_BLOCK) ((LPBYTE) pThisLogCounter + sizeof(PDHI_BINARY_LOG_RECORD_HEADER)); if (pThisCounter->pThisRawItemList) { RtlCopyMemory(pMultiCounter, pThisCounter->pThisRawItemList, pThisCounter->pThisRawItemList->dwLength); } else { FILETIME LocFileTime; if (TimeStamp != 0) { LocFileTime.dwLowDateTime = LODWORD(TimeStamp); LocFileTime.dwHighDateTime = HIDWORD(TimeStamp); } else { LocFileTime = tFileTime; } ZeroMemory(pMultiCounter, sizeof(PDHI_RAW_COUNTER_ITEM_BLOCK)); pMultiCounter->CStatus = PDH_CSTATUS_INVALID_DATA; pMultiCounter->TimeStamp.dwLowDateTime = LocFileTime.dwLowDateTime; pMultiCounter->TimeStamp.dwHighDateTime = LocFileTime.dwHighDateTime; } TimeStamp = MAKELONGLONG(pMultiCounter->TimeStamp.dwLowDateTime, pMultiCounter->TimeStamp.dwHighDateTime); } else { pThisLogCounter->dwType = BINLOG_TYPE_DATA_SINGLE; pSingleCounter = (PPDH_RAW_COUNTER) ((LPBYTE) pThisLogCounter + sizeof(PDHI_BINARY_LOG_RECORD_HEADER)); RtlCopyMemory( pSingleCounter, & pThisCounter->ThisValue, sizeof(PDH_RAW_COUNTER)); if (pSingleCounter->CStatus != ERROR_SUCCESS) { if (TimeStamp != 0) { pSingleCounter->TimeStamp.dwLowDateTime = LODWORD(TimeStamp); pSingleCounter->TimeStamp.dwHighDateTime = HIDWORD(TimeStamp); } else { pSingleCounter->TimeStamp.dwLowDateTime = tFileTime.dwLowDateTime; pSingleCounter->TimeStamp.dwHighDateTime = tFileTime.dwHighDateTime; } } TimeStamp = (ULONGLONG) MAKELONGLONG( pSingleCounter->TimeStamp.dwLowDateTime, pSingleCounter->TimeStamp.dwHighDateTime); } pThisCounter = pThisCounter->next.flink; // go to next in list } while (pThisCounter != pLog->pQuery->pCounterListHead); if (TimeStamp == 0) { TimeStamp = MAKELONGLONG(tFileTime.dwLowDateTime, tFileTime.dwHighDateTime); } if (pdhStatus == ERROR_SUCCESS && pLogCounterBuffer) { pLogCounterBuffer->dwType = BINLOG_TYPE_DATA; pLogCounterBuffer->dwLength = dwBufSize; LoggerInfo->TimeStamp = TimeStamp; if (! LoggerInfo->bHeaderEvent) { ULONG HeaderMofLength = 0; PVOID HeaderMofData = NULL; ULONG EventType; if (LoggerInfo->LoggerInfo.LogFileMode & EVENT_TRACE_FILE_MODE_APPEND) { #if 0 pdhStatus = PdhiBuildEmptyBlock(pLog, LoggerInfo->TimeStamp - 1, & HeaderMofLength, & HeaderMofData); if (pdhStatus == ERROR_SUCCESS) { pdhStatus = PdhWmiTraceEvent(pLog, PDH_LOG_DATA_BLOCK_EVENT, LoggerInfo->TimeStamp - 1, HeaderMofLength, HeaderMofData); } if (HeaderMofData) { G_FREE(HeaderMofData); } #endif } else { pdhStatus = PdhiBuildLogHeaderBlock(pLog, LoggerInfo); } LoggerInfo->bHeaderEvent = TRUE; } } if (pdhStatus == ERROR_SUCCESS && pLogCounterBuffer) { pdhStatus = PdhWmiTraceEvent(pLog, PDH_LOG_DATA_BLOCK_EVENT, TimeStamp, dwBufSize, (PVOID) pLogCounterBuffer); } if (pLogCounterBuffer != NULL) { G_FREE(pLogCounterBuffer); } return pdhStatus; } PDH_FUNCTION PdhiWriteWmiLogHeader ( IN PPDHI_LOG pLog, IN LPCWSTR szUserCaption) { UNREFERENCED_PARAMETER (pLog); UNREFERENCED_PARAMETER (szUserCaption); return ERROR_SUCCESS; } PDH_FUNCTION PdhiCloseWmiLog( IN PPDHI_LOG pLog, IN DWORD dwFlags) { PDH_STATUS Status = PDH_INVALID_ARGUMENT; UNREFERENCED_PARAMETER (pLog); UNREFERENCED_PARAMETER (dwFlags); if (pLog->dwLogFormat & PDH_LOG_WRITE_ACCESS) { if ((TRACEHANDLE) pLog->hLogFileHandle != (TRACEHANDLE) 0) { PPDH_EVENT_TRACE_PROPERTIES LoggerInfo = (PPDH_EVENT_TRACE_PROPERTIES) pLog->lpMappedFileBase; if (LoggerInfo == NULL) { Status = PDH_INVALID_HANDLE; } else { ULONG HeaderMofLength = 0; PVOID HeaderMofData = NULL; #if 0 Status = PdhiBuildEmptyBlock(pLog, LoggerInfo->TimeStamp, & HeaderMofLength, & HeaderMofData); if (Status == ERROR_SUCCESS) { Status = PdhWmiTraceEvent(pLog, PDH_LOG_DATA_BLOCK_EVENT, LoggerInfo->TimeStamp + 1, HeaderMofLength, HeaderMofData); } if (HeaderMofData) { G_FREE(HeaderMofData); } #endif Status = ControlTraceW((TRACEHANDLE) pLog->hLogFileHandle, LoggerInfo->LoggerName, (PEVENT_TRACE_PROPERTIES) LoggerInfo, EVENT_TRACE_CONTROL_STOP); if (Status != ERROR_SUCCESS) { DebugPrint((1, "StopTrace(0x%08X,%ws,%ws) fails (%d)\n", pLog->hLogFileHandle, LoggerInfo->LoggerName, LoggerInfo->LogFileName, Status, Status)); } if (LoggerInfo->MachineList != NULL) { G_FREE(LoggerInfo->MachineList); } G_FREE(pLog->lpMappedFileBase); pLog->lpMappedFileBase = NULL; } pLog->hLogFileHandle = INVALID_HANDLE_VALUE; if (PdhTraceRegistrationHandle != (TRACEHANDLE) 0) { Status = UnregisterTraceGuids(PdhTraceRegistrationHandle); if (Status != ERROR_SUCCESS) { DebugPrint((4, "UnregisterTraceGuid(0x%08X) fails (%d,0x%08X)\n", PdhTraceRegistrationHandle, Status, Status)); } } } else { Status = PDH_INVALID_HANDLE; } } else if (pLog->dwLogFormat & PDH_LOG_READ_ACCESS) { ULONG i; DWORD dwExitCode; PPDH_LOGGER_CONTEXT CurrentContext = (PPDH_LOGGER_CONTEXT) pLog->lpMappedFileBase; DWORD dwContext = GetLoggerContext(CurrentContext); if (dwContext < ContextCount) { Status = WAIT_FOR_AND_LOCK_MUTEX(hPdhContextMutex); if (Status == ERROR_SUCCESS) { CurrentContext->RefCount --; if (CurrentContext->RefCount > 0) { RELEASE_MUTEX(hPdhContextMutex); return ERROR_SUCCESS; } } else { return Status; } if (dwContext != ContextCount - 1) { ContextTable[dwContext] = ContextTable[ContextCount - 1]; } ContextCount --; ContextTable[ContextCount] = NULL; RELEASE_MUTEX(hPdhContextMutex); if (CurrentContext->hThreadWork != NULL && CurrentContext->hThreadWork != INVALID_HANDLE_VALUE) { if (GetExitCodeThread(CurrentContext->hThreadWork, & dwExitCode) && dwExitCode == STILL_ACTIVE) { CurrentContext->LoggerState = PdhProcessTraceEnd; SetEvent(CurrentContext->hSyncWMI); while (CurrentContext->LoggerState != PdhProcessTraceExit) { _sleep(1); } if (TerminateThread(CurrentContext->hThreadWork, 0)) { WaitForSingleObject(CurrentContext->hThreadWork, INFINITE); } } } if (CurrentContext->hSyncWMI != NULL) { CloseHandle(CurrentContext->hSyncWMI); } if (CurrentContext->hSyncPDH != NULL) { CloseHandle(CurrentContext->hSyncPDH); } for (i = 0; i < CurrentContext->LoggerCount; i ++) { if (! IsListEmpty(& CurrentContext->LogInfo[i].CounterPathList)) { PLIST_ENTRY PathHead = & CurrentContext->LogInfo[i].CounterPathList; PLIST_ENTRY PathNext = PathHead->Flink; PPDH_COUNTER_PATH pCounterPath; while (PathHead != PathNext) { pCounterPath = CONTAINING_RECORD(PathNext, PDH_COUNTER_PATH, Entry); PathNext = PathNext->Flink; RemoveEntryList(& pCounterPath->Entry); G_FREE(pCounterPath->CounterPathBuffer); G_FREE(pCounterPath); } } if (! IsListEmpty(& CurrentContext->LogInfo[i].PerfMachineList)) { PLIST_ENTRY PathHead = & CurrentContext->LogInfo[i].PerfMachineList; PLIST_ENTRY PathNext = PathHead->Flink; PPDH_WMI_PERF_MACHINE pPerfMachine; while (PathHead != PathNext) { pPerfMachine = CONTAINING_RECORD(PathNext, PDH_WMI_PERF_MACHINE, Entry); PathNext = PathNext->Flink; RemoveEntryList(& pPerfMachine->Entry); if (! IsListEmpty(& pPerfMachine->LogObjectList)) { PLIST_ENTRY pHead = & pPerfMachine->LogObjectList; PLIST_ENTRY pNext = pHead->Flink; PPDH_WMI_PERF_OBJECT pPerfObject; while (pHead != pNext) { pPerfObject = CONTAINING_RECORD( pNext, PDH_WMI_PERF_OBJECT, Entry); pNext = pNext->Flink; RemoveEntryList(& pPerfObject->Entry); G_FREE(pPerfObject->ptrBuffer); G_FREE(pPerfObject); } } G_FREE(pPerfMachine->pszBuffer); G_FREE(pPerfMachine->ptrStrAry); G_FREE(pPerfMachine); } } if (CurrentContext->LogInfo[i].DataBlock) { G_FREE(CurrentContext->LogInfo[i].DataBlock); } } if (CurrentContext->tmpBuffer) { G_FREE(CurrentContext->tmpBuffer); } if (CurrentContext->CounterPathBuffer) { G_FREE(CurrentContext->CounterPathBuffer); } G_FREE(pLog->lpMappedFileBase); pLog->lpMappedFileBase = NULL; pLog->pLastRecordRead = NULL; Status = ERROR_SUCCESS; } else { Status = PDH_INVALID_HANDLE; } } return Status; } PDH_FUNCTION PdhiAddWmiLogFileGuid( PPDH_LOGGER_CONTEXT CurrentContext, LPGUID pGuid) { PDH_STATUS Status = ERROR_SUCCESS; ULONG i; for (i = 0; i < CurrentContext->LoggerCount; i ++) { if (IsEqualGUID(pGuid, & CurrentContext->LogInfo[i].LogFileGuid)) break; } if (i == CurrentContext->LoggerCount) { CurrentContext->LogInfo[i].LogFileGuid = * pGuid; CurrentContext->LoggerCount ++; if (CurrentContext->LoggerCount > CurrentContext->LogFileCount) { DebugPrint((4, "LogFileCount(%d) LoggerCount(%d) mismatch\n", CurrentContext->LoggerCount, CurrentContext->LogFileCount)); } } return Status; } ULONG PdhiFindLogFileGuid( PPDH_LOGGER_CONTEXT CurrentContext, LPGUID pGuid) { ULONG i; for (i = 0; i < CurrentContext->LoggerCount; i ++) { if (IsEqualGUID(pGuid, & CurrentContext->LogInfo[i].LogFileGuid)) break; } return i; } ULONGLONG PdhWmiGetDataBlockTimeStamp( PPDH_LOGGER_CONTEXT CurrentContext, PEVENT_TRACE pEvent, BOOLEAN bFirstRun) { PVOID pDataBlock = pEvent->MofData; ULONGLONG TimeStamp = pEvent->Header.TimeStamp.QuadPart; if (TimeStamp > 0) { LPGUID pLogFileGuid = (LPGUID) pDataBlock; ULONG i; for (i = 0; i < CurrentContext->LoggerCount; i ++) { if (IsEqualGUID( pLogFileGuid, & CurrentContext->LogInfo[i].LogFileGuid)) { break; } } if (i < CurrentContext->LoggerCount) { if (bFirstRun) { if ( pEvent->Header.Class.Version < PDH_EVENT_VERSION || CurrentContext->LogInfo[i].TimePrev < TimeStamp) { CurrentContext->LogInfo[i].ValidEntries ++; } if (CurrentContext->LogInfo[i].TimeStart == 0) { CurrentContext->LogInfo[i].TimeStart = TimeStamp; CurrentContext->LogInfo[i].TimePrev = TimeStamp; } else { // no need to update StartTime. // Always assume the first trace event has the StartTime. // if (CurrentContext->LogInfo[i].TimeEnd < TimeStamp) { CurrentContext->LogInfo[i].TimeEnd = TimeStamp; } if ( (TimeStamp - CurrentContext->LogInfo[i].TimePrev) < (CurrentContext->LogInfo[i].TimeFreq)) { CurrentContext->LogInfo[i].TimeFreq = TimeStamp - CurrentContext->LogInfo[i].TimePrev; } CurrentContext->LogInfo[i].TimePrev = TimeStamp; } } else { assert(CurrentContext->LogInfo[i].TimePrev <= TimeStamp); assert(CurrentContext->LogInfo[i].TimeStart <= TimeStamp); assert(CurrentContext->LogInfo[i].TimeEnd >= TimeStamp); CurrentContext->LogInfo[i].TimePrev = TimeStamp; } } } return TimeStamp; } PDH_FUNCTION PdhiWmiComputeCounterBlocks( PPDH_LOGGER_CONTEXT CurrentContext, PEVENT_TRACE pEvent) { LPGUID pLogFileGuid; PDH_STATUS Status = ERROR_SUCCESS; PVOID pDataBlock; ULONG i; ULONG ulNumDataBlocks; ULONG ulDataBlocksCopied; ULONG ulBufferSize; ULONG ulBlockIndex; BOOLEAN bOldEvent; if (CurrentContext == NULL || pEvent == NULL) { return PDH_INVALID_DATA; } bOldEvent = (pEvent->Header.Class.Version < PDH_EVENT_VERSION); pLogFileGuid = (LPGUID) pEvent->MofData; if (pLogFileGuid == NULL) { return PDH_INVALID_DATA; } for (i = 0; i < CurrentContext->LoggerCount; i ++) { if (IsEqualGUID(pLogFileGuid, & CurrentContext->LogInfo[i].LogFileGuid)) { break; } } if (i == CurrentContext->LoggerCount) { return PDH_INVALID_DATA; } ulNumDataBlocks = CurrentContext->LogInfo[i].ulNumDataBlocks; ulDataBlocksCopied = CurrentContext->LogInfo[i].ulDataBlocksCopied; if (ulNumDataBlocks > 0 && ulNumDataBlocks == ulDataBlocksCopied) { if (CurrentContext->LogInfo[i].DataBlock != NULL) { G_FREE(CurrentContext->LogInfo[i].DataBlock); CurrentContext->LogInfo[i].DataBlock = NULL; } goto Cleanup; } if (ulNumDataBlocks == 0) { if (bOldEvent) { ulNumDataBlocks = 1; ulBufferSize = pEvent->MofLength; } else { ulNumDataBlocks = * (DWORD *) ( ((LPBYTE) pEvent->MofData) + sizeof(GUID) + sizeof(DWORD)); ulBufferSize = ulNumDataBlocks * PDH_BLOCK_BUFFER_SIZE + sizeof(GUID); } if (CurrentContext->LogInfo[i].DataBlock != NULL) { G_FREE(CurrentContext->LogInfo[i].DataBlock); CurrentContext->LogInfo[i].DataBlock = NULL; } CurrentContext->LogInfo[i].DataBlock = G_ALLOC(ulBufferSize); if (CurrentContext->LogInfo[i].DataBlock == NULL) { Status = PDH_MEMORY_ALLOCATION_FAILURE; goto Cleanup; } CurrentContext->LogInfo[i].ulNumDataBlocks = ulNumDataBlocks; CurrentContext->LogInfo[i].ulDataBlocksCopied = 0; CurrentContext->LogInfo[i].DataBlockAlloc = ulBufferSize; } if (bOldEvent) { RtlCopyMemory(CurrentContext->LogInfo[i].DataBlock, pEvent->MofData, pEvent->MofLength); } else { ulBlockIndex = * (DWORD *) (((LPBYTE) pEvent->MofData) + sizeof(GUID)); pDataBlock = (PVOID) ( ((LPBYTE) CurrentContext->LogInfo[i].DataBlock) + sizeof(GUID) + PDH_BLOCK_BUFFER_SIZE * (ulBlockIndex - 1)); RtlCopyMemory(pDataBlock, (PVOID) (((LPBYTE) pEvent->MofData) + sizeof(GUID) + sizeof(DWORD) + sizeof(DWORD)), pEvent->MofLength - sizeof(GUID) - sizeof(DWORD) - sizeof(DWORD)); } CurrentContext->LogInfo[i].ulDataBlocksCopied ++; if (CurrentContext->LogInfo[i].ulDataBlocksCopied >= CurrentContext->LogInfo[i].ulNumDataBlocks) { DWORD dwTotal; DWORD dwCurrent; DWORD dwCounters = 0; BOOLEAN bValidBlock = TRUE; PPDHI_BINARY_LOG_RECORD_HEADER pCurrent; PPDHI_BINARY_LOG_RECORD_HEADER pMasterRec; pDataBlock = CurrentContext->LogInfo[i].DataBlock; pMasterRec = (PPDHI_BINARY_LOG_RECORD_HEADER) ((LPBYTE) pDataBlock + sizeof(GUID)); dwTotal = pMasterRec->dwLength; pCurrent = pMasterRec; dwCurrent = sizeof(PDHI_BINARY_LOG_RECORD_HEADER); while (bValidBlock && dwCurrent < dwTotal) { pCurrent = (PPDHI_BINARY_LOG_RECORD_HEADER) ((LPBYTE) pMasterRec + dwCurrent); if (LOWORD(pCurrent->dwType) != BINLOG_START_WORD) { bValidBlock = FALSE; } else { dwCurrent += pCurrent->dwLength; dwCounters ++; } } if (bValidBlock) { CurrentContext->LogInfo[i].ulCounters += dwCounters; } } Cleanup: return Status; } PDH_FUNCTION PdhiAddCounterPathRecord( PPDH_LOGGER_CONTEXT CurrentContext, PEVENT_TRACE pEvent, LPGUID pLogFileGuid, ULONG BufferSize, PVOID pBuffer, ULONGLONG TimeStamp, DWORD dwIndex, DWORD dwCount, BOOLEAN * pNeedUpdate) { PPDH_COUNTER_PATH pNewCounter; ULONG i; PVOID pCounterPath; i = PdhiFindLogFileGuid(CurrentContext, pLogFileGuid); if (i == CurrentContext->LoggerCount) { return PDH_INVALID_DATA; } if (pEvent->Header.Class.Version >= PDH_EVENT_VERSION) { if ( CurrentContext->LogInfo[i].DataBlock && CurrentContext->LogInfo[i].ulNumDataBlocks != dwCount) { G_FREE(CurrentContext->LogInfo[i].DataBlock); CurrentContext->LogInfo[i].DataBlock = NULL; } if (CurrentContext->LogInfo[i].DataBlock == NULL) { CurrentContext->LogInfo[i].DataBlock = G_ALLOC(PDH_BLOCK_BUFFER_SIZE * dwCount); if (CurrentContext->LogInfo[i].DataBlock == NULL) { return PDH_MEMORY_ALLOCATION_FAILURE; } CurrentContext->LogInfo[i].DataBlockAlloc = PDH_BLOCK_BUFFER_SIZE * dwCount; CurrentContext->LogInfo[i].DataBlockSize = 0; CurrentContext->LogInfo[i].ulNumDataBlocks = dwCount; CurrentContext->LogInfo[i].ulDataBlocksCopied = 0; } pCounterPath = (PVOID) ( ((LPBYTE) CurrentContext->LogInfo[i].DataBlock) + (dwIndex - 1) * PDH_BLOCK_BUFFER_SIZE); if (BufferSize > PDH_BLOCK_BUFFER_SIZE) { BufferSize = PDH_BLOCK_BUFFER_SIZE; } RtlCopyMemory(pCounterPath, pBuffer, BufferSize); CurrentContext->LogInfo[i].ulDataBlocksCopied ++; CurrentContext->LogInfo[i].DataBlockSize += BufferSize; if ( CurrentContext->LogInfo[i].ulDataBlocksCopied < CurrentContext->LogInfo[i].ulNumDataBlocks) { return ERROR_SUCCESS; } pCounterPath = (PVOID) (((LPBYTE) CurrentContext->LogInfo[i].DataBlock) + sizeof(PDH_WMI_LOG_INFO)); BufferSize = CurrentContext->LogInfo[i].DataBlockSize - sizeof(PDH_WMI_LOG_INFO); } if (! IsListEmpty(& CurrentContext->LogInfo[i].CounterPathList)) { PLIST_ENTRY PathHead = & CurrentContext->LogInfo[i].CounterPathList; PLIST_ENTRY PathNext = PathHead->Flink; while (PathHead != PathNext) { pNewCounter = CONTAINING_RECORD(PathNext, PDH_COUNTER_PATH, Entry); PathNext = PathNext->Flink; if (TimeStamp == pNewCounter->TimeStamp) { // CounterPath record is already in the list // return ERROR_SUCCESS; } } } pNewCounter = G_ALLOC(sizeof(PDH_COUNTER_PATH)); if (pNewCounter == NULL) { return PDH_MEMORY_ALLOCATION_FAILURE; } pNewCounter->TimeStamp = TimeStamp; pNewCounter->CounterPathBuffer = G_ALLOC(BufferSize); if (pNewCounter->CounterPathBuffer == NULL) { G_FREE(pNewCounter); return PDH_MEMORY_ALLOCATION_FAILURE; } pNewCounter->CounterPathSize = BufferSize; if (pEvent->Header.Class.Version >= PDH_EVENT_VERSION) { RtlCopyMemory(pNewCounter->CounterPathBuffer, pCounterPath, BufferSize); } else { RtlCopyMemory(pNewCounter->CounterPathBuffer, pBuffer, BufferSize); } pNewCounter->CounterCount = 0; { PPDHI_LOG_COUNTER_PATH pPath = pNewCounter->CounterPathBuffer; ULONG dwProcessed = 0; while (dwProcessed < BufferSize) { pNewCounter->CounterCount ++; dwProcessed += pPath->dwLength; pPath = (PPDHI_LOG_COUNTER_PATH) (((LPBYTE) pPath) + pPath->dwLength); } } InsertTailList(& CurrentContext->LogInfo[i].CounterPathList, & pNewCounter->Entry); * pNeedUpdate = TRUE; if (pEvent->Header.Class.Version >= PDH_EVENT_VERSION) { G_FREE(CurrentContext->LogInfo[i].DataBlock); CurrentContext->LogInfo[i].DataBlock = NULL; CurrentContext->LogInfo[i].DataBlockAlloc = 0; CurrentContext->LogInfo[i].DataBlockSize = 0; CurrentContext->LogInfo[i].ulNumDataBlocks = 0; CurrentContext->LogInfo[i].ulDataBlocksCopied = 0; } return ERROR_SUCCESS; } PDH_FUNCTION PdhiAddPerfMachine( IN PPDH_LOGGER_CONTEXT CurrentContext, IN PVOID pMofDataBlock, IN DWORD dwMofLength) { PDH_STATUS Status = ERROR_SUCCESS; LPGUID pLogFileGuid = (LPGUID) pMofDataBlock; LPWSTR pszMachineName = (LPWSTR) (((LPBYTE) pMofDataBlock) + sizeof(GUID) + sizeof(DWORD) + sizeof(DWORD)); DWORD dwBufSize = dwMofLength - sizeof(GUID) - sizeof(DWORD) - sizeof(DWORD); ULONG i; LPWSTR pszTmpBuffer; DWORD dwThisId; DWORD dwBufUsed; PPDH_WMI_PERF_MACHINE pCurrentMachine = NULL; BOOLEAN bNewMachine = TRUE; i = PdhiFindLogFileGuid(CurrentContext, pLogFileGuid); if (i == CurrentContext->LoggerCount) { Status = PDH_INVALID_DATA; goto Cleanup; } if (! IsListEmpty(& CurrentContext->LogInfo[i].PerfMachineList)) { PLIST_ENTRY pHead = & CurrentContext->LogInfo[i].PerfMachineList; PLIST_ENTRY pNext = pHead->Flink; while (pNext != pHead) { PPDH_WMI_PERF_MACHINE pMachine = CONTAINING_RECORD(pNext, PDH_WMI_PERF_MACHINE, Entry); if (lstrcmpiW(pMachine->pszBuffer, pszMachineName) == 0) { pCurrentMachine = pMachine; bNewMachine = FALSE; break; } pNext = pNext->Flink; } } if (bNewMachine) { pCurrentMachine = G_ALLOC(sizeof(PDH_WMI_PERF_MACHINE)); if (pCurrentMachine == NULL) { Status = PDH_MEMORY_ALLOCATION_FAILURE; goto Cleanup; } InsertTailList(& CurrentContext->LogInfo[i].PerfMachineList, & pCurrentMachine->Entry); pCurrentMachine->pszBuffer = G_ALLOC(dwBufSize); if (pCurrentMachine->pszBuffer == NULL) { Status = PDH_MEMORY_ALLOCATION_FAILURE; goto Cleanup; } RtlCopyMemory(pCurrentMachine->pszBuffer, pszMachineName, dwBufSize); pCurrentMachine->dwBufSize = dwBufSize; InitializeListHead(& pCurrentMachine->LogObjectList); } else { pszTmpBuffer = pCurrentMachine->pszBuffer; dwBufSize -= (sizeof(WCHAR) * (lstrlenW(pszMachineName) + 1)); pszMachineName += (lstrlenW(pszMachineName) + 1); pCurrentMachine->pszBuffer = G_ALLOC( pCurrentMachine->dwBufSize + dwBufSize); if (pCurrentMachine->pszBuffer == NULL) { pCurrentMachine->pszBuffer = pszTmpBuffer; Status = PDH_MEMORY_ALLOCATION_FAILURE; goto Cleanup; } RtlCopyMemory(pCurrentMachine->pszBuffer, pszTmpBuffer, pCurrentMachine->dwBufSize); G_FREE(pszTmpBuffer); pszTmpBuffer = (LPWSTR) ( ((LPBYTE) pCurrentMachine->pszBuffer) + pCurrentMachine->dwBufSize); RtlCopyMemory(pszTmpBuffer, pszMachineName, dwBufSize); pCurrentMachine->dwBufSize += dwBufSize; } dwBufSize = pCurrentMachine->dwBufSize; pCurrentMachine->dwLastId = 0; i = lstrlenW(pCurrentMachine->pszBuffer) + 1; pszTmpBuffer = pCurrentMachine->pszBuffer + i; dwBufUsed = sizeof(WCHAR) * i; while ((dwBufUsed < dwBufSize) && (* pszTmpBuffer)) { do { dwThisId = wcstoul(pszTmpBuffer, NULL, 10); if (dwThisId > pCurrentMachine->dwLastId) { pCurrentMachine->dwLastId = dwThisId; } i = lstrlenW(pszTmpBuffer) + 1; dwBufUsed += (sizeof(WCHAR) * i); if (dwBufUsed < dwBufSize) { pszTmpBuffer += i; } } while ((dwThisId == 0) && (* pszTmpBuffer) && dwBufUsed < dwBufSize); i = lstrlenW(pszTmpBuffer) + 1; dwBufUsed += (sizeof(WCHAR) * i); if ((* pszTmpBuffer) && (dwBufUsed < dwBufSize)) { pszTmpBuffer += i; } } if (pCurrentMachine->dwLastId == 0) { Status = PDH_CANNOT_READ_NAME_STRINGS; goto Cleanup; } if (! bNewMachine) { G_FREE(pCurrentMachine->ptrStrAry); pCurrentMachine->ptrStrAry = NULL; } pCurrentMachine->ptrStrAry = G_ALLOC(sizeof(LPWSTR) * (pCurrentMachine->dwLastId + 1)); if (pCurrentMachine->ptrStrAry == NULL) { Status = PDH_CANNOT_READ_NAME_STRINGS; goto Cleanup; } i = lstrlenW(pCurrentMachine->pszBuffer) + 1; pszTmpBuffer = pCurrentMachine->pszBuffer + i; dwBufUsed = sizeof(WCHAR) * i; while ((dwBufUsed < dwBufSize) && (* pszTmpBuffer)) { do { dwThisId = wcstoul(pszTmpBuffer, NULL, 10); i = lstrlenW(pszTmpBuffer) + 1; dwBufUsed += (sizeof(WCHAR) * i); if (dwBufUsed < dwBufSize) { pszTmpBuffer += i; } } while ((dwThisId == 0) && (* pszTmpBuffer) && dwBufUsed < dwBufSize); if (dwThisId > 0 && dwThisId <= pCurrentMachine->dwLastId) { pCurrentMachine->ptrStrAry[dwThisId] = pszTmpBuffer; } i = lstrlenW(pszTmpBuffer) + 1; dwBufUsed += (sizeof(WCHAR) * i); if ((* pszTmpBuffer) && (dwBufUsed < dwBufSize)) { pszTmpBuffer += i; } } Cleanup: if (Status != ERROR_SUCCESS) { if (bNewMachine) { if (pCurrentMachine != NULL) { if (pCurrentMachine->pszBuffer != NULL) { G_FREE(pCurrentMachine->pszBuffer); } RemoveEntryList(& pCurrentMachine->Entry); G_FREE(pCurrentMachine); } } else if (pCurrentMachine != NULL) { if (pCurrentMachine->pszBuffer != NULL) { G_FREE(pCurrentMachine->pszBuffer); } RemoveEntryList(& pCurrentMachine->Entry); G_FREE(pCurrentMachine); } } return Status; } PDH_FUNCTION PdhiGetCounterPathRecord( IN PPDH_LOGGER_CONTEXT CurrentContext, IN PVOID pRecord, IN ULONG dwMaxSize) { PDH_STATUS Status = ERROR_SUCCESS; DWORD CurrentSize = sizeof(PDHI_BINARY_LOG_HEADER_RECORD); if (CurrentContext->bCounterPathChanged) { PPDHI_BINARY_LOG_HEADER_RECORD pBinLogHeader = NULL; PVOID pCounterPath; ULONG i; if (CurrentContext->CounterPathBuffer) { G_FREE(CurrentContext->CounterPathBuffer); } CurrentContext->CounterPathBuffer = G_ALLOC(CurrentSize); if (CurrentContext->CounterPathBuffer == NULL) { Status = PDH_MEMORY_ALLOCATION_FAILURE; goto Cleanup; } for (i = 0; i < CurrentContext->LoggerCount; i ++) { if (! IsListEmpty(& CurrentContext->LogInfo[i].CounterPathList)) { PLIST_ENTRY PathHead = & CurrentContext->LogInfo[i].CounterPathList; PLIST_ENTRY PathNext = PathHead->Flink; PPDH_COUNTER_PATH pCurrentPath; while (Status == ERROR_SUCCESS && PathNext != PathHead) { PVOID ptrTemp; pCurrentPath = CONTAINING_RECORD(PathNext, PDH_COUNTER_PATH, Entry); PathNext = PathNext->Flink; ptrTemp = CurrentContext->CounterPathBuffer; CurrentContext->CounterPathBuffer = G_REALLOC( ptrTemp, CurrentSize + pCurrentPath->CounterPathSize); if (CurrentContext->CounterPathBuffer == NULL) { G_FREE(ptrTemp); Status = PDH_MEMORY_ALLOCATION_FAILURE; goto Cleanup; } pCounterPath = (PVOID) (((PUCHAR) CurrentContext->CounterPathBuffer) + CurrentSize); RtlCopyMemory(pCounterPath, pCurrentPath->CounterPathBuffer, pCurrentPath->CounterPathSize); CurrentSize += pCurrentPath->CounterPathSize; } } } pBinLogHeader = (PPDHI_BINARY_LOG_HEADER_RECORD) CurrentContext->CounterPathBuffer; RtlZeroMemory(pBinLogHeader, sizeof(PDHI_BINARY_LOG_HEADER_RECORD)); pBinLogHeader->RecHeader.dwType = BINLOG_TYPE_CATALOG_LIST; pBinLogHeader->Info.dwLogVersion = BINLOG_VERSION; pBinLogHeader->RecHeader.dwLength = CurrentSize; CurrentContext->bCounterPathChanged = FALSE; } else if (CurrentContext->CounterPathBuffer == NULL) { return PDH_ENTRY_NOT_IN_LOG_FILE; } else { CurrentSize = ((PPDHI_BINARY_LOG_HEADER_RECORD) CurrentContext->CounterPathBuffer)->RecHeader.dwLength; } if (pRecord != NULL) { if (dwMaxSize < CurrentSize) { CurrentSize = dwMaxSize; Status = PDH_MORE_DATA; } RtlCopyMemory(pRecord, CurrentContext->CounterPathBuffer, CurrentSize); } Cleanup: return Status; } ULONG WINAPI PdhWmiFirstBufferCallback( PEVENT_TRACE_LOGFILEW LogFile) { UNREFERENCED_PARAMETER(LogFile); return TRUE; } ULONG WINAPI PdhWmiBufferCallback( PEVENT_TRACE_LOGFILEW LogFile) { ULONG bResult; PPDH_LOGGER_CONTEXT CurrentContext; UNREFERENCED_PARAMETER(LogFile); CurrentContext = GetCurrentContext(); bResult = (CurrentContext && CurrentContext->LoggerState == PdhProcessTraceNormal) ? (TRUE) : (FALSE); return bResult; } void WINAPI PdhWmiFirstEventCallback( PEVENT_TRACE pEvent) { DWORD dwMofHeader; DWORD dwCurrentBlock; DWORD dwTotalBlocks; PPDH_LOGGER_CONTEXT CurrentContext; CurrentContext = GetCurrentContext(); if (pEvent == NULL) { goto Cleanup; } else if (IsEqualGUID(& pEvent->Header.Guid, & EventTraceGuid)) { goto Cleanup; } else if (! IsEqualGUID(& pEvent->Header.Guid, & PdhTransactionGuid)) { goto Cleanup; } else if (CurrentContext == NULL) { goto Cleanup; } dwMofHeader = (pEvent->Header.Class.Version >= PDH_EVENT_VERSION) ? (sizeof(GUID) + sizeof(DWORD) + sizeof(DWORD)) : (sizeof(GUID)); switch (pEvent->Header.Class.Type) { case PDH_LOG_HEADER_EVENT: assert(pEvent->MofLength >= sizeof(PDH_WMI_LOG_INFO) + sizeof(GUID)); PdhiAddWmiLogFileGuid(CurrentContext, (LPGUID) pEvent->MofData); if (pEvent->Header.Class.Version >= PDH_EVENT_VERSION) { dwCurrentBlock = * (DWORD *) (((LPBYTE) pEvent->MofData) + sizeof(GUID)); dwTotalBlocks = * (DWORD *) (((LPBYTE) pEvent->MofData) + sizeof(GUID) + sizeof(DWORD)); PdhiAddCounterPathRecord( CurrentContext, pEvent, (LPGUID) pEvent->MofData, pEvent->MofLength - dwMofHeader, (PVOID) (((PUCHAR) pEvent->MofData) + dwMofHeader), pEvent->Header.TimeStamp.QuadPart, dwCurrentBlock, dwTotalBlocks, & CurrentContext->bCounterPathChanged); } else { dwCurrentBlock = dwTotalBlocks = 1; PdhiAddCounterPathRecord( CurrentContext, pEvent, (LPGUID) pEvent->MofData, pEvent->MofLength - sizeof(GUID) - sizeof(PDH_WMI_LOG_INFO), (PVOID) (((PUCHAR) pEvent->MofData) + sizeof(GUID) + sizeof(PDH_WMI_LOG_INFO)), pEvent->Header.TimeStamp.QuadPart, dwCurrentBlock, dwTotalBlocks, & CurrentContext->bCounterPathChanged); } break; case PDH_LOG_DATA_BLOCK_EVENT: PdhWmiGetDataBlockTimeStamp(CurrentContext, pEvent, TRUE); PdhiWmiComputeCounterBlocks(CurrentContext, pEvent); break; case PDH_LOG_COUNTER_STRING_EVENT: PdhiAddWmiLogFileGuid(CurrentContext, (LPGUID) pEvent->MofData); PdhiAddPerfMachine(CurrentContext, pEvent->MofData, pEvent->MofLength); break; default: DebugPrint((4, "PdhWmiFirstEventCallback(), unknown EventType %d\n", pEvent->Header.Class.Type)); break; } Cleanup: return; } void WINAPI PdhWmiEventCallback( PEVENT_TRACE pEvent) { LPGUID pLogFileGuid; ULONG iLogFile; BOOLEAN bNotifyPDH = FALSE; ULONGLONG EventTime = 0; ULONGLONG EventTimePrev = 0; DWORD dwNumDataBlocks = 0; DWORD dwBlockIndex = 0; DWORD dwBufferSize = 0; PPDH_LOGGER_CONTEXT CurrentContext = GetCurrentContext(); if (CurrentContext == NULL) { goto Cleanup; } if (pEvent == NULL) { DebugPrint((4, "PdhWmiEventCallback() with NULL PEVENT_TRACE\n")); goto Cleanup; } else if (IsEqualGUID(& pEvent->Header.Guid, & EventTraceGuid)) { goto Cleanup; } else if ((CurrentContext->LoggerState != PdhProcessTraceNormal) || (! IsEqualGUID(& pEvent->Header.Guid, & PdhTransactionGuid))) { goto Cleanup; } switch (pEvent->Header.Class.Type) { case PDH_LOG_HEADER_EVENT: case PDH_LOG_COUNTER_STRING_EVENT: // counter path information has been collected during the first run // break; case PDH_LOG_DATA_BLOCK_EVENT: pLogFileGuid = (LPGUID) pEvent->MofData; iLogFile = PdhiFindLogFileGuid(CurrentContext, pLogFileGuid); if (iLogFile >= CurrentContext->LoggerCount) { break; } EventTimePrev = CurrentContext->LogInfo[iLogFile].TimePrev; EventTime = PdhWmiGetDataBlockTimeStamp(CurrentContext, pEvent, FALSE); if (EventTime == 0 || EventTimePrev > EventTime) { break; } if ( pEvent->Header.Class.Version < PDH_EVENT_VERSION || EventTimePrev < EventTime) { dwNumDataBlocks = * (DWORD *) ( ((LPBYTE) pEvent->MofData) + sizeof(GUID) + sizeof(DWORD)); dwBufferSize = (pEvent->Header.Class.Version >= PDH_EVENT_VERSION) ? (dwNumDataBlocks * PDH_BLOCK_BUFFER_SIZE + sizeof(GUID)) : (pEvent->MofLength); if (CurrentContext->LogInfo[iLogFile].DataBlock == NULL) { CurrentContext->LogInfo[iLogFile].DataBlock = G_ALLOC(dwBufferSize); } else if ( CurrentContext->LogInfo[iLogFile].DataBlockAlloc < dwBufferSize) { PVOID ptrTemp = CurrentContext->LogInfo[iLogFile].DataBlock; CurrentContext->LogInfo[iLogFile].DataBlock = G_REALLOC(ptrTemp, dwBufferSize); if (CurrentContext->LogInfo[iLogFile].DataBlock == NULL) { G_FREE(ptrTemp); } } if ( (CurrentContext->LogInfo[iLogFile].DataBlock != NULL) && (pEvent->Header.Class.Version >= PDH_EVENT_VERSION)) { RtlCopyMemory(CurrentContext->LogInfo[iLogFile].DataBlock, pLogFileGuid, sizeof(GUID)); CurrentContext->LogInfo[iLogFile].DataBlockSize = sizeof(GUID); CurrentContext->LogInfo[iLogFile].DataBlockAlloc = dwBufferSize; CurrentContext->LogInfo[iLogFile].ulNumDataBlocks = dwNumDataBlocks; CurrentContext->LogInfo[iLogFile].ulDataBlocksCopied = 0; } } dwBlockIndex = * (DWORD *) (((LPBYTE) pEvent->MofData) + sizeof(GUID)); if (CurrentContext->LogInfo[iLogFile].DataBlock != NULL) { if (pEvent->Header.Class.Version >= PDH_EVENT_VERSION) { PVOID ptrDataBlock = (PVOID) ( ((LPBYTE) CurrentContext->LogInfo[iLogFile].DataBlock) + sizeof(GUID) + PDH_BLOCK_BUFFER_SIZE * (dwBlockIndex - 1)); RtlCopyMemory(ptrDataBlock, (PVOID) (((LPBYTE) pEvent->MofData) + sizeof(GUID) + sizeof(DWORD) + sizeof(DWORD)), pEvent->MofLength - sizeof(GUID) - sizeof(DWORD) - sizeof(DWORD)); CurrentContext->LogInfo[iLogFile].ulDataBlocksCopied ++; CurrentContext->LogInfo[iLogFile].DataBlockSize += pEvent->MofLength - sizeof(GUID) - sizeof(DWORD) - sizeof(DWORD); } else { RtlCopyMemory(CurrentContext->LogInfo[iLogFile].DataBlock, pEvent->MofData, pEvent->MofLength); CurrentContext->LogInfo[iLogFile].DataBlockSize = pEvent->MofLength; } } if (pEvent->Header.Class.Version < PDH_EVENT_VERSION) { if (DataBlockInfo.CurrentTime == (ULONGLONG) 0) { // no CurrentTime comparison, just get the data block // DataBlockInfo.CurrentTime = EventTime; } if (DataBlockInfo.CurrentTime <= EventTime) { DataBlockInfo.pRecord = CurrentContext->LogInfo[iLogFile].DataBlock; DataBlockInfo.dwCurrentSize = pEvent->MofLength; DataBlockInfo.Status = ERROR_SUCCESS; bNotifyPDH = TRUE; CurrentContext->bDataBlockProcessed = FALSE; } } else if ( CurrentContext->LogInfo[iLogFile].ulDataBlocksCopied >= CurrentContext->LogInfo[iLogFile].ulNumDataBlocks) { if (DataBlockInfo.CurrentTime == (ULONGLONG) 0) { // no CurrentTime comparison, just get the data block // DataBlockInfo.CurrentTime = EventTime; } if (DataBlockInfo.CurrentTime <= EventTime) { DataBlockInfo.pRecord = CurrentContext->LogInfo[iLogFile].DataBlock; DataBlockInfo.dwCurrentSize = CurrentContext->LogInfo[iLogFile].DataBlockSize; DataBlockInfo.Status = ERROR_SUCCESS; bNotifyPDH = TRUE; CurrentContext->bDataBlockProcessed = FALSE; } } break; default: DebugPrint((4, "PdhWmiEventCallback(), unknown EventType %d\n", pEvent->Header.Class.Type)); break; } Cleanup: if (bNotifyPDH) { // Signal that we get the current DataBlock event, then wait for next // DataBlock requests. // SetEvent(CurrentContext->hSyncPDH); WaitForSingleObject(CurrentContext->hSyncWMI, INFINITE); } } PDH_FUNCTION PdhProcessLog( PPDH_LOGGER_CONTEXT CurrentContext) { PDH_STATUS Status = ERROR_SUCCESS; LONG i; if (GetLoggerContext(CurrentContext) >= ContextCount) { return PDH_INVALID_HANDLE; } CurrentContext->bFirstRun = TRUE; CurrentContext->dwThread = GetCurrentThreadId(); do { CurrentContext->LoggerState = PdhProcessTraceNormal; CurrentContext->bFirstDataBlockRead = FALSE; CurrentContext->bDataBlockProcessed = FALSE; for (i = 0; i < (LONG) CurrentContext->LoggerCount; i ++) { CurrentContext->LogInfo[i].TimePrev = 0; if (CurrentContext->LogInfo[i].DataBlock) { G_FREE(CurrentContext->LogInfo[i].DataBlock); CurrentContext->LogInfo[i].DataBlock = NULL; } CurrentContext->LogInfo[i].DataBlockSize = 0; } RtlZeroMemory(& DataBlockInfo, sizeof(PDH_DATA_BLOCK_TRANSFER)); Status = ProcessTrace(CurrentContext->LogFileHandle, CurrentContext->LogFileCount, NULL, NULL); if (Status != ERROR_SUCCESS && Status != ERROR_CANCELLED) { DebugPrint((4, "ProcessTrace(0x%08X,%d) fails (%d,0x%08X)\n", CurrentContext, CurrentContext->LogFileCount, Status, Status)); } if (CurrentContext->bFirstRun) { CurrentContext->bFirstRun = FALSE; CurrentContext->LoggerState = PdhProcessTraceRewind; CurrentContext->TimeFreq = CurrentContext->LogInfo[0].TimeFreq; for (i = 1; i < (LONG) CurrentContext->LogFileCount; i ++) { if ( CurrentContext->TimeFreq > CurrentContext->LogInfo[i].TimeFreq) { CurrentContext->TimeFreq = CurrentContext->LogInfo[i].TimeFreq; } } } else if (CurrentContext->LoggerState == PdhProcessTraceNormal) { CurrentContext->LoggerState = PdhProcessTraceComplete; DataBlockInfo.Status = PDH_END_OF_LOG_FILE; // Wake up PDH main thread so that PdhiReadNextWmiRecord() will // notice END_OF_LOG_FILE condition. Wait PDH main thread to wake // me up and rewind logger. After wake up, LoggerState should // be reset to PdhProcessTraceNormal. // SetEvent(CurrentContext->hSyncPDH); Status = WaitForSingleObject(CurrentContext->hSyncWMI, INFINITE); assert(CurrentContext->LoggerState == PdhProcessTraceRewind); } for (i = 0; i < (LONG) CurrentContext->LogFileCount; i ++) { Status = CloseTrace(CurrentContext->LogFileHandle[i]); if (Status != ERROR_SUCCESS) { DebugPrint((4, "CloseTrace(%d,%ws) fails (%d,0x%08X)\n", CurrentContext->LogFileHandle[i], CurrentContext->LogFileName[i], Status, Status)); } } if (CurrentContext->LoggerState == PdhProcessTraceRewind) { EVENT_TRACE_LOGFILEW EvmFile; for (i = 0; i < (LONG) CurrentContext->LogFileCount; i ++) { RtlZeroMemory(& EvmFile, sizeof(EVENT_TRACE_LOGFILE)); EvmFile.BufferCallback = PdhWmiBufferCallback; EvmFile.EventCallback = PdhWmiEventCallback; EvmFile.LogFileName = CurrentContext->LogFileName[i]; CurrentContext->LogFileHandle[i] = OpenTraceW(& EvmFile); if ( CurrentContext->LogFileHandle[i] == 0 || CurrentContext->LogFileHandle[i] == (TRACEHANDLE) INVALID_HANDLE_VALUE) { DebugPrint((4,"OpenTraceW(%d,%ws) fails\n", i, CurrentContext->LogFileName[i])); while (--i >= 0) { CloseTrace(CurrentContext->LogFileHandle[i]); } Status = PDH_LOG_FILE_OPEN_ERROR; DataBlockInfo.Status = PDH_LOG_FILE_OPEN_ERROR; SetEvent(CurrentContext->hSyncPDH); goto Cleanup; } } } } while (CurrentContext->LoggerState == PdhProcessTraceRewind); Cleanup: CurrentContext->LoggerState = PdhProcessTraceExit; return Status; } PDH_FUNCTION PdhiOpenInputWmiLog( IN PPDHI_LOG pLog) { PDH_STATUS Status = ERROR_SUCCESS; PPDHI_LOG pLogCurrent = pLog; PPDH_LOGGER_CONTEXT CurrentContext; EVENT_TRACE_LOGFILEW EvmFile; WCHAR LogFileName[PDH_MAX_PATH]; LONG i; DWORD ThreadId; CurrentContext = (PPDH_LOGGER_CONTEXT) pLog->lpMappedFileBase; if (CurrentContext != NULL) { if (GetLoggerContext(CurrentContext) < ContextCount) { CurrentContext->RefCount ++; pLog->lpMappedFileBase = (PVOID) CurrentContext; return ERROR_SUCCESS; } else { DebugPrint((4, "PdhiOpenInputWmiLog(0x%08X,0x%08X,0x%08X)\n", pLog, pLog->lpMappedFileBase, CurrentContext)); return PDH_INVALID_ARGUMENT; } } CurrentContext = (PPDH_LOGGER_CONTEXT) G_ALLOC(sizeof(PDH_LOGGER_CONTEXT)); if (CurrentContext == NULL) { Status = PDH_MEMORY_ALLOCATION_FAILURE; goto Cleanup; } pLog->lpMappedFileBase = (PVOID) CurrentContext; RtlZeroMemory(CurrentContext, sizeof(PDH_LOGGER_CONTEXT)); for (i = 0; i < PDH_MAX_LOGFILES && pLogCurrent; i ++) { CurrentContext->LogFileName[i] = pLogCurrent->szLogFileName; pLogCurrent = pLogCurrent->NextLog; } CurrentContext->LogFileCount = i; CurrentContext->LoggerCount = 0; for (i = 0; i < (LONG) CurrentContext->LogFileCount; i ++) { InitializeListHead(& CurrentContext->LogInfo[i].CounterPathList); InitializeListHead(& CurrentContext->LogInfo[i].PerfMachineList); } CurrentContext->RefCount = 1; CurrentContext->hSyncWMI = CreateEvent(NULL, FALSE, FALSE, NULL); CurrentContext->hSyncPDH = CreateEvent(NULL, FALSE, FALSE, NULL); if (CurrentContext->hSyncWMI == NULL || CurrentContext->hSyncPDH == NULL) { Status = PDH_INVALID_HANDLE; goto Cleanup; } Status = WAIT_FOR_AND_LOCK_MUTEX(hPdhContextMutex); if (Status == ERROR_SUCCESS) { if (ContextCount < PDH_MAX_LOGFILES) { ContextTable[ContextCount] = CurrentContext; ContextCount ++; } else { Status = PDH_MEMORY_ALLOCATION_FAILURE; } RELEASE_MUTEX(hPdhContextMutex); } if (Status != ERROR_SUCCESS) { goto Cleanup; } for (i = 0; i < (LONG) CurrentContext->LogFileCount; i ++) { RtlZeroMemory(& EvmFile, sizeof(EVENT_TRACE_LOGFILE)); EvmFile.BufferCallback = PdhWmiFirstBufferCallback; EvmFile.EventCallback = PdhWmiFirstEventCallback; EvmFile.LogFileName = LogFileName; _wfullpath(EvmFile.LogFileName, CurrentContext->LogFileName[i], PDH_MAX_PATH); CurrentContext->LogFileHandle[i] = OpenTraceW(& EvmFile); if ( CurrentContext->LogFileHandle[i] == 0 || CurrentContext->LogFileHandle[i] == (TRACEHANDLE) INVALID_HANDLE_VALUE) { DebugPrint((4,"OpenTraceW(%d,%ws) fails\n", i, CurrentContext->LogFileName[i])); while (--i >= 0) { CloseTrace(CurrentContext->LogFileHandle[i]); } Status = PDH_LOG_FILE_OPEN_ERROR; goto Cleanup; } } CurrentContext->hThreadWork = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE) PdhProcessLog, CurrentContext, 0, (LPDWORD) & ThreadId); if (CurrentContext->hThreadWork == NULL) { Status = GetLastError(); DebugPrint((4, "CreateThread() fails (%d,0x%08X)\n", Status, Status)); for (i = 0; i < (LONG) CurrentContext->LogFileCount; i ++) { Status = CloseTrace(CurrentContext->LogFileHandle[i]); if (Status != ERROR_SUCCESS) { DebugPrint((4, "CloseTrace(0x%08X,%ws) fails (%d,0x%08X)\n", CurrentContext->LogFileHandle[i], CurrentContext->LogFileName[i], Status, Status)); } } goto Cleanup; } WaitForSingleObject(CurrentContext->hSyncPDH, INFINITE); Cleanup: if (Status != ERROR_SUCCESS) { if (CurrentContext != NULL) { DWORD dwContext = GetLoggerContext(CurrentContext); if (dwContext < ContextCount) { if ( WAIT_FOR_AND_LOCK_MUTEX(hPdhContextMutex) == ERROR_SUCCESS) { if (dwContext != ContextCount - 1) { ContextTable[dwContext] = ContextTable[ContextCount - 1]; } ContextTable[ContextCount - 1] = NULL; ContextCount --; RELEASE_MUTEX(hPdhContextMutex); } else { ContextTable[dwContext] = NULL; } } if (CurrentContext->hSyncWMI) { CloseHandle(CurrentContext->hSyncWMI); } if (CurrentContext->hSyncPDH) { CloseHandle(CurrentContext->hSyncPDH); } G_FREE(CurrentContext); CurrentContext = NULL; } pLog->lpMappedFileBase = NULL; } return Status; } PDH_FUNCTION PdhiRewindWmiLog( IN PPDHI_LOG pLog) { PDH_STATUS Status = PDH_INVALID_HANDLE; PPDH_LOGGER_CONTEXT CurrentContext; CurrentContext = (PPDH_LOGGER_CONTEXT) pLog->lpMappedFileBase; if (GetLoggerContext(CurrentContext) < ContextCount) { CurrentContext->LoggerState = PdhProcessTraceRewind; SetEvent(CurrentContext->hSyncWMI); WaitForSingleObject(CurrentContext->hSyncPDH, INFINITE); Status = ERROR_SUCCESS; } return Status; } PDH_FUNCTION PdhiReadWmiHeaderRecord( IN PPDHI_LOG pLog, IN LPVOID pRecord, IN DWORD dwMaxSize) { PDH_STATUS Status = ERROR_SUCCESS; PPDH_LOGGER_CONTEXT CurrentContext = (PPDH_LOGGER_CONTEXT) pLog->lpMappedFileBase; if (GetLoggerContext(CurrentContext) >= ContextCount) { return PDH_INVALID_HANDLE; } // Wait until logfiles are scaned first to collect // 1) Counter Path information // 2) Time Range information // while (CurrentContext->bFirstRun) { _sleep(1); } Status = PdhiGetCounterPathRecord(CurrentContext, pRecord, dwMaxSize); pLog->pLastRecordRead = CurrentContext->CounterPathBuffer; return Status; } PDH_FUNCTION PdhiBuildDataBlock( IN PPDHI_LOG pLog, IN ULONGLONG TimeStamp) { PDH_STATUS pdhStatus = ERROR_SUCCESS; LONG Offset = sizeof(PDHI_BINARY_LOG_RECORD_HEADER); LONG CopySize; LONG CheckSize; ULONG i; LONG CurrentSize = PDH_WMI_BUFFER_SIZE_BYTE; PPDH_LOGGER_CONTEXT CurrentContext; PPDHI_BINARY_LOG_RECORD_HEADER pHeader; PVOID pBlock; PPDHI_BINARY_LOG_RECORD_HEADER pCounterHeader; PPDH_RAW_COUNTER pSingleCounter; PPDHI_LOG_COUNTER_PATH pCounterPath; BOOLEAN bValidBlock; CurrentContext = (PPDH_LOGGER_CONTEXT) pLog->lpMappedFileBase; if (GetLoggerContext(CurrentContext) >= ContextCount) { return PDH_INVALID_HANDLE; } if (CurrentContext->tmpBuffer != NULL) { G_FREE(CurrentContext->tmpBuffer); CurrentContext->tmpBuffer = NULL; } pHeader = (PPDHI_BINARY_LOG_RECORD_HEADER) G_ALLOC(PDH_WMI_BUFFER_SIZE_BYTE); if (pHeader == NULL) { return PDH_MEMORY_ALLOCATION_FAILURE; } pHeader->dwType = BINLOG_TYPE_DATA; for (i = 0; i < CurrentContext->LoggerCount; i ++) { CopySize = CurrentContext->LogInfo[i].DataBlockSize - sizeof(GUID) - sizeof(PDHI_BINARY_LOG_RECORD_HEADER); bValidBlock = TRUE; if (Offset + CopySize > CurrentSize) { while (Offset + CopySize > CurrentSize) { CurrentSize += PDH_WMI_BUFFER_SIZE_BYTE; } CurrentContext->tmpBuffer = pHeader; pHeader = G_REALLOC(CurrentContext->tmpBuffer, CurrentSize); if (pHeader == NULL) { G_FREE(CurrentContext->tmpBuffer); CurrentContext->tmpBuffer = NULL; return PDH_MEMORY_ALLOCATION_FAILURE; } CurrentContext->tmpBuffer = NULL; } pBlock = (PVOID) (((PUCHAR) pHeader) + Offset); if ( (CurrentContext->LogInfo[i].DataBlock) && (CopySize > 0) && ( DataBlockInfo.CurrentTime <= CurrentContext->LogInfo[i].TimeEnd)) { CheckSize = sizeof(GUID); while (bValidBlock && CheckSize < CopySize) { pCounterHeader = (PPDHI_BINARY_LOG_RECORD_HEADER) (((PUCHAR) CurrentContext->LogInfo[i].DataBlock) + CheckSize); if (LOWORD(pCounterHeader->dwType) == BINLOG_START_WORD) { CheckSize += pCounterHeader->dwLength; } else { bValidBlock = FALSE; } } } else { bValidBlock = FALSE; } if (bValidBlock == TRUE) { RtlCopyMemory( pBlock, (PVOID) ( ((PUCHAR) CurrentContext->LogInfo[i].DataBlock) + sizeof(GUID) + sizeof(PDHI_BINARY_LOG_RECORD_HEADER)), CopySize); Offset += CopySize; } else { // need to sneak in pseudo counter block // PVOID pCounterBlock; ULONG BlockSize = 0; ULONG j; for (j = 0; j < CurrentContext->LogInfo[i].ulCounters; j ++) { pBlock = (PVOID) (((PUCHAR) pHeader) + Offset); RtlCopyMemory(pBlock, & PdhNullCounterHeader, sizeof(PDHI_BINARY_LOG_RECORD_HEADER)); pSingleCounter = (PPDH_RAW_COUNTER) (((PUCHAR) pBlock) + sizeof(PDHI_BINARY_LOG_RECORD_HEADER)); RtlCopyMemory(pSingleCounter, & PdhNullCounter, sizeof(PDH_RAW_COUNTER)); pSingleCounter->TimeStamp.dwLowDateTime = LODWORD(TimeStamp); pSingleCounter->TimeStamp.dwHighDateTime = HIDWORD(TimeStamp); Offset = Offset + sizeof(PDH_RAW_COUNTER) + sizeof(PDHI_BINARY_LOG_RECORD_HEADER); } } } pHeader->dwLength = Offset; CurrentContext->tmpBuffer = pHeader; return pdhStatus; } PDH_FUNCTION PdhiReadNextWmiRecord( IN PPDHI_LOG pLog, IN LPVOID pRecord, IN DWORD dwMaxSize, IN BOOLEAN bAllCounter) { PDH_STATUS Status = ERROR_SUCCESS; PPDH_LOGGER_CONTEXT CurrentContext; ULONGLONG CurrentTime; CurrentContext = (PPDH_LOGGER_CONTEXT) pLog->lpMappedFileBase; if (GetLoggerContext(CurrentContext) >= ContextCount) { Status = PDH_INVALID_HANDLE; goto Cleanup; } // Wait until logfiles are scaned first to collect // 1) Counter Path information // 2) Time Range information // while (CurrentContext->bFirstRun) { _sleep(1); } if (CurrentContext->LoggerState == PdhProcessTraceComplete) { CurrentContext->LoggerState = PdhProcessTraceRewind; SetEvent(CurrentContext->hSyncWMI); WaitForSingleObject(CurrentContext->hSyncPDH, INFINITE); Status = PDH_END_OF_LOG_FILE; goto Cleanup; } if (! CurrentContext->bFirstDataBlockRead) { CurrentContext->bFirstDataBlockRead = TRUE; CurrentContext->bDataBlockProcessed = TRUE; } else if (! CurrentContext->bDataBlockProcessed) { CurrentContext->bDataBlockProcessed = TRUE; } else { DataBlockInfo.CurrentTime = (ULONGLONG) 0; SetEvent(CurrentContext->hSyncWMI); WaitForSingleObject(CurrentContext->hSyncPDH, INFINITE); } if (CurrentContext->LoggerState == PdhProcessTraceComplete) { CurrentContext->LoggerState = PdhProcessTraceRewind; SetEvent(CurrentContext->hSyncWMI); WaitForSingleObject(CurrentContext->hSyncPDH, INFINITE); Status = PDH_END_OF_LOG_FILE; goto Cleanup; } if (bAllCounter && CurrentContext->LogFileCount > 1) { CurrentTime = DataBlockInfo.CurrentTime; while ( (CurrentContext->LoggerState != PdhProcessTraceComplete) && (DataBlockInfo.CurrentTime - CurrentTime <= TIME_DELTA)) { DataBlockInfo.CurrentTime = (ULONGLONG) 0; SetEvent(CurrentContext->hSyncWMI); WaitForSingleObject(CurrentContext->hSyncPDH, INFINITE); } CurrentContext->bDataBlockProcessed = FALSE; Status = DataBlockInfo.Status; if (Status == ERROR_SUCCESS) { Status = PdhiBuildDataBlock(pLog, CurrentTime); } if (Status == ERROR_SUCCESS) { pLog->pLastRecordRead = CurrentContext->tmpBuffer; } } else { if (bAllCounter) { pLog->pLastRecordRead = (((PUCHAR) DataBlockInfo.pRecord) + sizeof(GUID)); } else { pLog->pLastRecordRead = ((PUCHAR) DataBlockInfo.pRecord); } CurrentContext->bDataBlockProcessed = TRUE; Status = DataBlockInfo.Status; } if (Status == ERROR_SUCCESS) { if (dwMaxSize < DataBlockInfo.dwCurrentSize - sizeof(GUID)) { Status = PDH_MORE_DATA; } if (pRecord) { RtlCopyMemory(pRecord, pLog->pLastRecordRead, (Status == ERROR_SUCCESS) ? (DataBlockInfo.dwCurrentSize) : (dwMaxSize)); } } Cleanup: return Status; } PDH_FUNCTION PdhiReadTimeWmiRecord( IN PPDHI_LOG pLog, IN ULONGLONG TimeStamp, IN LPVOID pRecord, IN DWORD dwMaxSize) { PDH_STATUS Status = ERROR_SUCCESS; PPDH_LOGGER_CONTEXT CurrentContext; BOOLEAN TimeInRange = FALSE; BOOLEAN bRewind = TRUE; ULONG i; CurrentContext = (PPDH_LOGGER_CONTEXT) pLog->lpMappedFileBase; if (GetLoggerContext(CurrentContext) >= ContextCount) { Status = PDH_INVALID_HANDLE; goto Cleanup; } if (TimeStamp == MIN_TIME_VALUE) { TimeStamp = CurrentContext->LogInfo[0].TimeStart; } if (TimeStamp == MAX_TIME_VALUE) { TimeStamp = CurrentContext->LogInfo[0].TimeEnd; } for (i = 0; i < (ULONG) CurrentContext->LoggerCount; i ++) { if ( TimeStamp >= CurrentContext->LogInfo[i].TimeStart && TimeStamp <= CurrentContext->LogInfo[i].TimeEnd) { TimeInRange = TRUE; break; } } if (! TimeInRange) { Status = PDH_INVALID_ARGUMENT; goto Cleanup; } // Wait until logfiles are scaned first to collect // 1) Counter Path information // 2) Time Range information // while (CurrentContext->bFirstRun) { _sleep(1); } if (CurrentContext->LoggerState == PdhProcessTraceComplete) { CurrentContext->LoggerState = PdhProcessTraceRewind; SetEvent(CurrentContext->hSyncWMI); WaitForSingleObject(CurrentContext->hSyncPDH, INFINITE); Status = PDH_END_OF_LOG_FILE; goto Cleanup; } ReScan: if (! CurrentContext->bFirstDataBlockRead) { CurrentContext->bFirstDataBlockRead = TRUE; CurrentContext->bDataBlockProcessed = TRUE; } else if (! CurrentContext->bDataBlockProcessed) { CurrentContext->bDataBlockProcessed = TRUE; } else { DataBlockInfo.CurrentTime = 0; SetEvent(CurrentContext->hSyncWMI); WaitForSingleObject(CurrentContext->hSyncPDH, INFINITE); } if (CurrentContext->LoggerState == PdhProcessTraceComplete) { CurrentContext->LoggerState = PdhProcessTraceRewind; SetEvent(CurrentContext->hSyncWMI); WaitForSingleObject(CurrentContext->hSyncPDH, INFINITE); Status = PDH_END_OF_LOG_FILE; goto Cleanup; } else if (DataBlockInfo.CurrentTime > TimeStamp) { if (bRewind) { bRewind = FALSE; CurrentContext->LoggerState = PdhProcessTraceRewind; SetEvent(CurrentContext->hSyncWMI); WaitForSingleObject(CurrentContext->hSyncPDH, INFINITE); goto ReScan; } } while ( (CurrentContext->LoggerState != PdhProcessTraceComplete) && (( ((LONGLONG) TimeStamp) - ((LONGLONG) DataBlockInfo.CurrentTime)) > TIME_DELTA)) { DataBlockInfo.CurrentTime = (ULONGLONG) 0; SetEvent(CurrentContext->hSyncWMI); WaitForSingleObject(CurrentContext->hSyncPDH, INFINITE); } CurrentContext->bDataBlockProcessed = TRUE; Status = DataBlockInfo.Status; if (Status == ERROR_SUCCESS) { Status = PdhiBuildDataBlock(pLog, TimeStamp); } if (Status == ERROR_SUCCESS) { pLog->pLastRecordRead = CurrentContext->tmpBuffer; } if (Status == ERROR_SUCCESS) { if (dwMaxSize < DataBlockInfo.dwCurrentSize - sizeof(GUID)) { Status = PDH_MORE_DATA; } if (pRecord) { RtlCopyMemory(pRecord, (((PUCHAR) DataBlockInfo.pRecord) + sizeof(GUID)), (Status == ERROR_SUCCESS) ? (DataBlockInfo.dwCurrentSize) : (dwMaxSize)); } } Cleanup: return Status; } PDH_FUNCTION PdhiGetTimeRangeFromWmiLog ( IN PPDHI_LOG pLog, IN LPDWORD pdwNumEntries, IN PPDH_TIME_INFO pInfo, IN LPDWORD pdwBufferSize) { PDH_STATUS Status = ERROR_SUCCESS; PPDH_LOGGER_CONTEXT CurrentContext; ULONG i; ULONGLONG StartTime; ULONGLONG EndTime; ULONG EntryCount; CurrentContext = (PPDH_LOGGER_CONTEXT) pLog->lpMappedFileBase; if (GetLoggerContext(CurrentContext) >= ContextCount) { return PDH_INVALID_HANDLE; } // Wait until logfiles are scaned first to collect // 1) Counter Path information // 2) Time Range information // while (CurrentContext->bFirstRun) { _sleep(1); } for (StartTime = CurrentContext->LogInfo[0].TimeStart, EndTime = CurrentContext->LogInfo[0].TimeEnd, EntryCount = CurrentContext->LogInfo[0].ValidEntries, i = 1; i < CurrentContext->LoggerCount; i ++) { if ( StartTime == 0 || ( CurrentContext->LogInfo[i].TimeStart != 0 && StartTime > CurrentContext->LogInfo[i].TimeStart)) { StartTime = CurrentContext->LogInfo[i].TimeStart; } if (EndTime < CurrentContext->LogInfo[i].TimeEnd) EndTime = CurrentContext->LogInfo[i].TimeEnd; EntryCount += CurrentContext->LogInfo[i].ValidEntries; } if (* pdwBufferSize >= sizeof(PDH_TIME_INFO)) { * (LONGLONG *) (& pInfo->StartTime) = StartTime; * (LONGLONG *) (& pInfo->EndTime) = EndTime; pInfo->SampleCount = EntryCount; * pdwBufferSize = sizeof(PDH_TIME_INFO); * pdwNumEntries = 1; } else { Status = PDH_MORE_DATA; } return Status; } PPDH_WMI_PERF_MACHINE PdhWmiGetLogNameTable( IN PPDHI_LOG pLog, IN LPCWSTR szMachineName, IN DWORD dwLangId ) { PPDH_WMI_PERF_MACHINE pReturnMachine = NULL; PPDH_LOGGER_CONTEXT CurrentContext; DWORD i; CurrentContext = (PPDH_LOGGER_CONTEXT) pLog->lpMappedFileBase; if (GetLoggerContext(CurrentContext) >= ContextCount) { return NULL; } for (i = 0; pReturnMachine == NULL && i < CurrentContext->LoggerCount; i ++) { if (! IsListEmpty(& CurrentContext->LogInfo[i].PerfMachineList)) { PLIST_ENTRY pHead = & CurrentContext->LogInfo[i].PerfMachineList; PLIST_ENTRY pNext = pHead->Flink; while (pNext != pHead) { PPDH_WMI_PERF_MACHINE pMachine = CONTAINING_RECORD(pNext, PDH_WMI_PERF_MACHINE, Entry); if (lstrcmpiW(pMachine->pszBuffer, szMachineName) == 0) { pReturnMachine = pMachine; break; } pNext = pNext->Flink; } } } return pReturnMachine; } PPDH_WMI_PERF_OBJECT PdhWmiAddPerfObject( IN PPDHI_LOG pLog, IN LPCWSTR szMachineName, IN DWORD dwLangId, IN LPCWSTR szObjectName, IN DWORD dwObjectId, IN PPERF_DATA_BLOCK pDataBlock ) { PPDH_WMI_PERF_OBJECT pPerfObject = NULL; PPDH_WMI_PERF_MACHINE pPerfMachine = PdhWmiGetLogNameTable(pLog, szMachineName, dwLangId); PLIST_ENTRY pHead; PLIST_ENTRY pNext; PPDH_WMI_PERF_OBJECT pCurrentObj; if (pPerfMachine == NULL) { SetLastError(PDH_ENTRY_NOT_IN_LOG_FILE); goto Cleanup; } pHead = & pPerfMachine->LogObjectList; pNext = pHead->Flink; while (pNext != pHead) { pCurrentObj = CONTAINING_RECORD(pNext, PDH_WMI_PERF_OBJECT, Entry); if (lstrcmpiW(pCurrentObj->szObjectName, szObjectName) == 0) { pPerfObject = pCurrentObj; break; } pNext = pNext->Flink; } if (pPerfObject != NULL) { goto Cleanup; } pPerfObject = G_ALLOC(sizeof(PDH_WMI_PERF_OBJECT)); if (pPerfObject == NULL) { SetLastError(PDH_MEMORY_ALLOCATION_FAILURE); goto Cleanup; } pPerfObject->ptrBuffer = G_ALLOC(pDataBlock->TotalByteLength + sizeof(WCHAR) * (lstrlenW(szObjectName) + 1)); if (pPerfObject->ptrBuffer == NULL) { G_FREE(pPerfObject); SetLastError(PDH_MEMORY_ALLOCATION_FAILURE); goto Cleanup; } pPerfObject->dwObjectId = dwObjectId; RtlCopyMemory(pPerfObject->ptrBuffer, pDataBlock, pDataBlock->TotalByteLength); pPerfObject->szObjectName = (LPWSTR) (((LPBYTE) pPerfObject->ptrBuffer) + pDataBlock->TotalByteLength); lstrcpyW(pPerfObject->szObjectName, szObjectName); InsertTailList(& pPerfMachine->LogObjectList, & pPerfObject->Entry); Cleanup: return pPerfObject; } DWORD PdhWmiGetLogPerfIndexByName( IN PPDHI_LOG pLog, IN LPCWSTR szMachineName, IN DWORD dwLangId, IN LPCWSTR szNameBuffer ) { PPDH_WMI_PERF_MACHINE pMachine; DWORD dwLastIndex; LPWSTR * pNameArray; DWORD dwIndex; SetLastError(ERROR_SUCCESS); pMachine = PdhWmiGetLogNameTable(pLog, szMachineName, dwLangId); if (pMachine != NULL && pMachine->ptrStrAry != NULL) { dwLastIndex = pMachine->dwLastId; pNameArray = pMachine->ptrStrAry; for (dwIndex = 1; dwIndex <= dwLastIndex; dwIndex ++) { if (lstrcmpiW(szNameBuffer, pNameArray[dwIndex]) == 0) { if ((dwIndex & 0x00000001) == 0) { // counter name index should be even integer // break; } } } if (dwIndex > dwLastIndex) { SetLastError(PDH_STRING_NOT_FOUND); dwIndex = 0; } } else { SetLastError(PDH_ENTRY_NOT_IN_LOG_FILE); dwIndex = 0; } return dwIndex; } LPWSTR PdhWmiGetLogPerfNameByIndex ( IN PPDHI_LOG pLog, IN LPCWSTR szMachineName, IN DWORD dwLangId, IN DWORD dwIndex ) { PPDH_WMI_PERF_MACHINE pMachine; LPWSTR pszReturnName = NULL; LPWSTR * pNameArray; static WCHAR szNumber[16]; pMachine = PdhWmiGetLogNameTable(pLog, szMachineName, dwLangId); if (pMachine != NULL && pMachine->ptrStrAry != NULL && dwIndex < pMachine->dwLastId) { pNameArray = pMachine->ptrStrAry; pszReturnName = pNameArray[dwIndex]; } if (pszReturnName == NULL) { // unable to find name string, return numeric index string // memset(szNumber, 0, sizeof (szNumber)); _ltow(dwIndex, szNumber, 10); pszReturnName = szNumber; } return pszReturnName; } PPDHI_BINARY_LOG_RECORD_HEADER PdhiGetWmiSubRecord( IN PPDHI_LOG pLog, IN PPDHI_BINARY_LOG_RECORD_HEADER pRecord, IN DWORD dwRecordId, IN LPGUID LogFileGuid) { PPDHI_BINARY_LOG_RECORD_HEADER pThisRecord; PPDH_LOGGER_CONTEXT CurrentContext; DWORD dwRecordType; DWORD dwRecordLength; DWORD dwBytesProcessed; DWORD dwThisSubRecordId; DWORD dwLocalIndex; ULONG i; CurrentContext = (PPDH_LOGGER_CONTEXT) pLog->lpMappedFileBase; if (GetLoggerContext(CurrentContext) >= ContextCount) { return (NULL); } dwLocalIndex = dwRecordId; for (i = 0; i < CurrentContext->LoggerCount; i ++) { PLIST_ENTRY pHead = & CurrentContext->LogInfo[i].CounterPathList; if (! IsListEmpty(pHead)) { PLIST_ENTRY pNext = pHead->Flink; PPDH_COUNTER_PATH pCounterPath = CONTAINING_RECORD(pNext, PDH_COUNTER_PATH, Entry); if (dwLocalIndex <= pCounterPath->CounterCount) { break; } dwLocalIndex -= pCounterPath->CounterCount; } } assert(i < CurrentContext->LoggerCount); __try { if ( (i >= CurrentContext->LoggerCount) || (! IsEqualGUID( LogFileGuid, & CurrentContext->LogInfo[i].LogFileGuid))) { // binary log record does not contain intended object's counter // return NULL; } } __except(EXCEPTION_EXECUTE_HANDLER) { return NULL; } dwRecordType = ((PPDHI_BINARY_LOG_RECORD_HEADER) pRecord)->dwType; dwRecordLength = ((PPDHI_BINARY_LOG_RECORD_HEADER) pRecord)->dwLength; pThisRecord = (PPDHI_BINARY_LOG_RECORD_HEADER) (((LPBYTE) pRecord) + sizeof(PDHI_BINARY_LOG_RECORD_HEADER)); dwBytesProcessed = sizeof(PDHI_BINARY_LOG_RECORD_HEADER); if (dwBytesProcessed < dwRecordLength) { dwThisSubRecordId = 1; while (dwThisSubRecordId < dwLocalIndex) { if ((WORD)(pThisRecord->dwType & 0x0000FFFF) == BINLOG_START_WORD) { dwBytesProcessed += pThisRecord->dwLength; pThisRecord = (PPDHI_BINARY_LOG_RECORD_HEADER) (((LPBYTE)pThisRecord) + pThisRecord->dwLength); if (dwBytesProcessed >= dwRecordLength) { break; } else { dwThisSubRecordId ++; } } else { break; } } } else { dwThisSubRecordId = 0; } if (dwThisSubRecordId == dwLocalIndex) { if ((WORD)(pThisRecord->dwType & 0x0000FFFF) != BINLOG_START_WORD) { pThisRecord = NULL; } } else { pThisRecord = NULL; } return pThisRecord; } PDH_FUNCTION PdhWmiEnumObjectItemsFromDataBlock( IN PPDHI_LOG pLog, IN PPERF_DATA_BLOCK pDataBlock, IN LPCWSTR szMachineName, IN LPCWSTR szObjectName, IN DWORD dwObjectId, IN DWORD dwLangId, IN PDHI_COUNTER_TABLE CounterTable ) { PDH_STATUS Status = ERROR_SUCCESS; PERF_OBJECT_TYPE * pObjectDef = GetObjectDefByTitleIndex(pDataBlock, dwObjectId); PERF_COUNTER_DEFINITION * pCountDef; PERF_INSTANCE_DEFINITION * pInstDef; DWORD dwItems; LPWSTR szItemName; DWORD dwItemLen; WCHAR szInstanceName[1024]; PPDHI_INST_LIST pInstList = NULL; PPDHI_INSTANCE pInstance = NULL; PPDHI_INST_LIST pFirstInstList = NULL; PPDH_WMI_PERF_OBJECT pPerfObj; if (pObjectDef == NULL) { Status = PDH_ENTRY_NOT_IN_LOG_FILE; goto Cleanup; } pPerfObj = PdhWmiAddPerfObject(pLog, szMachineName, 9, szObjectName, dwObjectId, pDataBlock); if (pPerfObj == NULL) { Status = GetLastError(); goto Cleanup; } dwItems = 0; pCountDef = FirstCounter(pObjectDef); while (dwItems < (DWORD) pObjectDef->NumCounters) { szItemName = PdhWmiGetLogPerfNameByIndex( pLog, szMachineName, dwLangId, pCountDef->CounterNameTitleIndex); Status = PdhiFindCounterInstList( CounterTable, szItemName, & pInstList); if (Status == ERROR_SUCCESS && pFirstInstList == NULL && pInstList != NULL) { pFirstInstList = pInstList; } dwItems ++; pCountDef = NextCounter(pCountDef); } if (pFirstInstList == NULL) { Status = PDH_NO_COUNTERS; goto Cleanup; } if (pObjectDef->NumInstances != PERF_NO_INSTANCES) { dwItems = 0; pInstDef = FirstInstance(pObjectDef); while (dwItems < (DWORD) pObjectDef->NumInstances) { ZeroMemory(szInstanceName, sizeof(WCHAR) * 1024); dwItemLen = GetFullInstanceNameStr( pDataBlock, pObjectDef, pInstDef, szInstanceName); if (dwItemLen > 0) { Status = PdhiFindInstance( & pFirstInstList->InstList, szInstanceName, (lstrcmpiW(szInstanceName, L"_Total") == 0) ? FALSE : TRUE, & pInstance); } dwItems ++; pInstDef = NextInstance(pInstDef); } } Cleanup: return Status; } PDH_FUNCTION PdhiEnumObjectItemsFromWmiLog ( IN PPDHI_LOG pLog, IN LPCWSTR szMachineName, IN LPCWSTR szObjectName, IN PDHI_COUNTER_TABLE CounterTable, IN DWORD dwDetailLevel, IN DWORD dwFlags ) { DWORD dwTempBufferSize; LPVOID pTempBuffer = NULL; LPVOID ptrTemp; PDH_STATUS pdhStatus = ERROR_SUCCESS; PPDHI_BINARY_LOG_HEADER_RECORD pHeader; PPDHI_LOG_COUNTER_PATH pPath; PPDHI_BINARY_LOG_RECORD_HEADER pThisMasterRecord; PPDHI_BINARY_LOG_RECORD_HEADER pThisSubRecord; PPDHI_RAW_COUNTER_ITEM_BLOCK pDataBlock; PPDHI_RAW_COUNTER_ITEM pDataItem; DWORD dwBytesProcessed; LONG nItemCount = 0; LPBYTE pFirstChar; LPWSTR szThisMachineName = NULL; LPWSTR szThisObjectName = NULL; LPWSTR szThisCounterName = NULL; LPWSTR szThisInstanceName = NULL; LPWSTR szThisParentName; WCHAR szCompositeInstance[1024]; DWORD dwRecordLength; BOOL bCopyThisObject; BOOL bMachineDataBlockScaned = FALSE; BOOL bInstanceListScanned = FALSE; DWORD dwIndex; DWORD dwDataItemIndex; DWORD dwObjectId; PPERF_DATA_BLOCK pPerfBlock; PPDHI_INST_LIST pInstList = NULL; PPDHI_INSTANCE pInstance = NULL; PPDH_LOGGER_CONTEXT CurrentContext; UNREFERENCED_PARAMETER (dwDetailLevel); UNREFERENCED_PARAMETER (dwFlags); CurrentContext = (PPDH_LOGGER_CONTEXT) pLog->lpMappedFileBase; if (GetLoggerContext(CurrentContext) >= ContextCount) { pdhStatus = PDH_INVALID_ARGUMENT; goto Cleanup; } if (pLog->dwMaxRecordSize == 0) { // no size is defined so start with 64K pLog->dwMaxRecordSize = 0x010000; } dwTempBufferSize = pLog->dwMaxRecordSize; pTempBuffer = G_ALLOC(dwTempBufferSize); if (pTempBuffer == NULL) { pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE; goto Cleanup; } // read in the catalog record pdhStatus = PdhiReadWmiHeaderRecord(pLog, pTempBuffer, dwTempBufferSize); while (pdhStatus == PDH_MORE_DATA) { if (* (WORD *) pTempBuffer == BINLOG_START_WORD) { dwTempBufferSize = ((DWORD *) pTempBuffer)[1]; if (dwTempBufferSize < pLog->dwMaxRecordSize) { pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE; } else { pLog->dwMaxRecordSize = dwTempBufferSize; } } else { pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE; } ptrTemp = pTempBuffer; pTempBuffer = G_REALLOC(ptrTemp, dwTempBufferSize); if (pTempBuffer == NULL) { G_FREE(ptrTemp); pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE; } if (pdhStatus == PDH_MORE_DATA) { pdhStatus = PdhiReadWmiHeaderRecord( pLog, pTempBuffer, dwTempBufferSize); } } if (pdhStatus != ERROR_SUCCESS) { goto Cleanup; } pHeader = (PPDHI_BINARY_LOG_HEADER_RECORD) pTempBuffer; dwRecordLength = ((PPDHI_BINARY_LOG_RECORD_HEADER) pTempBuffer)->dwLength; pPath = (PPDHI_LOG_COUNTER_PATH) ((LPBYTE) pTempBuffer + sizeof(PDHI_BINARY_LOG_HEADER_RECORD)); dwBytesProcessed = sizeof(PDHI_BINARY_LOG_HEADER_RECORD); dwIndex = 0; while (dwBytesProcessed < dwRecordLength) { bCopyThisObject = FALSE; szThisObjectName = NULL; dwIndex ++; pFirstChar = (LPBYTE) & pPath->Buffer[0]; if (pPath->lMachineNameOffset >= 0L) { szThisMachineName = (LPWSTR) ( (LPBYTE) pFirstChar + pPath->lMachineNameOffset); if (lstrcmpiW(szThisMachineName, szMachineName) == 0) { if (pPath->dwFlags & PDHIC_COUNTER_BLOCK) { if (bMachineDataBlockScaned == FALSE) { bCopyThisObject = TRUE; bMachineDataBlockScaned = TRUE; } } else if (pPath->lObjectNameOffset >= 0) { szThisObjectName = (LPWSTR) ( (LPBYTE) pFirstChar + pPath->lObjectNameOffset); if (lstrcmpiW(szThisObjectName, szObjectName) == 0) { bCopyThisObject = TRUE; } } } } else if (pPath->lObjectNameOffset >= 0) { szThisObjectName = (LPWSTR) ( (LPBYTE) pFirstChar + pPath->lObjectNameOffset); if (lstrcmpiW(szThisObjectName, szObjectName) == 0) { bCopyThisObject = TRUE; } } dwObjectId = 0; if (bCopyThisObject) { if ( (pPath->dwFlags & PDHIC_COUNTER_OBJECT) || (pPath->dwFlags & PDHIC_COUNTER_BLOCK)) { dwObjectId = PdhWmiGetLogPerfIndexByName( pLog, szMachineName, 9, szObjectName); if (dwObjectId == 0) { dwObjectId = wcstoul(szObjectName, NULL, 10); if (dwObjectId == 0) { szThisCounterName = NULL; bCopyThisObject = FALSE; } } } else if (pPath->lCounterOffset > 0) { szThisCounterName = (LPWSTR) ( (LPBYTE)pFirstChar + pPath->lCounterOffset); } else { szThisCounterName = NULL; bCopyThisObject = FALSE; } } if (bCopyThisObject) { if (dwObjectId == 0) { pdhStatus = PdhiFindCounterInstList( CounterTable, szThisCounterName, & pInstList); if (pdhStatus == ERROR_SUCCESS && pInstList != NULL) { nItemCount ++; } } if (pPath->lInstanceOffset >= 0) { szThisInstanceName = (LPWSTR) ( (LPBYTE) pFirstChar + pPath->lInstanceOffset); } if ( dwObjectId > 0 || (pInstList != NULL && szThisInstanceName != NULL)) { if (szThisInstanceName && * szThisInstanceName != SPLAT_L) { if (pPath->lParentOffset >= 0) { szThisParentName = (LPWSTR) ((LPBYTE) pFirstChar + pPath->lParentOffset); lstrcpyW(szCompositeInstance, szThisParentName); lstrcatW(szCompositeInstance, cszSlash); lstrcatW(szCompositeInstance, szThisInstanceName); } else { lstrcpyW(szCompositeInstance, szThisInstanceName); } if (pPath->dwIndex > 0 && pPath->dwIndex != PERF_NO_UNIQUE_ID) { lstrcatW(szCompositeInstance, L"#"); _ltow(pPath->dwIndex, (LPWSTR)( szCompositeInstance + lstrlenW(szCompositeInstance)), 10L); } pdhStatus = PdhiFindInstance( & pInstList->InstList, szCompositeInstance, (lstrcmpiW(szCompositeInstance, L"_Total") == 0) ? FALSE : TRUE, & pInstance); if (pdhStatus == ERROR_SUCCESS && pInstance != NULL) { nItemCount ++; } } else if (dwObjectId > 0 || !bInstanceListScanned) { pdhStatus = PdhiRewindWmiLog(pLog); if (pdhStatus == ERROR_SUCCESS) { pdhStatus = PdhiReadNextWmiRecord( pLog, NULL, 0, FALSE); while ( pdhStatus == ERROR_SUCCESS || pdhStatus == PDH_MORE_DATA) { PdhiResetInstanceCount(CounterTable); pdhStatus = ERROR_SUCCESS; pThisMasterRecord = (PPDHI_BINARY_LOG_RECORD_HEADER) ( ((PUCHAR) pLog->pLastRecordRead) + sizeof(GUID)); pThisSubRecord = PdhiGetWmiSubRecord( pLog, pThisMasterRecord, dwIndex, (LPGUID)(pLog->pLastRecordRead)); if (pThisSubRecord == NULL) { // this data record does not contain // counter record for selected object, // skip to next one. // pdhStatus = PdhiReadNextWmiRecord( pLog, NULL, 0, FALSE); continue; } if (pThisSubRecord->dwType == BINLOG_TYPE_DATA_OBJECT || pThisSubRecord->dwType == BINLOG_TYPE_DATA_LOC_OBJECT) { pPerfBlock = (PPERF_DATA_BLOCK) ((LPBYTE)pThisSubRecord + sizeof (PDHI_BINARY_LOG_RECORD_HEADER)); pdhStatus = PdhWmiEnumObjectItemsFromDataBlock( pLog, pPerfBlock, szMachineName, szObjectName, dwObjectId, 9, CounterTable); if (pdhStatus == PDH_ENTRY_NOT_IN_LOG_FILE) { pdhStatus = ERROR_SUCCESS; } } else { pDataBlock = (PPDHI_RAW_COUNTER_ITEM_BLOCK) ((LPBYTE)pThisSubRecord + sizeof (PDHI_BINARY_LOG_RECORD_HEADER)); if (pDataBlock->dwLength > 0) { for (dwDataItemIndex = 0; dwDataItemIndex < pDataBlock->dwItemCount; dwDataItemIndex++) { pDataItem = & pDataBlock->pItemArray[dwDataItemIndex]; szThisInstanceName = (LPWSTR) (((LPBYTE) pDataBlock) + pDataItem->szName); pdhStatus = PdhiFindInstance( & pInstList->InstList, szThisInstanceName, (lstrcmpiW(szThisInstanceName, L"_Total") == 0) ? FALSE : TRUE, & pInstance); if (pdhStatus == ERROR_SUCCESS) { nItemCount++; } } } } if (pdhStatus != ERROR_SUCCESS) { break; } else { pdhStatus = PdhiReadNextWmiRecord(pLog, NULL, 0, FALSE); } } if (pdhStatus == PDH_END_OF_LOG_FILE) { pdhStatus = ERROR_SUCCESS; } if (pdhStatus == ERROR_SUCCESS) { bInstanceListScanned = TRUE; } } } } } ZeroMemory(szCompositeInstance, sizeof(szCompositeInstance)); dwBytesProcessed += pPath->dwLength; pPath = (PPDHI_LOG_COUNTER_PATH) ( (LPBYTE) pPath + pPath->dwLength); } if ((nItemCount > 0) && (pdhStatus != PDH_INSUFFICIENT_BUFFER) && (pdhStatus != PDH_MORE_DATA)) { pdhStatus = ERROR_SUCCESS; } Cleanup: if (pTempBuffer != NULL) G_FREE(pTempBuffer); return pdhStatus; } PDH_FUNCTION PdhiGetWmiLogCounterInfo( IN PPDHI_LOG pLog, IN PPDHI_COUNTER pCounter) { PDH_STATUS Status = ERROR_SUCCESS; DWORD dwObjectId = PdhWmiGetLogPerfIndexByName( pLog, pCounter->pCounterPath->szMachineName, 9, pCounter->pCounterPath->szObjectName); DWORD dwCounterId = wcstoul(pCounter->pCounterPath->szCounterName, NULL, 10); PPDH_WMI_PERF_MACHINE pMachine = NULL; PPDH_WMI_PERF_OBJECT pObject = NULL; PLIST_ENTRY pHead; PLIST_ENTRY pNext; PPERF_DATA_BLOCK pDataBlock = NULL; PERF_OBJECT_TYPE * pPerfObject = NULL; DWORD dwItems = 0; PERF_COUNTER_DEFINITION * pPerfCounter; PERF_INSTANCE_DEFINITION * pPerfInstance; PPDH_LOGGER_CONTEXT CurrentContext; BOOL bNeedEnumerate = TRUE; CurrentContext = (PPDH_LOGGER_CONTEXT) pLog->lpMappedFileBase; if (GetLoggerContext(CurrentContext) < ContextCount) { pMachine = PdhWmiGetLogNameTable(pLog, pCounter->pCounterPath->szMachineName, 9); if (pMachine == NULL) { Status = PDH_ENTRY_NOT_IN_LOG_FILE; goto Cleanup; } pHead = & pMachine->LogObjectList; pNext = pHead->Flink; while (pNext != pHead) { pObject = CONTAINING_RECORD(pNext, PDH_WMI_PERF_OBJECT, Entry); if (pObject->dwObjectId == dwObjectId) { bNeedEnumerate = FALSE; break; } pNext = pNext->Flink; } if (bNeedEnumerate) { DWORD dwCounterSize = 0; DWORD dwInstanceSize = 0; Status = PdhiEnumLoggedObjectItems( (HLOG) pLog, pCounter->pCounterPath->szMachineName, pCounter->pCounterPath->szObjectName, NULL, & dwCounterSize, NULL, & dwInstanceSize, 0, 0, TRUE); if (Status != ERROR_SUCCESS && Status != PDH_MORE_DATA && Status != PDH_INSUFFICIENT_BUFFER) { goto Cleanup; } Status = ERROR_SUCCESS; } } else { Status = PDH_INVALID_ARGUMENT; goto Cleanup; } if (dwObjectId == 0) { dwObjectId = wcstoul(pCounter->pCounterPath->szObjectName, NULL, 10); if (dwObjectId != 0) { Status = ERROR_SUCCESS; } else { Status = PDH_ENTRY_NOT_IN_LOG_FILE; } } else { Status = ERROR_SUCCESS; } if (Status != ERROR_SUCCESS) { goto Cleanup; } pMachine = PdhWmiGetLogNameTable(pLog, pCounter->pCounterPath->szMachineName, 9); if (pMachine == NULL) { Status = PDH_ENTRY_NOT_IN_LOG_FILE; goto Cleanup; } pHead = & pMachine->LogObjectList; pNext = pHead->Flink; while (pNext != pHead) { PPDH_WMI_PERF_OBJECT pThisObject = CONTAINING_RECORD( pNext, PDH_WMI_PERF_OBJECT, Entry); if (pThisObject->dwObjectId == dwObjectId) { pObject = pThisObject; break; } pNext = pNext->Flink; } if (pObject == NULL) { Status = PDH_ENTRY_NOT_IN_LOG_FILE; goto Cleanup; } pDataBlock = (PPERF_DATA_BLOCK) pObject->ptrBuffer; if (pDataBlock == NULL) { Status = PDH_ENTRY_NOT_IN_LOG_FILE; goto Cleanup; } pPerfObject = GetObjectDefByTitleIndex(pDataBlock, dwObjectId); if (pPerfObject == NULL) { Status = PDH_CSTATUS_NO_OBJECT; goto Cleanup; } dwItems = 0; pPerfCounter = FirstCounter(pPerfObject); while (dwItems < pPerfObject->NumCounters) { if ( pPerfCounter->CounterNameTitleIndex > 0 && pPerfCounter->CounterNameTitleIndex <= pMachine->dwLastId) { if (lstrcmpiW(pCounter->pCounterPath->szCounterName, pMachine->ptrStrAry[pPerfCounter->CounterNameTitleIndex]) == 0) { break; } if ( dwCounterId != 0 && dwCounterId == pPerfCounter->CounterNameTitleIndex) { break; } } dwItems ++; if (dwItems < pPerfObject->NumCounters) { pPerfCounter = NextCounter(pPerfCounter); if (pPerfCounter == NULL) { break; } } else { pPerfCounter = NULL; } } if (dwItems == pPerfObject->NumCounters) { pPerfCounter = NULL; } if (pPerfCounter == NULL) { Status = PDH_CSTATUS_NO_OBJECT; goto Cleanup; } pCounter->plCounterInfo.dwObjectId = dwObjectId; pCounter->plCounterInfo.dwCounterId = pPerfCounter->CounterNameTitleIndex; pCounter->plCounterInfo.dwCounterType = pPerfCounter->CounterType; pCounter->plCounterInfo.dwCounterSize = pPerfCounter->CounterSize; pCounter->plCounterInfo.lDefaultScale = pPerfCounter->DefaultScale; if (pCounter->plCounterInfo.dwCounterType & PERF_TIMER_100NS) { pCounter->TimeBase = (LONGLONG) 10000000; } else if (pCounter->plCounterInfo.dwCounterType & PERF_OBJECT_TIMER) { pCounter->TimeBase = pPerfObject->PerfFreq.QuadPart; } else { pCounter->TimeBase = pDataBlock->PerfFreq.QuadPart; } if (pPerfObject->NumInstances == PERF_NO_INSTANCES) { pCounter->plCounterInfo.lInstanceId = 0; pCounter->plCounterInfo.szInstanceName = NULL; pCounter->plCounterInfo.dwParentObjectId = 0; pCounter->plCounterInfo.szParentInstanceName = NULL; } else { pPerfInstance = FirstInstance(pPerfObject); if (pPerfInstance->UniqueID == PERF_NO_UNIQUE_ID) { pCounter->plCounterInfo.lInstanceId = PERF_NO_UNIQUE_ID; pCounter->plCounterInfo.szInstanceName = pCounter->pCounterPath->szInstanceName; pCounter->plCounterInfo.dwParentObjectId = (DWORD)PERF_NO_UNIQUE_ID; pCounter->plCounterInfo.szParentInstanceName = pCounter->pCounterPath->szParentName; } else { LONG lTempId; if (pCounter->pCounterPath->szInstanceName != NULL) { lTempId = wcstoul(pCounter->pCounterPath->szInstanceName, NULL, 10); } else { lTempId = 0; } pCounter->plCounterInfo.lInstanceId = lTempId; pCounter->plCounterInfo.szInstanceName = NULL; if (pCounter->pCounterPath->szParentName != NULL) { lTempId = wcstoul(pCounter->pCounterPath->szParentName, NULL, 10); } else { lTempId = 0; } pCounter->plCounterInfo.dwParentObjectId = lTempId; pCounter->plCounterInfo.szParentInstanceName = NULL; } } Cleanup: return Status; } PDH_FUNCTION PdhiGetWmiLogFileSize( IN PPDHI_LOG pLog, IN LONGLONG * llSize) { PDH_STATUS pdhStatus = ERROR_SUCCESS; LONGLONG SizeSum = 0; DWORD dwFileSizeLow; DWORD dwFileSizeHigh; DWORD dwError; HANDLE hFile; if (pLog->dwLogFormat & PDH_LOG_WRITE_ACCESS) { PPDH_EVENT_TRACE_PROPERTIES LoggerInfo = (PPDH_EVENT_TRACE_PROPERTIES) pLog->lpMappedFileBase; if (LoggerInfo != NULL && LoggerInfo->LogFileName != NULL && LoggerInfo->LogFileName[0] != L'\0') { hFile = CreateFileW( LoggerInfo->LogFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == NULL || hFile == INVALID_HANDLE_VALUE) { DWORD Win32Error = GetLastError(); switch (Win32Error) { case ERROR_FILE_NOT_FOUND: pdhStatus = PDH_FILE_NOT_FOUND; break; case ERROR_ALREADY_EXISTS: pdhStatus = PDH_FILE_ALREADY_EXISTS; break; default: pdhStatus = PDH_LOG_FILE_OPEN_ERROR; break; } } else { dwFileSizeLow = GetFileSize(hFile, & dwFileSizeHigh); if ( (dwFileSizeLow == 0xFFFFFFFF) && ((dwError = GetLastError()) != NO_ERROR)) { pdhStatus = PDH_LOG_FILE_OPEN_ERROR; } else { if (dwFileSizeHigh != 0) { SizeSum += (dwFileSizeHigh << (sizeof(DWORD) * 8)); } SizeSum += dwFileSizeLow; } CloseHandle(hFile); } } else { pdhStatus = PDH_INVALID_ARGUMENT; } } else { PPDH_LOGGER_CONTEXT CurrentContext = (PPDH_LOGGER_CONTEXT) pLog->lpMappedFileBase; if (GetLoggerContext(CurrentContext) < ContextCount) { LONG i; for (i = 0, hFile = NULL, dwFileSizeLow = 0, dwFileSizeHigh = 0; (pdhStatus == ERROR_SUCCESS) && (i < (LONG) CurrentContext->LogFileCount); i ++, hFile = NULL, dwFileSizeLow = 0, dwFileSizeHigh = 0) { hFile = CreateFileW( CurrentContext->LogFileName[i], GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == NULL || hFile == INVALID_HANDLE_VALUE) { DWORD Win32Error = GetLastError(); switch (Win32Error) { case ERROR_FILE_NOT_FOUND: pdhStatus = PDH_FILE_NOT_FOUND; break; case ERROR_ALREADY_EXISTS: pdhStatus = PDH_FILE_ALREADY_EXISTS; break; default: pdhStatus = PDH_LOG_FILE_OPEN_ERROR; break; } break; } dwFileSizeLow = GetFileSize(hFile, & dwFileSizeHigh); if ( (dwFileSizeLow == 0xFFFFFFFF) && ((dwError = GetLastError()) != NO_ERROR)) { pdhStatus = PDH_LOG_FILE_OPEN_ERROR; } else { if (dwFileSizeHigh != 0) { SizeSum = SizeSum + (dwFileSizeHigh << (sizeof(DWORD) * 8)); } SizeSum += dwFileSizeLow; } CloseHandle(hFile); } } else { pdhStatus = PDH_INVALID_ARGUMENT; } } if (pdhStatus == ERROR_SUCCESS) { __try { * llSize = SizeSum; } __except (EXCEPTION_EXECUTE_HANDLER) { pdhStatus = PDH_INVALID_ARGUMENT; } } return pdhStatus; }