1779 lines
71 KiB
C#
1779 lines
71 KiB
C#
//
|
|
// Copyright (C) Microsoft. All rights reserved.
|
|
//
|
|
|
|
using System;
|
|
using System.Diagnostics;
|
|
using System.Globalization;
|
|
using System.Runtime.InteropServices;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Specialized;
|
|
using System.Runtime.InteropServices.ComTypes;
|
|
using Microsoft.PowerShell.Commands.GetCounter;
|
|
using Microsoft.Win32;
|
|
|
|
namespace Microsoft.Powershell.Commands.GetCounter.PdhNative
|
|
{
|
|
internal static class PdhResults
|
|
{
|
|
public const long PDH_CSTATUS_VALID_DATA = 0x0L;
|
|
public const long PDH_CSTATUS_NEW_DATA = 0x1L;
|
|
public const long PDH_CSTATUS_NO_MACHINE = 0x800007D0L;
|
|
public const long PDH_CSTATUS_NO_INSTANCE = 0x800007D1L;
|
|
public const long PDH_MORE_DATA = 0x800007D2L;
|
|
public const long PDH_CSTATUS_ITEM_NOT_VALIDATED = 0x800007D3L;
|
|
public const long PDH_RETRY = 0x800007D4L;
|
|
public const long PDH_NO_DATA = 0x800007D5L;
|
|
public const long PDH_CALC_NEGATIVE_DENOMINATOR = 0x800007D6L;
|
|
public const long PDH_CALC_NEGATIVE_TIMEBASE = 0x800007D7L;
|
|
public const long PDH_CALC_NEGATIVE_VALUE = 0x800007D8L;
|
|
public const long PDH_DIALOG_CANCELLED = 0x800007D9L;
|
|
public const long PDH_END_OF_LOG_FILE = 0x800007DAL;
|
|
public const long PDH_ASYNC_QUERY_TIMEOUT = 0x800007DBL;
|
|
public const long PDH_CANNOT_SET_DEFAULT_REALTIME_DATASOURCE = 0x800007DCL;
|
|
public const long PDH_UNABLE_MAP_NAME_FILES = 0x80000BD5L;
|
|
public const long PDH_PLA_VALIDATION_WARNING = 0x80000BF3L;
|
|
public const long PDH_CSTATUS_NO_OBJECT = 0xC0000BB8L;
|
|
public const long PDH_CSTATUS_NO_COUNTER = 0xC0000BB9L;
|
|
public const long PDH_CSTATUS_INVALID_DATA = 0xC0000BBAL;
|
|
public const long PDH_MEMORY_ALLOCATION_FAILURE = 0xC0000BBBL;
|
|
public const long PDH_INVALID_HANDLE = 0xC0000BBCL;
|
|
public const long PDH_INVALID_ARGUMENT = 0xC0000BBDL;
|
|
public const long PDH_FUNCTION_NOT_FOUND = 0xC0000BBEL;
|
|
public const long PDH_CSTATUS_NO_COUNTERNAME = 0xC0000BBFL;
|
|
public const long PDH_CSTATUS_BAD_COUNTERNAME = 0xC0000BC0L;
|
|
public const long PDH_INVALID_BUFFER = 0xC0000BC1L;
|
|
public const long PDH_INSUFFICIENT_BUFFER = 0xC0000BC2L;
|
|
public const long PDH_CANNOT_CONNECT_MACHINE = 0xC0000BC3L;
|
|
public const long PDH_INVALID_PATH = 0xC0000BC4L;
|
|
public const long PDH_INVALID_INSTANCE = 0xC0000BC5L;
|
|
public const long PDH_INVALID_DATA = 0xC0000BC6L;
|
|
public const long PDH_NO_DIALOG_DATA = 0xC0000BC7L;
|
|
public const long PDH_CANNOT_READ_NAME_STRINGS = 0xC0000BC8L;
|
|
public const long PDH_LOG_FILE_CREATE_ERROR = 0xC0000BC9L;
|
|
public const long PDH_LOG_FILE_OPEN_ERROR = 0xC0000BCAL;
|
|
public const long PDH_LOG_TYPE_NOT_FOUND = 0xC0000BCBL;
|
|
public const long PDH_NO_MORE_DATA = 0xC0000BCCL;
|
|
public const long PDH_ENTRY_NOT_IN_LOG_FILE = 0xC0000BCDL;
|
|
public const long PDH_DATA_SOURCE_IS_LOG_FILE = 0xC0000BCEL;
|
|
public const long PDH_DATA_SOURCE_IS_REAL_TIME = 0xC0000BCFL;
|
|
public const long PDH_UNABLE_READ_LOG_HEADER = 0xC0000BD0L;
|
|
public const long PDH_FILE_NOT_FOUND = 0xC0000BD1L;
|
|
public const long PDH_FILE_ALREADY_EXISTS = 0xC0000BD2L;
|
|
public const long PDH_NOT_IMPLEMENTED = 0xC0000BD3L;
|
|
public const long PDH_STRING_NOT_FOUND = 0xC0000BD4L;
|
|
public const long PDH_UNKNOWN_LOG_FORMAT = 0xC0000BD6L;
|
|
public const long PDH_UNKNOWN_LOGSVC_COMMAND = 0xC0000BD7L;
|
|
public const long PDH_LOGSVC_QUERY_NOT_FOUND = 0xC0000BD8L;
|
|
public const long PDH_LOGSVC_NOT_OPENED = 0xC0000BD9L;
|
|
public const long PDH_WBEM_ERROR = 0xC0000BDAL;
|
|
public const long PDH_ACCESS_DENIED = 0xC0000BDBL;
|
|
public const long PDH_LOG_FILE_TOO_SMALL = 0xC0000BDCL;
|
|
public const long PDH_INVALID_DATASOURCE = 0xC0000BDDL;
|
|
public const long PDH_INVALID_SQLDB = 0xC0000BDEL;
|
|
public const long PDH_NO_COUNTERS = 0xC0000BDFL;
|
|
public const long PDH_SQL_ALLOC_FAILED = 0xC0000BE0L;
|
|
public const long PDH_SQL_ALLOCCON_FAILED = 0xC0000BE1L;
|
|
public const long PDH_SQL_EXEC_DIRECT_FAILED = 0xC0000BE2L;
|
|
public const long PDH_SQL_FETCH_FAILED = 0xC0000BE3L;
|
|
public const long PDH_SQL_ROWCOUNT_FAILED = 0xC0000BE4L;
|
|
public const long PDH_SQL_MORE_RESULTS_FAILED = 0xC0000BE5L;
|
|
public const long PDH_SQL_CONNECT_FAILED = 0xC0000BE6L;
|
|
public const long PDH_SQL_BIND_FAILED = 0xC0000BE7L;
|
|
public const long PDH_CANNOT_CONNECT_WMI_SERVER = 0xC0000BE8L;
|
|
public const long PDH_PLA_COLLECTION_ALREADY_RUNNING = 0xC0000BE9L;
|
|
public const long PDH_PLA_ERROR_SCHEDULE_OVERLAP = 0xC0000BEAL;
|
|
public const long PDH_PLA_COLLECTION_NOT_FOUND = 0xC0000BEBL;
|
|
public const long PDH_PLA_ERROR_SCHEDULE_ELAPSED = 0xC0000BECL;
|
|
public const long PDH_PLA_ERROR_NOSTART = 0xC0000BEDL;
|
|
public const long PDH_PLA_ERROR_ALREADY_EXISTS = 0xC0000BEEL;
|
|
public const long PDH_PLA_ERROR_TYPE_MISMATCH = 0xC0000BEFL;
|
|
public const long PDH_PLA_ERROR_FILEPATH = 0xC0000BF0L;
|
|
public const long PDH_PLA_SERVICE_ERROR = 0xC0000BF1L;
|
|
public const long PDH_PLA_VALIDATION_ERROR = 0xC0000BF2L;
|
|
public const long PDH_PLA_ERROR_NAME_TOO_LONG = 0xC0000BF4L;
|
|
public const long PDH_INVALID_SQL_LOG_FORMAT = 0xC0000BF5L;
|
|
public const long PDH_COUNTER_ALREADY_IN_QUERY = 0xC0000BF6L;
|
|
public const long PDH_BINARY_LOG_CORRUPT = 0xC0000BF7L;
|
|
public const long PDH_LOG_SAMPLE_TOO_SMALL = 0xC0000BF8L;
|
|
public const long PDH_OS_LATER_VERSION = 0xC0000BF9L;
|
|
public const long PDH_OS_EARLIER_VERSION = 0xC0000BFAL;
|
|
public const long PDH_INCORRECT_APPEND_TIME = 0xC0000BFBL;
|
|
public const long PDH_UNMATCHED_APPEND_COUNTER = 0xC0000BFCL;
|
|
public const long PDH_SQL_ALTER_DETAIL_FAILED = 0xC0000BFDL;
|
|
public const long PDH_QUERY_PERF_DATA_TIMEOUT = 0xC0000BFEL;
|
|
}
|
|
|
|
|
|
|
|
internal static class PerfDetail
|
|
{
|
|
public const uint PERF_DETAIL_NOVICE = 100; // The uninformed can understand it
|
|
public const uint PERF_DETAIL_ADVANCED = 200; // For the advanced user
|
|
public const uint PERF_DETAIL_EXPERT = 300; // For the expert user
|
|
public const uint PERF_DETAIL_WIZARD = 400; // For the system designer
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 2, Size = 16)]
|
|
internal struct SYSTEMTIME
|
|
{
|
|
public UInt16 year;
|
|
public UInt16 month;
|
|
public UInt16 dayOfWeek;
|
|
public UInt16 day;
|
|
public UInt16 hour;
|
|
public UInt16 minute;
|
|
public UInt16 second;
|
|
public UInt16 milliseconds;
|
|
}
|
|
|
|
internal static class PdhFormat
|
|
{
|
|
public const uint PDH_FMT_RAW = 0x00000010;
|
|
public const uint PDH_FMT_ANSI = 0x00000020;
|
|
public const uint PDH_FMT_UNICODE = 0x00000040;
|
|
public const uint PDH_FMT_LONG = 0x00000100;
|
|
public const uint PDH_FMT_DOUBLE = 0x00000200;
|
|
public const uint PDH_FMT_LARGE = 0x00000400;
|
|
public const uint PDH_FMT_NOSCALE = 0x00001000;
|
|
public const uint PDH_FMT_1000 = 0x00002000;
|
|
public const uint PDH_FMT_NODATA = 0x00004000;
|
|
public const uint PDH_FMT_NOCAP100 = 0x00008000;
|
|
public const uint PERF_DETAIL_COSTLY = 0x00010000;
|
|
public const uint PERF_DETAIL_STANDARD = 0x0000FFFF;
|
|
}
|
|
|
|
internal static class PdhLogAccess
|
|
{
|
|
public const uint PDH_LOG_READ_ACCESS = 0x00010000;
|
|
public const uint PDH_LOG_WRITE_ACCESS = 0x00020000;
|
|
public const uint PDH_LOG_UPDATE_ACCESS = 0x00040000;
|
|
public const uint PDH_LOG_ACCESS_MASK = 0x000F0000;
|
|
}
|
|
|
|
internal static class PdhLogOpenMode
|
|
{
|
|
public const uint PDH_LOG_CREATE_NEW = 0x00000001;
|
|
public const uint PDH_LOG_CREATE_ALWAYS = 0x00000002;
|
|
public const uint PDH_LOG_OPEN_ALWAYS = 0x00000003;
|
|
public const uint PDH_LOG_OPEN_EXISTING = 0x00000004;
|
|
public const uint PDH_LOG_CREATE_MASK = 0x0000000F;
|
|
}
|
|
|
|
internal static class PdhLogOpenOption
|
|
{
|
|
public const uint PDH_LOG_OPT_USER_STRING = 0x01000000;
|
|
public const uint PDH_LOG_OPT_CIRCULAR = 0x02000000;
|
|
public const uint PDH_LOG_OPT_MAX_IS_BYTES = 0x04000000;
|
|
public const uint PDH_LOG_OPT_APPEND = 0x08000000;
|
|
}
|
|
|
|
internal enum PdhLogFileType
|
|
{
|
|
PDH_LOG_TYPE_UNDEFINED = 0,
|
|
PDH_LOG_TYPE_CSV = 1,
|
|
PDH_LOG_TYPE_TSV = 2,
|
|
PDH_LOG_TYPE_TRACE_KERNEL = 4,
|
|
PDH_LOG_TYPE_TRACE_GENERIC = 5,
|
|
PDH_LOG_TYPE_PERFMON = 6,
|
|
PDH_LOG_TYPE_SQL = 7,
|
|
PDH_LOG_TYPE_BINARY = 8
|
|
}
|
|
|
|
internal static class PdhWildCardFlag
|
|
{
|
|
public const uint PDH_NOEXPANDCOUNTERS = 1;
|
|
public const uint PDH_NOEXPANDINSTANCES = 2;
|
|
public const uint PDH_REFRESHCOUNTERS = 4;
|
|
}
|
|
|
|
internal struct CounterHandleNInstance
|
|
{
|
|
public IntPtr hCounter;
|
|
public string InstanceName;
|
|
}
|
|
|
|
internal class PdhHelper : IDisposable
|
|
{
|
|
private bool _isPreVista = false;
|
|
|
|
public PdhHelper(bool isPreVista)
|
|
{
|
|
_isPreVista = isPreVista;
|
|
}
|
|
|
|
|
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
|
private struct PDH_COUNTER_PATH_ELEMENTS
|
|
{
|
|
[MarshalAs(UnmanagedType.LPWStr)]
|
|
public string MachineName;
|
|
|
|
[MarshalAs(UnmanagedType.LPWStr)]
|
|
public string ObjectName;
|
|
|
|
[MarshalAs(UnmanagedType.LPWStr)]
|
|
public string InstanceName;
|
|
|
|
[MarshalAs(UnmanagedType.LPWStr)]
|
|
public string ParentInstance;
|
|
|
|
public UInt32 InstanceIndex;
|
|
|
|
[MarshalAs(UnmanagedType.LPWStr)]
|
|
public string CounterName;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
private struct PDH_FMT_COUNTERVALUE_LARGE
|
|
{
|
|
public uint CStatus;
|
|
|
|
public Int64 largeValue;
|
|
|
|
//[FieldOffset (4), MarshalAs(UnmanagedType.LPStr)]
|
|
//public string AnsiStringValue;
|
|
|
|
//[FieldOffset(4), MarshalAs(UnmanagedType.LPWStr)]
|
|
//public string WideStringValue;
|
|
};
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
private struct PDH_FMT_COUNTERVALUE_DOUBLE
|
|
{
|
|
public uint CStatus;
|
|
|
|
public double doubleValue;
|
|
};
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
private struct PDH_FMT_COUNTERVALUE_UNICODE
|
|
{
|
|
public uint CStatus;
|
|
|
|
[MarshalAs(UnmanagedType.LPWStr)]
|
|
public string WideStringValue;
|
|
};
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
private struct PDH_RAW_COUNTER
|
|
{
|
|
public uint CStatus;
|
|
public System.Runtime.InteropServices.ComTypes.FILETIME TimeStamp;
|
|
public Int64 FirstValue;
|
|
public Int64 SecondValue;
|
|
public uint MultiCount;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
private struct PDH_TIME_INFO
|
|
{
|
|
public Int64 StartTime;
|
|
public Int64 EndTime;
|
|
public UInt32 SampleCount;
|
|
}
|
|
|
|
|
|
/*
|
|
//
|
|
// This is the structure returned by PdhGetCounterInfo().
|
|
// We only need dwType and lDefaultScale fields from this structure.
|
|
// We access those fields directly. The struct is here for reference only.
|
|
//
|
|
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
|
|
struct PDH_COUNTER_INFO {
|
|
[FieldOffset(0)] public UInt32 dwLength;
|
|
[FieldOffset(4)] public UInt32 dwType;
|
|
[FieldOffset(8)] public UInt32 CVersion;
|
|
[FieldOffset(12)] public UInt32 CStatus;
|
|
[FieldOffset(16)] public UInt32 lScale;
|
|
[FieldOffset(20)] public UInt32 lDefaultScale;
|
|
[FieldOffset(24)] public IntPtr dwUserData;
|
|
[FieldOffset(32)] public IntPtr dwQueryUserData;
|
|
[FieldOffset(40)] public string szFullPath;
|
|
|
|
[FieldOffset(48)] public string szMachineName;
|
|
[FieldOffset(56)] public string szObjectName;
|
|
[FieldOffset(64)] public string szInstanceName;
|
|
[FieldOffset(72)] public string szParentInstance;
|
|
[FieldOffset(80)] public UInt32 dwInstanceIndex;
|
|
[FieldOffset(88)] public string szCounterName;
|
|
|
|
[FieldOffset(96)] public string szExplainText;
|
|
[FieldOffset(104)]public IntPtr DataBuffer;
|
|
}*/
|
|
|
|
|
|
[DllImport("pdh.dll", CharSet = CharSet.Unicode)]
|
|
private static extern uint PdhBindInputDataSource(out PdhSafeDataSourceHandle phDataSource, string szLogFileNameList);
|
|
|
|
[DllImport("pdh.dll")]
|
|
private static extern uint PdhOpenQueryH(PdhSafeDataSourceHandle hDataSource, IntPtr dwUserData, out PdhSafeQueryHandle phQuery);
|
|
|
|
[DllImport("pdh.dll", CharSet = CharSet.Unicode)]
|
|
private static extern uint PdhAddCounter(PdhSafeQueryHandle queryHandle, string counterPath, IntPtr userData, out IntPtr counterHandle);
|
|
|
|
//Win7+ only
|
|
[DllImport("pdh.dll", CharSet = CharSet.Unicode)]
|
|
private static extern uint PdhAddRelogCounter(PdhSafeQueryHandle queryHandle, string counterPath,
|
|
UInt32 counterType, UInt32 counterDefaultScale,
|
|
UInt64 timeBase, out IntPtr counterHandle);
|
|
|
|
//not on XP
|
|
[DllImport("pdh.dll")]
|
|
private static extern uint PdhCollectQueryDataWithTime(PdhSafeQueryHandle queryHandle, ref Int64 pllTimeStamp);
|
|
|
|
[DllImport("pdh.dll")]
|
|
private static extern uint PdhCollectQueryData(PdhSafeQueryHandle queryHandle);
|
|
|
|
[DllImport("pdh.dll")]
|
|
internal static extern uint PdhCloseQuery(IntPtr queryHandle);
|
|
|
|
[DllImport("pdh.dll")]
|
|
internal static extern uint PdhCloseLog(IntPtr logHandle, uint dwFlags);
|
|
|
|
[DllImport("pdh.dll", CharSet = CharSet.Unicode)]
|
|
private static extern uint PdhOpenLog(string szLogFileName,
|
|
uint dwAccessFlags,
|
|
ref PdhLogFileType lpdwLogType,
|
|
PdhSafeQueryHandle hQuery,
|
|
uint dwMaxSize,
|
|
string szUserCaption,
|
|
out PdhSafeLogHandle phLog
|
|
);
|
|
|
|
//Win7+ only
|
|
[DllImport("pdh.dll", CharSet = CharSet.Unicode)]
|
|
private static extern void PdhResetRelogCounterValues(PdhSafeLogHandle LogHandle);
|
|
|
|
|
|
//Win7+ only
|
|
[DllImport("pdh.dll", CharSet = CharSet.Unicode)]
|
|
private static extern uint PdhSetCounterValue(IntPtr CounterHandle,
|
|
ref PDH_RAW_COUNTER Value, /*PPDH_RAW_COUNTER */
|
|
string InstanceName
|
|
);
|
|
|
|
//Win7+ only
|
|
[DllImport("pdh.dll")]
|
|
private static extern uint PdhWriteRelogSample(PdhSafeLogHandle LogHandle,
|
|
Int64 Timestamp
|
|
);
|
|
|
|
[DllImport("pdh.dll", CharSet = CharSet.Unicode)]
|
|
private static extern uint PdhGetFormattedCounterValue(IntPtr counterHandle, uint dwFormat, out IntPtr lpdwType, out PDH_FMT_COUNTERVALUE_DOUBLE pValue);
|
|
|
|
[DllImport("pdh.dll", CharSet = CharSet.Unicode)]
|
|
private static extern uint PdhGetRawCounterValue(IntPtr hCounter, out IntPtr lpdwType, out PDH_RAW_COUNTER pValue);
|
|
|
|
[DllImport("pdh.dll", CharSet = CharSet.Unicode)]
|
|
private static extern uint PdhEnumMachinesH(PdhSafeDataSourceHandle hDataSource, IntPtr mszMachineNameList, ref IntPtr pcchBufferLength);
|
|
|
|
[DllImport("pdh.dll", CharSet = CharSet.Unicode)]
|
|
private static extern uint PdhEnumObjectsH(PdhSafeDataSourceHandle hDataSource, string szMachineName, IntPtr mszObjectList, ref IntPtr pcchBufferLength, uint dwDetailLevel, bool bRefresh);
|
|
|
|
[DllImport("pdh.dll", CharSet = CharSet.Unicode)]
|
|
private static extern uint PdhEnumObjectItemsH(PdhSafeDataSourceHandle hDataSource,
|
|
string szMachineName,
|
|
string szObjectName,
|
|
IntPtr mszCounterList,
|
|
ref IntPtr pcchCounterListLength,
|
|
IntPtr mszInstanceList,
|
|
ref IntPtr pcchInstanceListLength,
|
|
uint dwDetailLevel,
|
|
uint dwFlags);
|
|
|
|
[DllImport("pdh.dll", CharSet = CharSet.Unicode)]
|
|
private static extern uint PdhMakeCounterPath(ref PDH_COUNTER_PATH_ELEMENTS pCounterPathElements,
|
|
IntPtr szFullPathBuffer,
|
|
ref IntPtr pcchBufferSize,
|
|
UInt32 dwFlags);
|
|
|
|
[DllImport("pdh.dll", CharSet = CharSet.Unicode)]
|
|
private static extern uint PdhParseCounterPath(string szFullPathBuffer,
|
|
IntPtr pCounterPathElements, //PDH_COUNTER_PATH_ELEMENTS
|
|
ref IntPtr pdwBufferSize,
|
|
uint dwFlags);
|
|
|
|
|
|
[DllImport("pdh.dll", CharSet = CharSet.Unicode)]
|
|
private static extern uint PdhExpandWildCardPathH(PdhSafeDataSourceHandle hDataSource,
|
|
string szWildCardPath,
|
|
IntPtr mszExpandedPathList,
|
|
ref IntPtr pcchPathListLength,
|
|
uint dwFlags);
|
|
|
|
//not available on XP
|
|
[DllImport("pdh.dll", CharSet = CharSet.Unicode)]
|
|
private static extern uint PdhValidatePathEx(PdhSafeDataSourceHandle hDataSource, string szFullPathBuffer);
|
|
|
|
[DllImport("pdh.dll", CharSet = CharSet.Unicode)]
|
|
private static extern uint PdhValidatePath(string szFullPathBuffer);
|
|
|
|
//not available on XP
|
|
[DllImport("pdh.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, PreserveSig = true)] //private export
|
|
private static extern IntPtr PdhGetExplainText(string szMachineName, string szObjectName, string szCounterName);
|
|
|
|
[DllImport("pdh.dll", CharSet = CharSet.Unicode)]
|
|
private static extern uint PdhGetCounterInfo(IntPtr hCounter, [MarshalAs(UnmanagedType.U1)]bool bRetrieveExplainText, ref IntPtr pdwBufferSize, IntPtr lpBuffer);
|
|
|
|
[DllImport("pdh.dll", CharSet = CharSet.Unicode)]
|
|
private static extern uint PdhGetCounterTimeBase(IntPtr hCounter, out UInt64 pTimeBase);
|
|
|
|
[DllImport("pdh.dll", CharSet = CharSet.Unicode)]
|
|
private static extern uint PdhGetDataSourceTimeRangeH(PdhSafeDataSourceHandle hDataSource, ref IntPtr pdwNumEntries, ref PDH_TIME_INFO pInfo, ref IntPtr pdwBufferSize);
|
|
|
|
[DllImport("pdh.dll", CharSet = CharSet.Unicode)]
|
|
private static extern uint PdhSetQueryTimeRange(PdhSafeQueryHandle hQuery, ref PDH_TIME_INFO pInfo);
|
|
|
|
|
|
[DllImport("pdh.dll", CharSet = CharSet.Unicode)]
|
|
private static extern uint PdhLookupPerfNameByIndex(string szMachineName, UInt32 dwNameIndex, IntPtr szNameBuffer, ref int pcchNameBufferSize);
|
|
|
|
|
|
private PdhSafeDataSourceHandle _hDataSource = null;
|
|
|
|
private PdhSafeQueryHandle _hQuery = null;
|
|
|
|
private bool _firstReading = true;
|
|
|
|
private PdhSafeLogHandle _hOutputLog = null;
|
|
|
|
//
|
|
// Implement IDisposable::Dispose() to close native safe handles
|
|
//
|
|
public void Dispose()
|
|
{
|
|
if (_hDataSource != null && !_hDataSource.IsInvalid)
|
|
{
|
|
_hDataSource.Dispose();
|
|
}
|
|
|
|
if (_hOutputLog != null && !_hOutputLog.IsInvalid)
|
|
{
|
|
_hOutputLog.Dispose();
|
|
}
|
|
|
|
if (_hQuery != null && !_hQuery.IsInvalid)
|
|
{
|
|
_hQuery.Dispose();
|
|
}
|
|
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
//
|
|
// m_ConsumerPathToHandleAndInstanceMap map is used for reading counter date (live or from files).
|
|
//
|
|
private Dictionary<string, CounterHandleNInstance> _consumerPathToHandleAndInstanceMap = new Dictionary<string, CounterHandleNInstance>();
|
|
|
|
|
|
//
|
|
// m_ReloggerPathToHandleAndInstanceMap map is used for writing relog counters.
|
|
//
|
|
private Dictionary<string, CounterHandleNInstance> _reloggerPathToHandleAndInstanceMap = new Dictionary<string, CounterHandleNInstance>();
|
|
|
|
/// <summary>
|
|
/// A helper reading in a Unicode string with embedded NULLs and splitting it into a StringCollection.
|
|
/// </summary>
|
|
/// <param name="strNative"></param>
|
|
/// <param name="strSize"></param>
|
|
/// <param name="strColl"></param>
|
|
|
|
private void ReadPdhMultiString(ref IntPtr strNative, Int32 strSize, ref StringCollection strColl)
|
|
{
|
|
Debug.Assert(strSize >= 2);
|
|
int offset = 0;
|
|
string allSubstringsWithNulls = "";
|
|
while (offset <= ((strSize * sizeof(char)) - 4))
|
|
{
|
|
Int32 next4 = Marshal.ReadInt32(strNative, offset);
|
|
if (next4 == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
allSubstringsWithNulls += (char)next4;
|
|
|
|
offset += 2;
|
|
}
|
|
|
|
allSubstringsWithNulls = allSubstringsWithNulls.TrimEnd('\0');
|
|
|
|
strColl.AddRange(allSubstringsWithNulls.Split('\0'));
|
|
}
|
|
|
|
|
|
|
|
private uint GetCounterInfoPlus(IntPtr hCounter, out UInt32 counterType, out UInt32 defaultScale, out UInt64 timeBase)
|
|
{
|
|
uint res = 0;
|
|
counterType = 0;
|
|
defaultScale = 0;
|
|
timeBase = 0;
|
|
|
|
Debug.Assert(hCounter != null);
|
|
|
|
IntPtr pBufferSize = new IntPtr(0);
|
|
res = PdhGetCounterInfo(hCounter, false, ref pBufferSize, IntPtr.Zero);
|
|
if (res != PdhResults.PDH_MORE_DATA)
|
|
{
|
|
return res;
|
|
}
|
|
|
|
Int32 bufSize = pBufferSize.ToInt32();
|
|
IntPtr bufCounterInfo = Marshal.AllocHGlobal(bufSize);
|
|
|
|
try
|
|
{
|
|
res = PdhGetCounterInfo(hCounter, false, ref pBufferSize, bufCounterInfo);
|
|
if (res == 0 && bufCounterInfo != IntPtr.Zero)
|
|
{
|
|
//PDH_COUNTER_INFO pdhCounterInfo = (PDH_COUNTER_INFO)Marshal.PtrToStructure(bufCounterInfo, typeof(PDH_COUNTER_INFO));
|
|
|
|
counterType = (uint)Marshal.ReadInt32(bufCounterInfo, 4);
|
|
defaultScale = (uint)Marshal.ReadInt32(bufCounterInfo, 20);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
Marshal.FreeHGlobal(bufCounterInfo);
|
|
}
|
|
|
|
res = PdhGetCounterTimeBase(hCounter, out timeBase);
|
|
if (res != 0)
|
|
{
|
|
return res;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
public uint ConnectToDataSource()
|
|
{
|
|
if (_hDataSource != null && !_hDataSource.IsInvalid)
|
|
{
|
|
_hDataSource.Dispose();
|
|
}
|
|
|
|
uint res = PdhHelper.PdhBindInputDataSource(out _hDataSource, null);
|
|
if (res != 0)
|
|
{
|
|
//Console.WriteLine("error in PdhBindInputDataSource: " + res);
|
|
return res;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
/// <summary>
|
|
/// Connects to a single named datasource, initializing m_hDataSource variable.
|
|
/// </summary>
|
|
/// <param name="dataSourceName"></param>
|
|
/// <returns></returns>
|
|
public uint ConnectToDataSource(string dataSourceName)
|
|
{
|
|
if (_hDataSource != null && !_hDataSource.IsInvalid)
|
|
{
|
|
_hDataSource.Dispose();
|
|
}
|
|
|
|
uint res = PdhHelper.PdhBindInputDataSource(out _hDataSource, dataSourceName);
|
|
if (res != 0)
|
|
{
|
|
//Console.WriteLine("error in PdhBindInputDataSource: " + res);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
|
|
public uint ConnectToDataSource(StringCollection blgFileNames)
|
|
{
|
|
if (blgFileNames.Count == 1)
|
|
{
|
|
return ConnectToDataSource(blgFileNames[0]);
|
|
}
|
|
|
|
string doubleNullTerminated = "";
|
|
foreach (string fileName in blgFileNames)
|
|
{
|
|
doubleNullTerminated += fileName + '\0';
|
|
}
|
|
|
|
doubleNullTerminated += '\0';
|
|
|
|
return ConnectToDataSource(doubleNullTerminated);
|
|
}
|
|
|
|
public uint OpenQuery()
|
|
{
|
|
uint res = PdhOpenQueryH(_hDataSource, IntPtr.Zero, out _hQuery);
|
|
|
|
if (res != 0)
|
|
{
|
|
//Console.WriteLine("error in PdhOpenQueryH: " + res);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
public uint OpenLogForWriting(string logName, PdhLogFileType logFileType, bool bOverwrite, UInt32 maxSize, bool bCircular, string caption)
|
|
{
|
|
Debug.Assert(_hQuery != null);
|
|
|
|
UInt32 accessFlags = PdhLogAccess.PDH_LOG_WRITE_ACCESS;
|
|
accessFlags |= bCircular ? PdhLogOpenOption.PDH_LOG_OPT_CIRCULAR : 0;
|
|
accessFlags |= bOverwrite ? PdhLogOpenMode.PDH_LOG_CREATE_ALWAYS : PdhLogOpenMode.PDH_LOG_CREATE_NEW;
|
|
|
|
uint res = PdhOpenLog(logName,
|
|
accessFlags,
|
|
ref logFileType,
|
|
_hQuery,
|
|
maxSize,
|
|
caption,
|
|
out _hOutputLog);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
public uint SetQueryTimeRange(DateTime startTime, DateTime endTime)
|
|
{
|
|
Debug.Assert(_hQuery != null);
|
|
Debug.Assert(endTime >= startTime);
|
|
|
|
PDH_TIME_INFO pTimeInfo = new PDH_TIME_INFO();
|
|
|
|
if (startTime != DateTime.MinValue && startTime.Kind == DateTimeKind.Local)
|
|
{
|
|
startTime = new DateTime(startTime.Ticks, DateTimeKind.Utc);
|
|
}
|
|
pTimeInfo.StartTime = (startTime == DateTime.MinValue) ? 0 : startTime.ToFileTimeUtc();
|
|
|
|
if (endTime != DateTime.MaxValue && endTime.Kind == DateTimeKind.Local)
|
|
{
|
|
endTime = new DateTime(endTime.Ticks, DateTimeKind.Utc);
|
|
}
|
|
pTimeInfo.EndTime = (endTime == DateTime.MaxValue) ? Int64.MaxValue : endTime.ToFileTimeUtc();
|
|
|
|
pTimeInfo.SampleCount = 0;
|
|
|
|
return PdhSetQueryTimeRange(_hQuery, ref pTimeInfo);
|
|
}
|
|
|
|
public uint EnumBlgFilesMachines(ref StringCollection machineNames)
|
|
{
|
|
IntPtr MachineListTcharSizePtr = new IntPtr(0);
|
|
uint res = PdhHelper.PdhEnumMachinesH(_hDataSource, IntPtr.Zero, ref MachineListTcharSizePtr);
|
|
if (res != PdhResults.PDH_MORE_DATA)
|
|
{
|
|
return res;
|
|
}
|
|
|
|
Int32 cChars = MachineListTcharSizePtr.ToInt32(); //should be ok on 64 bit
|
|
IntPtr strMachineList = Marshal.AllocHGlobal(cChars * sizeof(char));
|
|
|
|
try
|
|
{
|
|
res = PdhHelper.PdhEnumMachinesH(_hDataSource, (IntPtr)strMachineList, ref MachineListTcharSizePtr);
|
|
if (res == 0)
|
|
{
|
|
ReadPdhMultiString(ref strMachineList, MachineListTcharSizePtr.ToInt32(), ref machineNames);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
Marshal.FreeHGlobal(strMachineList);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
public uint EnumObjects(string machineName, ref StringCollection objectNames)
|
|
{
|
|
IntPtr pBufferSize = new IntPtr(0);
|
|
uint res = PdhEnumObjectsH(_hDataSource, machineName, IntPtr.Zero, ref pBufferSize, PerfDetail.PERF_DETAIL_WIZARD, false);
|
|
if (res != PdhResults.PDH_MORE_DATA)
|
|
{
|
|
return res;
|
|
}
|
|
|
|
Int32 cChars = pBufferSize.ToInt32();
|
|
IntPtr strObjectList = Marshal.AllocHGlobal(cChars * sizeof(char));
|
|
|
|
try
|
|
{
|
|
res = PdhEnumObjectsH(_hDataSource, machineName, (IntPtr)strObjectList, ref pBufferSize, PerfDetail.PERF_DETAIL_WIZARD, false);
|
|
if (res == 0)
|
|
{
|
|
ReadPdhMultiString(ref strObjectList, pBufferSize.ToInt32(), ref objectNames);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
Marshal.FreeHGlobal(strObjectList);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
public uint EnumObjectItems(string machineName, string objectName, ref StringCollection counterNames, ref StringCollection instanceNames)
|
|
{
|
|
IntPtr pCounterBufferSize = new IntPtr(0);
|
|
IntPtr pInstanceBufferSize = new IntPtr(0);
|
|
|
|
uint res = PdhEnumObjectItemsH(_hDataSource, machineName, objectName,
|
|
IntPtr.Zero, ref pCounterBufferSize,
|
|
IntPtr.Zero, ref pInstanceBufferSize,
|
|
PerfDetail.PERF_DETAIL_WIZARD, 0);
|
|
if (res == PdhResults.PDH_CSTATUS_NO_INSTANCE)
|
|
{
|
|
instanceNames.Clear();
|
|
return 0; //masking the error
|
|
}
|
|
else if (res == PdhResults.PDH_CSTATUS_NO_OBJECT)
|
|
{
|
|
counterNames.Clear();
|
|
return 0; //masking the error
|
|
}
|
|
else if (res != PdhResults.PDH_MORE_DATA)
|
|
{
|
|
//Console.WriteLine("error in PdhEnumObjectItemsH 1st call: " + res);
|
|
return res;
|
|
}
|
|
|
|
Int32 cChars = pCounterBufferSize.ToInt32();
|
|
IntPtr strCountersList = (cChars > 0) ?
|
|
Marshal.AllocHGlobal((cChars) * sizeof(char)) : IntPtr.Zero;
|
|
//re-set count to 0 if it is lte 2
|
|
if (cChars < 0)
|
|
{
|
|
pCounterBufferSize = new IntPtr(0);
|
|
}
|
|
|
|
cChars = pInstanceBufferSize.ToInt32();
|
|
IntPtr strInstancesList = (cChars > 0) ?
|
|
Marshal.AllocHGlobal((cChars) * sizeof(char)) : IntPtr.Zero;
|
|
|
|
//re-set count to 0 if it is lte 2
|
|
if (cChars < 0)
|
|
{
|
|
pInstanceBufferSize = new IntPtr(0);
|
|
}
|
|
|
|
try
|
|
{
|
|
res = PdhEnumObjectItemsH(_hDataSource, machineName, objectName,
|
|
strCountersList, ref pCounterBufferSize,
|
|
strInstancesList, ref pInstanceBufferSize,
|
|
PerfDetail.PERF_DETAIL_WIZARD, 0);
|
|
if (res != 0)
|
|
{
|
|
//Console.WriteLine("error in PdhEnumObjectItemsH 2nd call: " + res + "\n Counter buffer size is "
|
|
// + pCounterBufferSize.ToInt32() + "\n Instance buffer size is " + pInstanceBufferSize.ToInt32());
|
|
}
|
|
else
|
|
{
|
|
ReadPdhMultiString(ref strCountersList, pCounterBufferSize.ToInt32(), ref counterNames);
|
|
if (strInstancesList != IntPtr.Zero)
|
|
{
|
|
ReadPdhMultiString(ref strInstancesList, pInstanceBufferSize.ToInt32(), ref instanceNames);
|
|
}
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
if (strCountersList != IntPtr.Zero)
|
|
{
|
|
Marshal.FreeHGlobal(strCountersList);
|
|
}
|
|
if (strInstancesList != IntPtr.Zero)
|
|
{
|
|
Marshal.FreeHGlobal(strInstancesList);
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
public uint GetValidPathsFromFiles(ref StringCollection validPaths)
|
|
{
|
|
Debug.Assert(_hDataSource != null && !_hDataSource.IsInvalid, "Call ConnectToDataSource before GetValidPathsFromFiles");
|
|
|
|
|
|
StringCollection machineNames = new StringCollection();
|
|
uint res = this.EnumBlgFilesMachines(ref machineNames);
|
|
if (res != 0)
|
|
{
|
|
return res;
|
|
}
|
|
|
|
foreach (string machine in machineNames)
|
|
{
|
|
StringCollection counterSets = new StringCollection();
|
|
res = this.EnumObjects(machine, ref counterSets);
|
|
if (res != 0)
|
|
{
|
|
return res;
|
|
}
|
|
|
|
foreach (string counterSet in counterSets)
|
|
{
|
|
//Console.WriteLine("Counter set " + counterSet);
|
|
|
|
StringCollection counterSetCounters = new StringCollection();
|
|
StringCollection counterSetInstances = new StringCollection();
|
|
|
|
res = this.EnumObjectItems(machine, counterSet, ref counterSetCounters, ref counterSetInstances);
|
|
if (res != 0)
|
|
{
|
|
return res;
|
|
}
|
|
|
|
res = this.GetValidPaths(machine, counterSet, ref counterSetCounters, ref counterSetInstances, ref validPaths);
|
|
if (res != 0)
|
|
{
|
|
return res;
|
|
}
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
private bool IsPathValid(ref PDH_COUNTER_PATH_ELEMENTS pathElts, out string outPath)
|
|
{
|
|
bool ret = false;
|
|
outPath = "";
|
|
IntPtr pPathBufferSize = new IntPtr(0);
|
|
|
|
uint res = PdhMakeCounterPath(ref pathElts, IntPtr.Zero, ref pPathBufferSize, 0);
|
|
if (res != PdhResults.PDH_MORE_DATA)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Int32 cChars = pPathBufferSize.ToInt32();
|
|
IntPtr strPath = Marshal.AllocHGlobal(cChars * sizeof(char));
|
|
|
|
try
|
|
{
|
|
res = PdhMakeCounterPath(ref pathElts, strPath, ref pPathBufferSize, 0);
|
|
if (res == 0)
|
|
{
|
|
outPath = Marshal.PtrToStringUni(strPath);
|
|
|
|
if (!_isPreVista)
|
|
{
|
|
ret = (PdhValidatePathEx(_hDataSource, outPath) == 0);
|
|
}
|
|
else
|
|
{
|
|
ret = (PdhValidatePath(outPath) == 0);
|
|
}
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
Marshal.FreeHGlobal(strPath);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
public bool IsPathValid(string path)
|
|
{
|
|
if (!_isPreVista)
|
|
{
|
|
return (PdhValidatePathEx(_hDataSource, path) == 0);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Note: this assumes the paths already contain machine names
|
|
//
|
|
return (PdhValidatePath(path) == 0);
|
|
}
|
|
}
|
|
|
|
|
|
private uint MakePath(PDH_COUNTER_PATH_ELEMENTS pathElts, out string outPath, bool bWildcardInstances)
|
|
{
|
|
outPath = "";
|
|
IntPtr pPathBufferSize = new IntPtr(0);
|
|
|
|
if (bWildcardInstances)
|
|
{
|
|
pathElts.InstanceIndex = 0;
|
|
pathElts.InstanceName = "*";
|
|
pathElts.ParentInstance = null;
|
|
}
|
|
|
|
uint res = PdhMakeCounterPath(ref pathElts, IntPtr.Zero, ref pPathBufferSize, 0);
|
|
if (res != PdhResults.PDH_MORE_DATA)
|
|
{
|
|
return res;
|
|
}
|
|
|
|
Int32 cChars = pPathBufferSize.ToInt32();
|
|
IntPtr strPath = Marshal.AllocHGlobal(cChars * sizeof(char));
|
|
|
|
try
|
|
{
|
|
res = PdhMakeCounterPath(ref pathElts, strPath, ref pPathBufferSize, 0);
|
|
if (res == 0)
|
|
{
|
|
outPath = Marshal.PtrToStringUni(strPath);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
Marshal.FreeHGlobal(strPath);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
private uint MakeAllInstancePath(string origPath, out string unifiedPath)
|
|
{
|
|
unifiedPath = origPath;
|
|
|
|
PDH_COUNTER_PATH_ELEMENTS elts = new PDH_COUNTER_PATH_ELEMENTS();
|
|
|
|
uint res = ParsePath(origPath, ref elts);
|
|
if (res != 0)
|
|
{
|
|
return res;
|
|
}
|
|
|
|
return MakePath(elts, out unifiedPath, true);
|
|
}
|
|
|
|
|
|
private uint ParsePath(string fullPath, ref PDH_COUNTER_PATH_ELEMENTS pCounterPathElements)
|
|
{
|
|
IntPtr bufSize = new IntPtr(0);
|
|
|
|
uint res = PdhParseCounterPath(fullPath,
|
|
IntPtr.Zero,
|
|
ref bufSize,
|
|
0);
|
|
if (res != PdhResults.PDH_MORE_DATA && res != 0)
|
|
{
|
|
//Console.WriteLine("error in PdhParseCounterPath: " + res);
|
|
return res;
|
|
}
|
|
|
|
IntPtr structPtr = Marshal.AllocHGlobal(bufSize.ToInt32());
|
|
|
|
try
|
|
{
|
|
res = PdhParseCounterPath(fullPath,
|
|
structPtr,
|
|
ref bufSize,
|
|
0);
|
|
if (res == 0)
|
|
{
|
|
//
|
|
// Marshal.PtrToStructure will allocate managed memory for the object,
|
|
// so the unmanaged ptr can be freed safely
|
|
//
|
|
pCounterPathElements = Marshal.PtrToStructure<PDH_COUNTER_PATH_ELEMENTS>(structPtr);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
Marshal.FreeHGlobal(structPtr);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
//
|
|
// TranslateLocalCounterPath() helper translates counter paths from English into the current locale language.
|
|
// NOTE: we can only translate counter set and counter names.
|
|
// Translated instance names come from providers
|
|
// This function will leave them unchanged:
|
|
// however, it works for common cases like "*" and "_total"
|
|
// and many instance names are just numbers, anyway.
|
|
//
|
|
// Also - this only supports local paths, b/c connecting to remote registry
|
|
// requires a different firewall exception.
|
|
// This function checks and Asserts if the path is not valid.
|
|
//
|
|
public uint TranslateLocalCounterPath(string englishPath, out string localizedPath)
|
|
{
|
|
uint res = 0;
|
|
localizedPath = "";
|
|
PDH_COUNTER_PATH_ELEMENTS pathElts = new PDH_COUNTER_PATH_ELEMENTS();
|
|
res = ParsePath(englishPath, ref pathElts);
|
|
if (res != 0)
|
|
{
|
|
return res;
|
|
}
|
|
|
|
// Check if the path is local and assert if not:
|
|
string machineNameMassaged = pathElts.MachineName.ToLowerInvariant();
|
|
machineNameMassaged = machineNameMassaged.TrimStart('\\');
|
|
Debug.Assert(machineNameMassaged == System.Environment.MachineName.ToLowerInvariant());
|
|
|
|
string lowerEngCtrName = pathElts.CounterName.ToLowerInvariant();
|
|
string lowerEngObjectName = pathElts.ObjectName.ToLowerInvariant();
|
|
|
|
// Get the registry index
|
|
RegistryKey rootKey = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\009");
|
|
string[] regCounters = (string[])rootKey.GetValue("Counter");
|
|
|
|
|
|
// NOTE: 1-based enumeration because the name strings follow index strings in the array
|
|
Int32 counterIndex = -1;
|
|
Int32 objIndex = -1;
|
|
for (uint enumIndex = 1; enumIndex < regCounters.Length; enumIndex++)
|
|
{
|
|
string regString = regCounters[enumIndex];
|
|
if (regString.ToLowerInvariant() == lowerEngCtrName)
|
|
{
|
|
try
|
|
{
|
|
counterIndex = Convert.ToInt32(regCounters[enumIndex - 1], CultureInfo.InvariantCulture);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return (uint)PdhResults.PDH_INVALID_PATH;
|
|
}
|
|
}
|
|
else if (regString.ToLowerInvariant() == lowerEngObjectName)
|
|
{
|
|
try
|
|
{
|
|
objIndex = Convert.ToInt32(regCounters[enumIndex - 1], CultureInfo.InvariantCulture);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return (uint)PdhResults.PDH_INVALID_PATH;
|
|
}
|
|
}
|
|
if (counterIndex != -1 && objIndex != -1)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (counterIndex == -1 || objIndex == -1)
|
|
{
|
|
return (uint)PdhResults.PDH_INVALID_PATH;
|
|
}
|
|
|
|
|
|
// Now, call retrieve the localized names of the object and the counter by index:
|
|
string objNameLocalized;
|
|
res = LookupPerfNameByIndex(pathElts.MachineName, (uint)objIndex, out objNameLocalized);
|
|
if (res != 0)
|
|
{
|
|
return res;
|
|
}
|
|
pathElts.ObjectName = objNameLocalized;
|
|
|
|
|
|
string ctrNameLocalized;
|
|
res = LookupPerfNameByIndex(pathElts.MachineName, (uint)counterIndex, out ctrNameLocalized);
|
|
if (res != 0)
|
|
{
|
|
return res;
|
|
}
|
|
pathElts.CounterName = ctrNameLocalized;
|
|
|
|
// Assemble the path back by using the translated object and counter names:
|
|
|
|
res = MakePath(pathElts, out localizedPath, false);
|
|
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
public uint LookupPerfNameByIndex(string machineName, uint index, out string locName)
|
|
{
|
|
//
|
|
// NOTE: to make PdhLookupPerfNameByIndex() work,
|
|
// localizedPath needs to be pre-allocated on the first call.
|
|
// This is different from most other PDH functions that tolerate NULL buffers and return required size.
|
|
//
|
|
|
|
int strSize = 256;
|
|
IntPtr localizedPathPtr = Marshal.AllocHGlobal(strSize * sizeof(char));
|
|
locName = "";
|
|
uint res = 0;
|
|
try
|
|
{
|
|
res = PdhLookupPerfNameByIndex(machineName, index, localizedPathPtr, ref strSize);
|
|
if (res == PdhResults.PDH_MORE_DATA)
|
|
{
|
|
Marshal.FreeHGlobal(localizedPathPtr);
|
|
localizedPathPtr = Marshal.AllocHGlobal(strSize * sizeof(char));
|
|
res = PdhLookupPerfNameByIndex(machineName, index, localizedPathPtr, ref strSize);
|
|
}
|
|
if (res == 0)
|
|
{
|
|
locName = Marshal.PtrToStringUni(localizedPathPtr);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
Marshal.FreeHGlobal(localizedPathPtr);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
|
|
public uint GetValidPaths(string machineName,
|
|
string objectName,
|
|
ref StringCollection counters,
|
|
ref StringCollection instances,
|
|
ref StringCollection validPaths)
|
|
{
|
|
uint res = 0;
|
|
|
|
PDH_COUNTER_PATH_ELEMENTS pathElts = new PDH_COUNTER_PATH_ELEMENTS();
|
|
pathElts.MachineName = machineName;
|
|
pathElts.ObjectName = objectName;
|
|
|
|
foreach (string counterName in counters)
|
|
{
|
|
pathElts.CounterName = counterName;
|
|
|
|
if (instances.Count == 0)
|
|
{
|
|
string pathCandidate;
|
|
if (IsPathValid(ref pathElts, out pathCandidate))
|
|
{
|
|
validPaths.Add(pathCandidate);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
foreach (string instanceName in instances)
|
|
{
|
|
pathElts.InstanceName = instanceName;
|
|
pathElts.InstanceIndex = 0;
|
|
|
|
string pathCandidate;
|
|
if (IsPathValid(ref pathElts, out pathCandidate))
|
|
{
|
|
validPaths.Add(pathCandidate);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
|
|
public uint AddCounters(ref StringCollection validPaths, bool bFlushOldCounters)
|
|
{
|
|
Debug.Assert(_hQuery != null && !_hQuery.IsInvalid);
|
|
|
|
if (bFlushOldCounters)
|
|
{
|
|
_consumerPathToHandleAndInstanceMap.Clear();
|
|
}
|
|
|
|
bool bAtLeastOneAdded = false;
|
|
uint res = 0;
|
|
|
|
foreach (string counterPath in validPaths)
|
|
{
|
|
IntPtr counterHandle;
|
|
res = PdhAddCounter(_hQuery, counterPath, IntPtr.Zero, out counterHandle);
|
|
if (res == 0)
|
|
{
|
|
CounterHandleNInstance chi = new CounterHandleNInstance();
|
|
chi.hCounter = counterHandle;
|
|
chi.InstanceName = null;
|
|
|
|
PDH_COUNTER_PATH_ELEMENTS pathElts = new PDH_COUNTER_PATH_ELEMENTS();
|
|
res = ParsePath(counterPath, ref pathElts);
|
|
if (res == 0 && pathElts.InstanceName != null)
|
|
{
|
|
chi.InstanceName = pathElts.InstanceName.ToLowerInvariant();
|
|
}
|
|
|
|
if (!_consumerPathToHandleAndInstanceMap.ContainsKey(counterPath.ToLowerInvariant()))
|
|
{
|
|
_consumerPathToHandleAndInstanceMap.Add(counterPath.ToLowerInvariant(), chi);
|
|
}
|
|
|
|
bAtLeastOneAdded = true;
|
|
}
|
|
}
|
|
|
|
return bAtLeastOneAdded ? 0 : res;
|
|
}
|
|
|
|
|
|
//
|
|
// AddRelogCounters combines instances and adds counters to m_hQuery.
|
|
// The counter handles and full paths
|
|
//
|
|
public uint AddRelogCounters(PerformanceCounterSampleSet sampleSet)
|
|
{
|
|
Debug.Assert(_hQuery != null && !_hQuery.IsInvalid);
|
|
|
|
uint res = 0;
|
|
|
|
Dictionary<string, List<PerformanceCounterSample>> prefixInstanceMap = new Dictionary<string, List<PerformanceCounterSample>>();
|
|
|
|
//
|
|
// Go through all the samples one, constructing prefixInstanceMap and adding new counters as needed
|
|
//
|
|
foreach (PerformanceCounterSample sample in sampleSet.CounterSamples)
|
|
{
|
|
PDH_COUNTER_PATH_ELEMENTS pathElts = new PDH_COUNTER_PATH_ELEMENTS();
|
|
res = ParsePath(sample.Path, ref pathElts);
|
|
if (res != 0)
|
|
{
|
|
// Skipping for now, but should be a non-terminating error
|
|
continue;
|
|
}
|
|
|
|
string lowerCaseMachine = pathElts.MachineName.ToLowerInvariant();
|
|
string lowerCaseObject = pathElts.ObjectName.ToLowerInvariant();
|
|
string lowerCaseCounter = pathElts.CounterName.ToLowerInvariant();
|
|
|
|
string lcPathMinusInstance = @"\\" + lowerCaseMachine + @"\" + lowerCaseObject + @"\" + lowerCaseCounter;
|
|
|
|
List<PerformanceCounterSample> sampleList;
|
|
if (prefixInstanceMap.TryGetValue(lcPathMinusInstance, out sampleList))
|
|
{
|
|
prefixInstanceMap[lcPathMinusInstance].Add(sample);
|
|
}
|
|
else
|
|
{
|
|
List<PerformanceCounterSample> newList = new List<PerformanceCounterSample>();
|
|
newList.Add(sample);
|
|
prefixInstanceMap.Add(lcPathMinusInstance, newList);
|
|
}
|
|
|
|
//Console.WriteLine ("Added path " + sample.Path + " to the 1ist map with prefix " + lcPathMinusInstance);
|
|
}
|
|
|
|
//
|
|
// Add counters to the query, consolidating multi-instance with a wildcard path,
|
|
// and construct m_ReloggerPathToHandleAndInstanceMap where each full path would be pointing to its counter handle
|
|
// and an instance name (might be empty for no-instance counter types).
|
|
// You can have multiple full paths inside m_ReloggerPathToHandleAndInstanceMap pointing to the same handle.
|
|
//
|
|
|
|
foreach (string prefix in prefixInstanceMap.Keys)
|
|
{
|
|
IntPtr counterHandle;
|
|
string unifiedPath = prefixInstanceMap[prefix][0].Path;
|
|
|
|
if (prefixInstanceMap[prefix].Count > 1)
|
|
{
|
|
res = MakeAllInstancePath(prefixInstanceMap[prefix][0].Path, out unifiedPath);
|
|
if (res != 0)
|
|
{
|
|
// Skipping for now, but should be a non-terminating error
|
|
continue;
|
|
}
|
|
}
|
|
|
|
res = PdhAddRelogCounter(_hQuery,
|
|
unifiedPath,
|
|
(UInt32)prefixInstanceMap[prefix][0].CounterType,
|
|
prefixInstanceMap[prefix][0].DefaultScale,
|
|
prefixInstanceMap[prefix][0].TimeBase,
|
|
out counterHandle);
|
|
if (res != 0)
|
|
{
|
|
// Skipping for now, but should be a non-terminating error
|
|
// Console.WriteLine ("PdhAddCounter returned " + res + " for counter path " + unifiedPath);
|
|
continue;
|
|
}
|
|
|
|
//now, add all actual paths to m_ReloggerPathToHandleAndInstanceMap
|
|
foreach (PerformanceCounterSample sample in prefixInstanceMap[prefix])
|
|
{
|
|
PDH_COUNTER_PATH_ELEMENTS pathElts = new PDH_COUNTER_PATH_ELEMENTS();
|
|
res = ParsePath(sample.Path, ref pathElts);
|
|
if (res != 0)
|
|
{
|
|
// Skipping for now, but should be a non-terminating error
|
|
continue;
|
|
}
|
|
|
|
CounterHandleNInstance chi = new CounterHandleNInstance();
|
|
|
|
chi.hCounter = counterHandle;
|
|
|
|
if (pathElts.InstanceName != null)
|
|
{
|
|
chi.InstanceName = pathElts.InstanceName.ToLowerInvariant();
|
|
}
|
|
|
|
if (!_reloggerPathToHandleAndInstanceMap.ContainsKey(sample.Path.ToLowerInvariant()))
|
|
{
|
|
_reloggerPathToHandleAndInstanceMap.Add(sample.Path.ToLowerInvariant(), chi);
|
|
//Console.WriteLine ("added map path:" + sample.Path );
|
|
}
|
|
}
|
|
}
|
|
|
|
//TODO: verify that all counters are in the map
|
|
|
|
return (_reloggerPathToHandleAndInstanceMap.Keys.Count > 0) ? 0 : res;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// AddRelogCountersPreservingPaths preserves all paths and adds as relog counters to m_hQuery.
|
|
// The counter handles and full paths are added to m_ReloggerPathToHandleAndInstanceMap
|
|
//
|
|
public uint AddRelogCountersPreservingPaths(PerformanceCounterSampleSet sampleSet)
|
|
{
|
|
Debug.Assert(_hQuery != null && !_hQuery.IsInvalid);
|
|
|
|
uint res = 0;
|
|
|
|
//
|
|
// Go through all the samples one, constructing prefixInstanceMap and adding new counters as needed
|
|
//
|
|
foreach (PerformanceCounterSample sample in sampleSet.CounterSamples)
|
|
{
|
|
PDH_COUNTER_PATH_ELEMENTS pathElts = new PDH_COUNTER_PATH_ELEMENTS();
|
|
res = ParsePath(sample.Path, ref pathElts);
|
|
if (res != 0)
|
|
{
|
|
// Skipping for now, but should be a non-terminating error
|
|
continue;
|
|
}
|
|
|
|
IntPtr counterHandle;
|
|
res = PdhAddRelogCounter(_hQuery,
|
|
sample.Path,
|
|
(uint)sample.CounterType,
|
|
sample.DefaultScale,
|
|
sample.TimeBase,
|
|
out counterHandle);
|
|
if (res != 0)
|
|
{
|
|
// Skipping for now, but should be a non-terminating error
|
|
continue;
|
|
}
|
|
|
|
CounterHandleNInstance chi = new CounterHandleNInstance();
|
|
|
|
chi.hCounter = counterHandle;
|
|
if (pathElts.InstanceName != null)
|
|
{
|
|
chi.InstanceName = pathElts.InstanceName.ToLowerInvariant();
|
|
}
|
|
|
|
if (!_reloggerPathToHandleAndInstanceMap.ContainsKey(sample.Path.ToLowerInvariant()))
|
|
{
|
|
_reloggerPathToHandleAndInstanceMap.Add(sample.Path.ToLowerInvariant(), chi);
|
|
}
|
|
}
|
|
|
|
return (_reloggerPathToHandleAndInstanceMap.Keys.Count > 0) ? 0 : res;
|
|
}
|
|
|
|
public string GetCounterSetHelp(string szMachineName, string szObjectName)
|
|
{
|
|
if (_isPreVista)
|
|
{
|
|
return string.Empty;
|
|
}
|
|
IntPtr retString = PdhGetExplainText(szMachineName, szObjectName, null);
|
|
return Marshal.PtrToStringUni(retString);
|
|
}
|
|
|
|
public uint ReadNextSetPreVista(out PerformanceCounterSampleSet nextSet, bool bSkipReading)
|
|
{
|
|
uint res = 0;
|
|
nextSet = null;
|
|
|
|
res = PdhCollectQueryData(_hQuery);
|
|
if (bSkipReading)
|
|
{
|
|
return res;
|
|
}
|
|
if (res != 0 && res != PdhResults.PDH_NO_DATA)
|
|
{
|
|
return res;
|
|
}
|
|
|
|
PerformanceCounterSample[] samplesArr = new PerformanceCounterSample[_consumerPathToHandleAndInstanceMap.Count];
|
|
uint sampleIndex = 0;
|
|
uint numInvalidDataSamples = 0;
|
|
uint lastErr = 0;
|
|
|
|
DateTime sampleTimeStamp = DateTime.Now;
|
|
|
|
foreach (string path in _consumerPathToHandleAndInstanceMap.Keys)
|
|
{
|
|
IntPtr counterTypePtr = new IntPtr(0);
|
|
UInt32 counterType = (UInt32)PerformanceCounterType.RawBase;
|
|
UInt32 defaultScale = 0;
|
|
UInt64 timeBase = 0;
|
|
|
|
IntPtr hCounter = _consumerPathToHandleAndInstanceMap[path].hCounter;
|
|
Debug.Assert(hCounter != null);
|
|
|
|
res = GetCounterInfoPlus(hCounter, out counterType, out defaultScale, out timeBase);
|
|
if (res != 0)
|
|
{
|
|
//Console.WriteLine ("GetCounterInfoPlus for " + path + " failed with " + res);
|
|
}
|
|
|
|
PDH_RAW_COUNTER rawValue;
|
|
res = PdhGetRawCounterValue(hCounter, out counterTypePtr, out rawValue);
|
|
if (res == PdhResults.PDH_INVALID_DATA || res == PdhResults.PDH_NO_DATA)
|
|
{
|
|
//Console.WriteLine ("PdhGetRawCounterValue returned " + res);
|
|
samplesArr[sampleIndex++] = new PerformanceCounterSample(path,
|
|
_consumerPathToHandleAndInstanceMap[path].InstanceName,
|
|
0,
|
|
(ulong)0,
|
|
(ulong)0,
|
|
0,
|
|
PerformanceCounterType.RawBase,
|
|
defaultScale,
|
|
timeBase,
|
|
DateTime.Now,
|
|
(UInt64)DateTime.Now.ToFileTime(),
|
|
rawValue.CStatus);
|
|
|
|
numInvalidDataSamples++;
|
|
lastErr = res;
|
|
continue;
|
|
}
|
|
else if (res != 0)
|
|
{
|
|
return res;
|
|
}
|
|
|
|
long dtFT = (((long)rawValue.TimeStamp.dwHighDateTime) << 32) +
|
|
(uint)rawValue.TimeStamp.dwLowDateTime;
|
|
|
|
//
|
|
// NOTE: PDH returns the filetime as local time, therefore
|
|
// we need to call FromFileTimUtc() to avoid .NET applying the timezone adjustment.
|
|
// However, that would result in the DateTime object having Kind.Utc.
|
|
// We have to copy it once more to correct that (Kind is a read-only property).
|
|
//
|
|
sampleTimeStamp = new DateTime(DateTime.FromFileTimeUtc(dtFT).Ticks, DateTimeKind.Local);
|
|
|
|
PDH_FMT_COUNTERVALUE_DOUBLE fmtValueDouble;
|
|
res = PdhGetFormattedCounterValue(hCounter,
|
|
PdhFormat.PDH_FMT_DOUBLE | PdhFormat.PDH_FMT_NOCAP100,
|
|
out counterTypePtr,
|
|
out fmtValueDouble);
|
|
if (res == PdhResults.PDH_INVALID_DATA || res == PdhResults.PDH_NO_DATA)
|
|
{
|
|
//Console.WriteLine ("PdhGetFormattedCounterValue returned " + res);
|
|
samplesArr[sampleIndex++] = new PerformanceCounterSample(path,
|
|
_consumerPathToHandleAndInstanceMap[path].InstanceName,
|
|
0,
|
|
(ulong)rawValue.FirstValue,
|
|
(ulong)rawValue.SecondValue,
|
|
rawValue.MultiCount,
|
|
(PerformanceCounterType)counterType,
|
|
defaultScale,
|
|
timeBase,
|
|
sampleTimeStamp,
|
|
(UInt64)dtFT,
|
|
fmtValueDouble.CStatus);
|
|
|
|
numInvalidDataSamples++;
|
|
lastErr = res;
|
|
continue;
|
|
}
|
|
else if (res != 0)
|
|
{
|
|
//Console.WriteLine ("PdhGetFormattedCounterValue returned " + res);
|
|
return res;
|
|
}
|
|
|
|
samplesArr[sampleIndex++] = new PerformanceCounterSample(path,
|
|
_consumerPathToHandleAndInstanceMap[path].InstanceName,
|
|
fmtValueDouble.doubleValue,
|
|
(ulong)rawValue.FirstValue,
|
|
(ulong)rawValue.SecondValue,
|
|
rawValue.MultiCount,
|
|
(PerformanceCounterType)counterTypePtr.ToInt32(),
|
|
defaultScale,
|
|
timeBase,
|
|
sampleTimeStamp,
|
|
(UInt64)dtFT,
|
|
fmtValueDouble.CStatus);
|
|
}
|
|
|
|
//
|
|
// Prior to Vista, PdhCollectQueryDataWithTime() was not available,
|
|
// so we could not collect a timestamp for the entire sample set.
|
|
// We will use the last sample's timestamp instead.
|
|
//
|
|
nextSet = new PerformanceCounterSampleSet(sampleTimeStamp, samplesArr, _firstReading);
|
|
_firstReading = false;
|
|
|
|
if (numInvalidDataSamples == samplesArr.Length)
|
|
{
|
|
res = lastErr;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Reset the error - any errors are saved per sample in PerformanceCounterSample.Status for kvetching later
|
|
//
|
|
res = 0;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
public uint ReadNextSet(out PerformanceCounterSampleSet nextSet, bool bSkipReading)
|
|
{
|
|
Debug.Assert(_hQuery != null && !_hQuery.IsInvalid);
|
|
|
|
if (_isPreVista)
|
|
{
|
|
return ReadNextSetPreVista(out nextSet, bSkipReading);
|
|
}
|
|
|
|
uint res = 0;
|
|
nextSet = null;
|
|
|
|
Int64 batchTimeStampFT = 0;
|
|
|
|
res = PdhCollectQueryDataWithTime(_hQuery, ref batchTimeStampFT);
|
|
if (bSkipReading)
|
|
{
|
|
return res;
|
|
}
|
|
if (res != 0 && res != PdhResults.PDH_NO_DATA)
|
|
{
|
|
return res;
|
|
}
|
|
|
|
//
|
|
// NOTE: PDH returns the filetime as local time, therefore
|
|
// we need to call FromFileTimUtc() to avoid .NET applying the timezone adjustment.
|
|
// However, that would result in the DateTime object having Kind.Utc.
|
|
// We have to copy it once more to correct that (Kind is a read-only property).
|
|
//
|
|
DateTime batchStamp = DateTime.Now;
|
|
if (res != PdhResults.PDH_NO_DATA)
|
|
{
|
|
batchStamp = new DateTime(DateTime.FromFileTimeUtc(batchTimeStampFT).Ticks, DateTimeKind.Local);
|
|
}
|
|
|
|
PerformanceCounterSample[] samplesArr = new PerformanceCounterSample[_consumerPathToHandleAndInstanceMap.Count];
|
|
uint sampleIndex = 0;
|
|
uint numInvalidDataSamples = 0;
|
|
uint lastErr = 0;
|
|
|
|
foreach (string path in _consumerPathToHandleAndInstanceMap.Keys)
|
|
{
|
|
IntPtr counterTypePtr = new IntPtr(0);
|
|
UInt32 counterType = (UInt32)PerformanceCounterType.RawBase;
|
|
UInt32 defaultScale = 0;
|
|
UInt64 timeBase = 0;
|
|
|
|
IntPtr hCounter = _consumerPathToHandleAndInstanceMap[path].hCounter;
|
|
Debug.Assert(hCounter != null);
|
|
|
|
res = GetCounterInfoPlus(hCounter, out counterType, out defaultScale, out timeBase);
|
|
if (res != 0)
|
|
{
|
|
//Console.WriteLine ("GetCounterInfoPlus for " + path + " failed with " + res);
|
|
}
|
|
|
|
PDH_RAW_COUNTER rawValue;
|
|
res = PdhGetRawCounterValue(hCounter, out counterTypePtr, out rawValue);
|
|
if (res != 0)
|
|
{
|
|
samplesArr[sampleIndex++] = new PerformanceCounterSample(path,
|
|
_consumerPathToHandleAndInstanceMap[path].InstanceName,
|
|
0,
|
|
(ulong)0,
|
|
(ulong)0,
|
|
0,
|
|
PerformanceCounterType.RawBase,
|
|
defaultScale,
|
|
timeBase,
|
|
batchStamp,
|
|
(UInt64)batchStamp.ToFileTime(),
|
|
(rawValue.CStatus == 0) ? res : rawValue.CStatus);
|
|
|
|
numInvalidDataSamples++;
|
|
lastErr = res;
|
|
continue;
|
|
}
|
|
|
|
long dtFT = (((long)rawValue.TimeStamp.dwHighDateTime) << 32) +
|
|
(uint)rawValue.TimeStamp.dwLowDateTime;
|
|
|
|
DateTime dt = new DateTime(DateTime.FromFileTimeUtc(dtFT).Ticks, DateTimeKind.Local);
|
|
|
|
PDH_FMT_COUNTERVALUE_DOUBLE fmtValueDouble;
|
|
res = PdhGetFormattedCounterValue(hCounter,
|
|
PdhFormat.PDH_FMT_DOUBLE | PdhFormat.PDH_FMT_NOCAP100,
|
|
out counterTypePtr,
|
|
out fmtValueDouble);
|
|
if (res != 0)
|
|
{
|
|
samplesArr[sampleIndex++] = new PerformanceCounterSample(path,
|
|
_consumerPathToHandleAndInstanceMap[path].InstanceName,
|
|
0,
|
|
(ulong)rawValue.FirstValue,
|
|
(ulong)rawValue.SecondValue,
|
|
rawValue.MultiCount,
|
|
(PerformanceCounterType)counterType,
|
|
defaultScale,
|
|
timeBase,
|
|
dt,
|
|
(UInt64)dtFT,
|
|
(fmtValueDouble.CStatus == 0) ? res : rawValue.CStatus);
|
|
|
|
numInvalidDataSamples++;
|
|
lastErr = res;
|
|
continue;
|
|
}
|
|
|
|
samplesArr[sampleIndex++] = new PerformanceCounterSample(path,
|
|
_consumerPathToHandleAndInstanceMap[path].InstanceName,
|
|
fmtValueDouble.doubleValue,
|
|
(ulong)rawValue.FirstValue,
|
|
(ulong)rawValue.SecondValue,
|
|
rawValue.MultiCount,
|
|
(PerformanceCounterType)counterTypePtr.ToInt32(),
|
|
defaultScale,
|
|
timeBase,
|
|
dt,
|
|
(UInt64)dtFT,
|
|
fmtValueDouble.CStatus);
|
|
}
|
|
|
|
|
|
nextSet = new PerformanceCounterSampleSet(batchStamp, samplesArr, _firstReading);
|
|
_firstReading = false;
|
|
|
|
if (numInvalidDataSamples == samplesArr.Length)
|
|
{
|
|
res = lastErr;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Reset the error - any errors are saved per sample in PerformanceCounterSample.Status for kvetching later
|
|
//
|
|
res = 0;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
public uint GetFilesSummary(out CounterFileInfo summary)
|
|
{
|
|
IntPtr pNumEntries = new IntPtr(0);
|
|
PDH_TIME_INFO pInfo = new PDH_TIME_INFO();
|
|
IntPtr bufSize = new IntPtr(System.Runtime.InteropServices.Marshal.SizeOf(pInfo));
|
|
|
|
uint res = PdhGetDataSourceTimeRangeH(_hDataSource,
|
|
ref pNumEntries,
|
|
ref pInfo,
|
|
ref bufSize);
|
|
if (res != 0)
|
|
{
|
|
summary = new CounterFileInfo();
|
|
return res;
|
|
}
|
|
|
|
summary = new CounterFileInfo(new DateTime(DateTime.FromFileTimeUtc(pInfo.StartTime).Ticks, DateTimeKind.Local),
|
|
new DateTime(DateTime.FromFileTimeUtc(pInfo.EndTime).Ticks, DateTimeKind.Local),
|
|
pInfo.SampleCount);
|
|
|
|
return res;
|
|
}
|
|
|
|
public uint ExpandWildCardPath(string path, out StringCollection expandedPaths)
|
|
{
|
|
expandedPaths = new StringCollection();
|
|
IntPtr pcchPathListLength = new IntPtr(0);
|
|
|
|
uint res = PdhExpandWildCardPathH(_hDataSource,
|
|
path,
|
|
IntPtr.Zero,
|
|
ref pcchPathListLength,
|
|
PdhWildCardFlag.PDH_REFRESHCOUNTERS);
|
|
|
|
if (res != PdhResults.PDH_MORE_DATA)
|
|
{
|
|
return res;
|
|
}
|
|
|
|
Int32 cChars = pcchPathListLength.ToInt32();
|
|
IntPtr strPathList = Marshal.AllocHGlobal(cChars * sizeof(char));
|
|
|
|
try
|
|
{
|
|
res = PdhExpandWildCardPathH(_hDataSource, path, strPathList, ref pcchPathListLength, PdhWildCardFlag.PDH_REFRESHCOUNTERS);
|
|
if (res == 0)
|
|
{
|
|
ReadPdhMultiString(ref strPathList, pcchPathListLength.ToInt32(), ref expandedPaths);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
Marshal.FreeHGlobal(strPathList);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
public void ResetRelogValues()
|
|
{
|
|
Debug.Assert(_hOutputLog != null && !_hOutputLog.IsInvalid);
|
|
PdhResetRelogCounterValues(_hOutputLog);
|
|
}
|
|
|
|
public uint WriteRelogSample(DateTime timeStamp)
|
|
{
|
|
Debug.Assert(_hOutputLog != null && !_hOutputLog.IsInvalid);
|
|
return PdhWriteRelogSample(_hOutputLog, (new DateTime(timeStamp.Ticks, DateTimeKind.Utc)).ToFileTimeUtc());
|
|
}
|
|
|
|
public uint SetCounterValue(PerformanceCounterSample sample, out bool bUnknownPath)
|
|
{
|
|
Debug.Assert(_hOutputLog != null && !_hOutputLog.IsInvalid);
|
|
|
|
bUnknownPath = false;
|
|
|
|
string lcPath = sample.Path.ToLowerInvariant();
|
|
|
|
if (!_reloggerPathToHandleAndInstanceMap.ContainsKey(lcPath))
|
|
{
|
|
bUnknownPath = true;
|
|
return 0;
|
|
}
|
|
|
|
PDH_RAW_COUNTER rawStruct = new PDH_RAW_COUNTER();
|
|
rawStruct.FirstValue = (long)sample.RawValue;
|
|
rawStruct.SecondValue = (long)sample.SecondValue;
|
|
rawStruct.MultiCount = sample.MultipleCount;
|
|
rawStruct.TimeStamp.dwHighDateTime = (int)((new DateTime(sample.Timestamp.Ticks, DateTimeKind.Utc).ToFileTimeUtc() >> 32) & 0xFFFFFFFFL);
|
|
rawStruct.TimeStamp.dwLowDateTime = (int)(new DateTime(sample.Timestamp.Ticks, DateTimeKind.Utc).ToFileTimeUtc() & 0xFFFFFFFFL);
|
|
rawStruct.CStatus = sample.Status;
|
|
|
|
|
|
return PdhSetCounterValue(_reloggerPathToHandleAndInstanceMap[lcPath].hCounter,
|
|
ref rawStruct, /*PPDH_RAW_COUNTER */
|
|
_reloggerPathToHandleAndInstanceMap[lcPath].InstanceName);
|
|
}
|
|
}
|
|
}
|