static ProcessInfo[] GetProcessInfos(PerformanceCounterLib library, int processIndex, int threadIndex, byte[] data)
{
#if FEATURE_TRACESWITCH
Debug.WriteLineIf(Process._processTracing.TraceVerbose, "GetProcessInfos()");
#endif
Dictionary <int, ProcessInfo> processInfos = new Dictionary <int, ProcessInfo>();
List <ThreadInfo> threadInfos = new List <ThreadInfo>();
GCHandle dataHandle = new GCHandle();
try
{
dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
IntPtr dataBlockPtr = dataHandle.AddrOfPinnedObject();
Interop.Advapi32.PERF_DATA_BLOCK dataBlock = new Interop.Advapi32.PERF_DATA_BLOCK();
Marshal.PtrToStructure(dataBlockPtr, dataBlock);
IntPtr typePtr = (IntPtr)((long)dataBlockPtr + dataBlock.HeaderLength);
Interop.Advapi32.PERF_INSTANCE_DEFINITION instance = new Interop.Advapi32.PERF_INSTANCE_DEFINITION();
Interop.Advapi32.PERF_COUNTER_BLOCK counterBlock = new Interop.Advapi32.PERF_COUNTER_BLOCK();
for (int i = 0; i < dataBlock.NumObjectTypes; i++)
{
Interop.Advapi32.PERF_OBJECT_TYPE type = new Interop.Advapi32.PERF_OBJECT_TYPE();
Marshal.PtrToStructure(typePtr, type);
IntPtr instancePtr = (IntPtr)((long)typePtr + type.DefinitionLength);
IntPtr counterPtr = (IntPtr)((long)typePtr + type.HeaderLength);
List <Interop.Advapi32.PERF_COUNTER_DEFINITION> counterList = new List <Interop.Advapi32.PERF_COUNTER_DEFINITION>();
for (int j = 0; j < type.NumCounters; j++)
{
Interop.Advapi32.PERF_COUNTER_DEFINITION counter = new Interop.Advapi32.PERF_COUNTER_DEFINITION();
Marshal.PtrToStructure(counterPtr, counter);
string counterName = library.GetCounterName(counter.CounterNameTitleIndex);
if (type.ObjectNameTitleIndex == processIndex)
{
counter.CounterNameTitlePtr = (int)GetValueId(counterName);
}
else if (type.ObjectNameTitleIndex == threadIndex)
{
counter.CounterNameTitlePtr = (int)GetValueId(counterName);
}
counterList.Add(counter);
counterPtr = (IntPtr)((long)counterPtr + counter.ByteLength);
}
Interop.Advapi32.PERF_COUNTER_DEFINITION[] counters = counterList.ToArray();
for (int j = 0; j < type.NumInstances; j++)
{
Marshal.PtrToStructure(instancePtr, instance);
IntPtr namePtr = (IntPtr)((long)instancePtr + instance.NameOffset);
string instanceName = Marshal.PtrToStringUni(namePtr);
if (instanceName.Equals("_Total"))
{
continue;
}
IntPtr counterBlockPtr = (IntPtr)((long)instancePtr + instance.ByteLength);
Marshal.PtrToStructure(counterBlockPtr, counterBlock);
if (type.ObjectNameTitleIndex == processIndex)
{
ProcessInfo processInfo = GetProcessInfo(type, (IntPtr)((long)instancePtr + instance.ByteLength), counters);
if (processInfo.ProcessId == 0 && string.Compare(instanceName, "Idle", StringComparison.OrdinalIgnoreCase) != 0)
{
// Sometimes we'll get a process structure that is not completely filled in.
// We can catch some of these by looking for non-"idle" processes that have id 0
// and ignoring those.
#if FEATURE_TRACESWITCH
Debug.WriteLineIf(Process._processTracing.TraceVerbose, "GetProcessInfos() - found a non-idle process with id 0; ignoring.");
#endif
}
else
{
if (processInfos.ContainsKey(processInfo.ProcessId))
{
// We've found two entries in the perfcounters that claim to be the
// same process. We throw an exception. Is this really going to be
// helpful to the user? Should we just ignore?
#if FEATURE_TRACESWITCH
Debug.WriteLineIf(Process._processTracing.TraceVerbose, "GetProcessInfos() - found a duplicate process id");
#endif
}
else
{
// the performance counters keep a 15 character prefix of the exe name, and then delete the ".exe",
// if it's in the first 15. The problem is that sometimes that will leave us with part of ".exe"
// at the end. If instanceName ends in ".", ".e", or ".ex" we remove it.
string processName = instanceName;
if (processName.Length == 15)
{
if (instanceName.EndsWith(".", StringComparison.Ordinal))
{
processName = instanceName.Substring(0, 14);
}
else if (instanceName.EndsWith(".e", StringComparison.Ordinal))
{
processName = instanceName.Substring(0, 13);
}
else if (instanceName.EndsWith(".ex", StringComparison.Ordinal))
{
processName = instanceName.Substring(0, 12);
}
}
processInfo.ProcessName = processName;
processInfos.Add(processInfo.ProcessId, processInfo);
}
}
}
else if (type.ObjectNameTitleIndex == threadIndex)
{
ThreadInfo threadInfo = GetThreadInfo(type, (IntPtr)((long)instancePtr + instance.ByteLength), counters);
if (threadInfo._threadId != 0)
{
threadInfos.Add(threadInfo);
}
}
instancePtr = (IntPtr)((long)instancePtr + instance.ByteLength + counterBlock.ByteLength);
}
typePtr = (IntPtr)((long)typePtr + type.TotalByteLength);
}
}
finally
{
if (dataHandle.IsAllocated)
{
dataHandle.Free();
}
}
for (int i = 0; i < threadInfos.Count; i++)
{
ThreadInfo threadInfo = (ThreadInfo)threadInfos[i];
ProcessInfo processInfo;
if (processInfos.TryGetValue(threadInfo._processId, out processInfo))
{
processInfo._threadInfoList.Add(threadInfo);
}
}
ProcessInfo[] temp = new ProcessInfo[processInfos.Values.Count];
processInfos.Values.CopyTo(temp, 0);
return(temp);
}