4104 lines
148 KiB
C
4104 lines
148 KiB
C
/*++
|
|
|
|
Copyright (C) 1996-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
log_wmi.c
|
|
|
|
Abstract:
|
|
|
|
<abstract>
|
|
|
|
--*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <assert.h>
|
|
#include <pdh.h>
|
|
#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 <initguid.h>
|
|
#include <wmistr.h>
|
|
#include <ntwmi.h>
|
|
#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;
|
|
}
|