PowerShell/src/Microsoft.PowerShell.Commands.Diagnostics/PdhHelper.cs
PowerShell Team c748652c34 Copy all mapped files from [SD:725290]
commit 8cec8f150da7583b7af5efbe2853efee0179750c
2016-07-28 23:23:03 -07:00

1797 lines
74 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 m_isPreVista = false;
public PdhHelper (bool isPreVista)
{
m_isPreVista = isPreVista;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
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)]
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)]
struct PDH_FMT_COUNTERVALUE_DOUBLE
{
public uint CStatus;
public double doubleValue;
} ;
[StructLayout(LayoutKind.Sequential)]
struct PDH_FMT_COUNTERVALUE_UNICODE
{
public uint CStatus;
[MarshalAs(UnmanagedType.LPWStr)]
public string WideStringValue;
} ;
[StructLayout(LayoutKind.Sequential)]
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)]
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 m_hDataSource = null;
private PdhSafeQueryHandle m_hQuery = null;
private bool m_firstReading = true;
private PdhSafeLogHandle m_hOutputLog = null;
//
// Implement IDisposable::Dispose() to close native safe handles
//
public void Dispose()
{
if (m_hDataSource != null && !m_hDataSource.IsInvalid)
{
m_hDataSource.Dispose();
}
if (m_hOutputLog != null && !m_hOutputLog.IsInvalid)
{
m_hOutputLog.Dispose();
}
if (m_hQuery != null && !m_hQuery.IsInvalid)
{
m_hQuery.Dispose();
}
GC.SuppressFinalize(this);
}
//
// m_ConsumerPathToHandleAndInstanceMap map is used for reading counter date (live or from files).
//
private Dictionary<string, CounterHandleNInstance> m_ConsumerPathToHandleAndInstanceMap = new Dictionary<string, CounterHandleNInstance>();
//
// m_ReloggerPathToHandleAndInstanceMap map is used for writing relog counters.
//
private Dictionary<string, CounterHandleNInstance> m_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="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 (m_hDataSource != null && !m_hDataSource.IsInvalid)
{
m_hDataSource.Dispose();
}
uint res = PdhHelper.PdhBindInputDataSource(out m_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 (m_hDataSource != null && !m_hDataSource.IsInvalid)
{
m_hDataSource.Dispose();
}
uint res = PdhHelper.PdhBindInputDataSource(out m_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(m_hDataSource, IntPtr.Zero, out m_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 (m_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,
m_hQuery,
maxSize,
caption,
out m_hOutputLog);
return res;
}
public uint SetQueryTimeRange(DateTime startTime, DateTime endTime)
{
Debug.Assert (m_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 (m_hQuery, ref pTimeInfo);
}
public uint EnumBlgFilesMachines(ref StringCollection machineNames)
{
IntPtr MachineListTcharSizePtr = new IntPtr(0);
uint res = PdhHelper.PdhEnumMachinesH(m_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(m_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(m_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(m_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(m_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(m_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(m_hDataSource != null && !m_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 (!m_isPreVista)
{
ret = (PdhValidatePathEx(m_hDataSource, outPath) == 0);
}
else
{
ret = (PdhValidatePath(outPath) == 0);
}
}
}
finally
{
Marshal.FreeHGlobal(strPath);
}
return ret;
}
public bool IsPathValid(string path)
{
if (!m_isPreVista)
{
return (PdhValidatePathEx(m_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 = (PDH_COUNTER_PATH_ELEMENTS)Marshal.PtrToStructure(structPtr, typeof(PDH_COUNTER_PATH_ELEMENTS));
}
}
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.ToLower(CultureInfo.InvariantCulture);
machineNameMassaged = machineNameMassaged.TrimStart('\\');
Debug.Assert (machineNameMassaged == System.Environment.MachineName.ToLower(CultureInfo.InvariantCulture));
string lowerEngCtrName = pathElts.CounterName.ToLower(CultureInfo.InvariantCulture);
string lowerEngObjectName = pathElts.ObjectName.ToLower(CultureInfo.InvariantCulture);
// 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.ToLower(CultureInfo.InvariantCulture) == lowerEngCtrName)
{
try
{
counterIndex = Convert.ToInt32(regCounters[enumIndex-1], CultureInfo.InvariantCulture);
}
catch (Exception)
{
return (uint)PdhResults.PDH_INVALID_PATH;
}
}
else if (regString.ToLower(CultureInfo.InvariantCulture) == 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(m_hQuery != null && !m_hQuery.IsInvalid);
if (bFlushOldCounters)
{
m_ConsumerPathToHandleAndInstanceMap.Clear();
}
bool bAtLeastOneAdded = false;
uint res = 0;
foreach (string counterPath in validPaths)
{
IntPtr counterHandle;
res = PdhAddCounter(m_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.ToLower(CultureInfo.InvariantCulture);
}
if (!m_ConsumerPathToHandleAndInstanceMap.ContainsKey(counterPath.ToLower(CultureInfo.InvariantCulture)))
{
m_ConsumerPathToHandleAndInstanceMap.Add(counterPath.ToLower(CultureInfo.InvariantCulture), 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(m_hQuery != null && !m_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.ToLower(CultureInfo.InvariantCulture);
string lowerCaseObject = pathElts.ObjectName.ToLower(CultureInfo.InvariantCulture);
string lowerCaseCounter = pathElts.CounterName.ToLower(CultureInfo.InvariantCulture);
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(m_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;
}
//Console.WriteLine ("added pdh query path:" + unifiedPath );
//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.ToLower(CultureInfo.InvariantCulture);
}
if (!m_ReloggerPathToHandleAndInstanceMap.ContainsKey(sample.Path.ToLower(CultureInfo.InvariantCulture)))
{
m_ReloggerPathToHandleAndInstanceMap.Add(sample.Path.ToLower(CultureInfo.InvariantCulture), chi);
//Console.WriteLine ("added map path:" + sample.Path );
}
}
}
//TODO: verify that all counters are in the map
return (m_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(m_hQuery != null && !m_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(m_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.ToLower(CultureInfo.InvariantCulture);
}
if (!m_ReloggerPathToHandleAndInstanceMap.ContainsKey(sample.Path.ToLower(CultureInfo.InvariantCulture)))
{
m_ReloggerPathToHandleAndInstanceMap.Add(sample.Path.ToLower(CultureInfo.InvariantCulture), chi);
}
}
return (m_ReloggerPathToHandleAndInstanceMap.Keys.Count > 0) ? 0 : res;
}
public string GetCounterSetHelp(string szMachineName, string szObjectName)
{
if (m_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(m_hQuery);
if (bSkipReading)
{
return res;
}
if (res != 0 && res != PdhResults.PDH_NO_DATA)
{
return res;
}
PerformanceCounterSample[] samplesArr = new PerformanceCounterSample[m_ConsumerPathToHandleAndInstanceMap.Count];
uint sampleIndex = 0;
uint numInvalidDataSamples = 0;
uint lastErr = 0;
DateTime sampleTimeStamp = DateTime.Now;
foreach (string path in m_ConsumerPathToHandleAndInstanceMap.Keys)
{
IntPtr counterTypePtr = new IntPtr(0);
UInt32 counterType = (UInt32)PerformanceCounterType.RawBase;
UInt32 defaultScale = 0;
UInt64 timeBase = 0;
IntPtr hCounter = m_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,
m_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,
m_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,
m_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 timstamp instead.
//
nextSet = new PerformanceCounterSampleSet(sampleTimeStamp, samplesArr, m_firstReading);
m_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(m_hQuery != null && !m_hQuery.IsInvalid);
if (m_isPreVista)
{
return ReadNextSetPreVista (out nextSet, bSkipReading);
}
uint res = 0;
nextSet = null;
Int64 batchTimeStampFT = 0;
res = PdhCollectQueryDataWithTime(m_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[m_ConsumerPathToHandleAndInstanceMap.Count];
uint sampleIndex = 0;
uint numInvalidDataSamples = 0;
uint lastErr = 0;
foreach (string path in m_ConsumerPathToHandleAndInstanceMap.Keys)
{
IntPtr counterTypePtr = new IntPtr(0);
UInt32 counterType = (UInt32)PerformanceCounterType.RawBase;
UInt32 defaultScale = 0;
UInt64 timeBase = 0;
IntPtr hCounter = m_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,
m_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,
m_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,
m_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, m_firstReading);
m_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(m_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(m_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(m_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(m_hOutputLog != null && !m_hOutputLog.IsInvalid);
PdhResetRelogCounterValues(m_hOutputLog);
}
public uint WriteRelogSample (DateTime timeStamp)
{
Debug.Assert(m_hOutputLog != null && !m_hOutputLog.IsInvalid);
return PdhWriteRelogSample(m_hOutputLog, (new DateTime(timeStamp.Ticks, DateTimeKind.Utc)).ToFileTimeUtc() );
}
public uint SetCounterValue (PerformanceCounterSample sample, out bool bUnknownPath)
{
Debug.Assert(m_hOutputLog != null && !m_hOutputLog.IsInvalid);
bUnknownPath = false;
string lcPath = sample.Path.ToLower(CultureInfo.InvariantCulture);
if (!m_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 (m_ReloggerPathToHandleAndInstanceMap[lcPath].hCounter,
ref rawStruct, /*PPDH_RAW_COUNTER */
m_ReloggerPathToHandleAndInstanceMap[lcPath].InstanceName);
}
}
}