private static unsafe ProcessInfo[] GetProcessInfos(IntPtr dataPtr) { // Use a dictionary to avoid duplicate entries if any // 60 is a reasonable number for processes on a normal machine. Dictionary <int, ProcessInfo> processInfos = new Dictionary <int, ProcessInfo>(60); long totalOffset = 0; while (true) { IntPtr currentPtr = (IntPtr)((long)dataPtr + totalOffset); ref SystemProcessInformation pi = ref *(SystemProcessInformation *)(currentPtr); // get information for a process ProcessInfo processInfo = new ProcessInfo(); // Process ID shouldn't overflow. OS API GetCurrentProcessID returns DWORD. processInfo.ProcessId = pi.UniqueProcessId.ToInt32(); processInfo.SessionId = (int)pi.SessionId; processInfo.PoolPagedBytes = (long)pi.QuotaPagedPoolUsage;; processInfo.PoolNonPagedBytes = (long)pi.QuotaNonPagedPoolUsage; processInfo.VirtualBytes = (long)pi.VirtualSize; processInfo.VirtualBytesPeak = (long)pi.PeakVirtualSize; processInfo.WorkingSetPeak = (long)pi.PeakWorkingSetSize; processInfo.WorkingSet = (long)pi.WorkingSetSize; processInfo.PageFileBytesPeak = (long)pi.PeakPagefileUsage; processInfo.PageFileBytes = (long)pi.PagefileUsage; processInfo.PrivateBytes = (long)pi.PrivatePageCount; processInfo.BasePriority = pi.BasePriority; processInfo.HandleCount = (int)pi.HandleCount; if (pi.ImageName.Buffer == IntPtr.Zero) { if (processInfo.ProcessId == NtProcessManager.SystemProcessID) { processInfo.ProcessName = "System"; } else if (processInfo.ProcessId == NtProcessManager.IdleProcessID) { processInfo.ProcessName = "Idle"; } else { // for normal process without name, using the process ID. processInfo.ProcessName = processInfo.ProcessId.ToString(CultureInfo.InvariantCulture); } } else { string processName = GetProcessShortName(Marshal.PtrToStringUni(pi.ImageName.Buffer, pi.ImageName.Length / sizeof(char))); processInfo.ProcessName = processName; } // get the threads for current process processInfos[processInfo.ProcessId] = processInfo; currentPtr = (IntPtr)((long)currentPtr + Marshal.SizeOf(pi)); int i = 0; while (i < pi.NumberOfThreads) { ref SystemThreadInformation ti = ref *(SystemThreadInformation *)(currentPtr); ThreadInfo threadInfo = new ThreadInfo(); threadInfo._processId = (int)ti.ClientId.UniqueProcess; threadInfo._threadId = (ulong)ti.ClientId.UniqueThread; threadInfo._basePriority = ti.BasePriority; threadInfo._currentPriority = ti.Priority; threadInfo._startAddress = ti.StartAddress; threadInfo._threadState = (ThreadState)ti.ThreadState; threadInfo._threadWaitReason = NtProcessManager.GetThreadWaitReason((int)ti.WaitReason); processInfo._threadInfoList.Add(threadInfo); currentPtr = (IntPtr)((long)currentPtr + Marshal.SizeOf(ti)); i++; }
static ProcessInfo[] GetProcessInfos(IntPtr dataPtr) { // 60 is a reasonable number for processes on a normal machine. Dictionary<int, ProcessInfo> processInfos = new Dictionary<int, ProcessInfo>(60); long totalOffset = 0; while (true) { IntPtr currentPtr = (IntPtr)((long)dataPtr + totalOffset); SystemProcessInformation pi = new SystemProcessInformation(); Marshal.PtrToStructure(currentPtr, pi); // get information for a process ProcessInfo processInfo = new ProcessInfo(); // Process ID shouldn't overflow. OS API GetCurrentProcessID returns DWORD. processInfo.ProcessId = pi.UniqueProcessId.ToInt32(); processInfo.SessionId = (int)pi.SessionId; processInfo.PoolPagedBytes = (long)pi.QuotaPagedPoolUsage; ; processInfo.PoolNonPagedBytes = (long)pi.QuotaNonPagedPoolUsage; processInfo.VirtualBytes = (long)pi.VirtualSize; processInfo.VirtualBytesPeak = (long)pi.PeakVirtualSize; processInfo.WorkingSetPeak = (long)pi.PeakWorkingSetSize; processInfo.WorkingSet = (long)pi.WorkingSetSize; processInfo.PageFileBytesPeak = (long)pi.PeakPagefileUsage; processInfo.PageFileBytes = (long)pi.PagefileUsage; processInfo.PrivateBytes = (long)pi.PrivatePageCount; processInfo.BasePriority = pi.BasePriority; if (pi.NamePtr == IntPtr.Zero) { if (processInfo.ProcessId == NtProcessManager.SystemProcessID) { processInfo.ProcessName = "System"; } else if (processInfo.ProcessId == NtProcessManager.IdleProcessID) { processInfo.ProcessName = "Idle"; } else { // for normal process without name, using the process ID. processInfo.ProcessName = processInfo.ProcessId.ToString(CultureInfo.InvariantCulture); } } else { string processName = GetProcessShortName(Marshal.PtrToStringUni(pi.NamePtr, pi.NameLength / sizeof(char))); processInfo.ProcessName = processName; } // get the threads for current process processInfos[processInfo.ProcessId] = processInfo; currentPtr = (IntPtr)((long)currentPtr + Marshal.SizeOf(pi)); int i = 0; while (i < pi.NumberOfThreads) { SystemThreadInformation ti = new SystemThreadInformation(); Marshal.PtrToStructure(currentPtr, ti); ThreadInfo threadInfo = new ThreadInfo(); threadInfo._processId = (int)ti.UniqueProcess; threadInfo._threadId = (ulong)ti.UniqueThread; threadInfo._basePriority = ti.BasePriority; threadInfo._currentPriority = ti.Priority; threadInfo._startAddress = ti.StartAddress; threadInfo._threadState = (ThreadState)ti.ThreadState; threadInfo._threadWaitReason = NtProcessManager.GetThreadWaitReason((int)ti.WaitReason); processInfo._threadInfoList.Add(threadInfo); currentPtr = (IntPtr)((long)currentPtr + Marshal.SizeOf(ti)); i++; } if (pi.NextEntryOffset == 0) { break; } totalOffset += pi.NextEntryOffset; } ProcessInfo[] temp = new ProcessInfo[processInfos.Values.Count]; processInfos.Values.CopyTo(temp, 0); return temp; }
static ProcessInfo[] GetProcessInfos(IntPtr dataPtr) { // 60 is a reasonable number for processes on a normal machine. Hashtable processInfos = new Hashtable(60); long totalOffset = 0; while(true) { IntPtr currentPtr = (IntPtr)((long)dataPtr + totalOffset); SystemProcessInformation pi = new SystemProcessInformation(); Marshal.PtrToStructure(currentPtr, pi); // get information for a process ProcessInfo processInfo = new ProcessInfo(); // Process ID shouldn't overflow. OS API GetCurrentProcessID returns DWORD. processInfo.processId = pi.UniqueProcessId.ToInt32(); processInfo.handleCount = (int)pi.HandleCount; processInfo.sessionId = (int)pi.SessionId; processInfo.poolPagedBytes = (long)pi.QuotaPagedPoolUsage;; processInfo.poolNonpagedBytes = (long)pi.QuotaNonPagedPoolUsage; processInfo.virtualBytes = (long)pi.VirtualSize; processInfo.virtualBytesPeak = (long)pi.PeakVirtualSize; processInfo.workingSetPeak = (long)pi.PeakWorkingSetSize; processInfo.workingSet = (long)pi.WorkingSetSize; processInfo.pageFileBytesPeak = (long)pi.PeakPagefileUsage; processInfo.pageFileBytes = (long)pi.PagefileUsage; processInfo.privateBytes = (long)pi.PrivatePageCount; processInfo.basePriority = pi.BasePriority; if( pi.NamePtr == IntPtr.Zero) { if( processInfo.processId == NtProcessManager.SystemProcessID) { processInfo.processName = "System"; } else if( processInfo.processId == NtProcessManager.IdleProcessID) { processInfo.processName = "Idle"; } else { // for normal process without name, using the process ID. processInfo.processName = processInfo.processId.ToString(CultureInfo.InvariantCulture); } } else { string processName = GetProcessShortName(Marshal.PtrToStringUni(pi.NamePtr, pi.NameLength/sizeof(char))); // // On old operating system (NT4 and windows 2000), the process name might be truncated to 15 // characters. For example, aspnet_admin.exe will show up in performance counter as aspnet_admin.ex. // Process class try to return a nicer name. We used to get the main module name for a process and // use that as the process name. However normal user doesn't have access to module information, // so normal user will see an exception when we try to get a truncated process name. // if (ProcessManager.IsOSOlderThanXP && (processName.Length == 15)) { if (processName.EndsWith(".", StringComparison.OrdinalIgnoreCase)) { processName = processName.Substring(0, 14); } else if (processName.EndsWith(".e", StringComparison.OrdinalIgnoreCase)) { processName = processName.Substring(0, 13); } else if (processName.EndsWith(".ex", StringComparison.OrdinalIgnoreCase)) { processName = processName.Substring(0, 12); } } processInfo.processName = processName; } // get the threads for current process processInfos[processInfo.processId] = processInfo; currentPtr = (IntPtr)((long)currentPtr + Marshal.SizeOf(pi)); int i = 0; while( i < pi.NumberOfThreads) { SystemThreadInformation ti = new SystemThreadInformation(); Marshal.PtrToStructure(currentPtr, ti); ThreadInfo threadInfo = new ThreadInfo(); threadInfo.processId = (int)ti.UniqueProcess; threadInfo.threadId = (int)ti.UniqueThread; threadInfo.basePriority = ti.BasePriority; threadInfo.currentPriority = ti.Priority; threadInfo.startAddress = ti.StartAddress; threadInfo.threadState = (ThreadState)ti.ThreadState; threadInfo.threadWaitReason = NtProcessManager.GetThreadWaitReason((int)ti.WaitReason); processInfo.threadInfoList.Add(threadInfo); currentPtr = (IntPtr)((long)currentPtr + Marshal.SizeOf(ti)); i++; } if (pi.NextEntryOffset == 0) { break; } totalOffset += pi.NextEntryOffset; } ProcessInfo[] temp = new ProcessInfo[processInfos.Values.Count]; processInfos.Values.CopyTo(temp, 0); return temp; }
static ProcessInfo[] GetProcessInfos(IntPtr dataPtr) { // 60 is a reasonable number for processes on a normal machine. Dictionary <int, ProcessInfo> processInfos = new Dictionary <int, ProcessInfo>(60); long totalOffset = 0; while (true) { IntPtr currentPtr = (IntPtr)((long)dataPtr + totalOffset); SystemProcessInformation pi = new SystemProcessInformation(); Marshal.PtrToStructure(currentPtr, pi); // get information for a process ProcessInfo processInfo = new ProcessInfo(); // Process ID shouldn't overflow. OS API GetCurrentProcessID returns DWORD. processInfo._processId = pi.UniqueProcessId.ToInt32(); processInfo._handleCount = (int)pi.HandleCount; processInfo._sessionId = (int)pi.SessionId; processInfo._poolPagedBytes = (long)pi.QuotaPagedPoolUsage;; processInfo._poolNonpagedBytes = (long)pi.QuotaNonPagedPoolUsage; processInfo._virtualBytes = (long)pi.VirtualSize; processInfo._virtualBytesPeak = (long)pi.PeakVirtualSize; processInfo._workingSetPeak = (long)pi.PeakWorkingSetSize; processInfo._workingSet = (long)pi.WorkingSetSize; processInfo._pageFileBytesPeak = (long)pi.PeakPagefileUsage; processInfo._pageFileBytes = (long)pi.PagefileUsage; processInfo._privateBytes = (long)pi.PrivatePageCount; processInfo._basePriority = pi.BasePriority; if (pi.NamePtr == IntPtr.Zero) { if (processInfo._processId == NtProcessManager.SystemProcessID) { processInfo._processName = "System"; } else if (processInfo._processId == NtProcessManager.IdleProcessID) { processInfo._processName = "Idle"; } else { // for normal process without name, using the process ID. processInfo._processName = processInfo._processId.ToString(CultureInfo.InvariantCulture); } } else { string processName = GetProcessShortName(Marshal.PtrToStringUni(pi.NamePtr, pi.NameLength / sizeof(char))); processInfo._processName = processName; } // get the threads for current process processInfos[processInfo._processId] = processInfo; currentPtr = (IntPtr)((long)currentPtr + Marshal.SizeOf(pi)); int i = 0; while (i < pi.NumberOfThreads) { SystemThreadInformation ti = new SystemThreadInformation(); Marshal.PtrToStructure(currentPtr, ti); ThreadInfo threadInfo = new ThreadInfo(); threadInfo._processId = (int)ti.UniqueProcess; threadInfo._threadId = (int)ti.UniqueThread; threadInfo._basePriority = ti.BasePriority; threadInfo._currentPriority = ti.Priority; threadInfo._startAddress = ti.StartAddress; threadInfo._threadState = (ThreadState)ti.ThreadState; threadInfo._threadWaitReason = NtProcessManager.GetThreadWaitReason((int)ti.WaitReason); processInfo._threadInfoList.Add(threadInfo); currentPtr = (IntPtr)((long)currentPtr + Marshal.SizeOf(ti)); i++; } if (pi.NextEntryOffset == 0) { break; } totalOffset += pi.NextEntryOffset; } ProcessInfo[] temp = new ProcessInfo[processInfos.Values.Count]; processInfos.Values.CopyTo(temp, 0); return(temp); }
protected override void Update() { // Load symbols if they are not already loaded. this.LoadSymbols(); var threads = Windows.GetProcessThreads(_pid); Dictionary <int, ThreadItem> newdictionary = new Dictionary <int, ThreadItem>(this.Dictionary); if (threads == null) { threads = new Dictionary <int, SystemThreadInformation>(); } // look for dead threads foreach (int tid in Dictionary.Keys) { if (!threads.ContainsKey(tid)) { ThreadItem item = this.Dictionary[tid]; if (item.ThreadQueryLimitedHandle != null) { item.ThreadQueryLimitedHandle.Dispose(); } this.OnDictionaryRemoved(item); newdictionary.Remove(tid); } } // Get resolve results. _messageQueue.Listen(); // look for new threads foreach (int tid in threads.Keys) { SystemThreadInformation t = threads[tid]; if (!Dictionary.ContainsKey(tid)) { ThreadItem item = new ThreadItem { RunId = this.RunCount, Tid = tid, ContextSwitches = t.ContextSwitchCount, WaitReason = t.WaitReason }; try { item.ThreadQueryHandle = new ThreadHandle(tid, OSVersion.MinThreadQueryInfoAccess); item.ThreadQueryLimitedHandle = new ThreadHandle(tid, Program.MinThreadQueryRights); try { item.PriorityI = (int)item.ThreadQueryLimitedHandle.GetBasePriorityWin32(); item.Priority = item.ThreadQueryLimitedHandle.GetBasePriorityWin32().ToString(); } catch { } //if (KProcessHacker.Instance != null) //{ // try // { // item.IsGuiThread = KProcessHacker.Instance.KphGetThreadWin32Thread(item.ThreadQueryLimitedHandle) != 0; // } // catch // { } //} if (OSVersion.HasCycleTime) { try { item.Cycles = item.ThreadQueryLimitedHandle.GetCycleTime(); } catch { } } item.StartAddressI = item.ThreadQueryLimitedHandle.GetWin32StartAddress(); } catch { item.StartAddressI = t.StartAddress; } if (_moduleLoadCompletedEvent.Wait(0)) { try { item.StartAddress = this.GetThreadBasicStartAddress( item.StartAddressI.ToUInt64(), out item.StartAddressLevel); } catch { } } if (string.IsNullOrEmpty(item.StartAddress)) { item.StartAddress = Utils.FormatAddress(item.StartAddressI); item.StartAddressLevel = SymbolResolveLevel.Address; } this.QueueThreadResolveStartAddress(tid, item.StartAddressI.ToUInt64()); newdictionary.Add(tid, item); this.OnDictionaryAdded(item); } // look for modified threads else { ThreadItem item = Dictionary[tid]; ThreadItem newitem = item.Clone() as ThreadItem; newitem.JustResolved = false; newitem.ContextSwitchesDelta = t.ContextSwitchCount - newitem.ContextSwitches; newitem.ContextSwitches = t.ContextSwitchCount; newitem.WaitReason = t.WaitReason; try { newitem.PriorityI = (int)newitem.ThreadQueryLimitedHandle.GetBasePriorityWin32(); newitem.Priority = newitem.ThreadQueryLimitedHandle.GetBasePriorityWin32().ToString(); } catch { } if (OSVersion.HasCycleTime) { try { ulong thisCycles = newitem.ThreadQueryLimitedHandle.GetCycleTime(); newitem.CyclesDelta = thisCycles - newitem.Cycles; newitem.Cycles = thisCycles; } catch { } } if (newitem.StartAddressLevel == SymbolResolveLevel.Address) { if (_moduleLoadCompletedEvent.Wait(0)) { newitem.StartAddress = this.GetThreadBasicStartAddress( newitem.StartAddressI.ToUInt64(), out newitem.StartAddressLevel); } // If we couldn't resolve it to a module+offset, // use the StartAddress (instead of the Win32StartAddress) // and queue the resolve again. if ( item.StartAddressLevel == SymbolResolveLevel.Address && item.JustResolved) { if (item.StartAddressI != t.StartAddress) { item.StartAddressI = t.StartAddress; this.QueueThreadResolveStartAddress(tid, item.StartAddressI.ToUInt64()); } } } if ( newitem.ContextSwitches != item.ContextSwitches || newitem.ContextSwitchesDelta != item.ContextSwitchesDelta || newitem.Cycles != item.Cycles || newitem.CyclesDelta != item.CyclesDelta || newitem.IsGuiThread != item.IsGuiThread || newitem.Priority != item.Priority || newitem.StartAddress != item.StartAddress || newitem.WaitReason != item.WaitReason || item.JustResolved ) { newdictionary[tid] = newitem; this.OnDictionaryModified(item, newitem); } } } Dictionary = newdictionary; }
public static ProcessInfo[] NtGetProcessInfos(IntPtr dataPtr) { IntPtr ptr; Hashtable hashtable = new Hashtable(100); uint num = 0; Label_000B: ptr = (IntPtr)(((uint)dataPtr) + num); SystemProcessInformation structure = new SystemProcessInformation(); Marshal.PtrToStructure(ptr, structure); ProcessInfo info = new ProcessInfo(); info.processId = structure.UniqueProcessId.ToInt32(); info.handleCount = (int)structure.HandleCount; info.sessionId = (int)structure.SessionId; info.poolPagedBytes = (long)structure.QuotaPagedPoolUsage; info.poolNonpagedBytes = (long)structure.QuotaNonPagedPoolUsage; info.virtualBytes = (long)structure.VirtualSize; info.virtualBytesPeak = (long)structure.PeakVirtualSize; info.workingSetPeak = (long)structure.PeakWorkingSetSize; info.workingSet = (long)structure.WorkingSetSize; info.pageFileBytesPeak = (long)structure.PeakPagefileUsage; info.pageFileBytes = (long)structure.PagefileUsage; info.privateBytes = (long)structure.PrivatePageCount; info.basePriority = structure.BasePriority; hashtable[info.processId] = info; try { ptr = (IntPtr)(((long)ptr) + Marshal.SizeOf(structure)); } catch { } for (int i = 0; i < structure.NumberOfThreads; i++) { SystemThreadInformation information2 = new SystemThreadInformation(); Marshal.PtrToStructure(ptr, information2); ThreadInfo info2 = new ThreadInfo { processId = (int)information2.UniqueProcess, threadId = (int)information2.UniqueThread, basePriority = information2.BasePriority, currentPriority = information2.Priority, startAddress = information2.StartAddress, threadState = (ThreadState)information2.ThreadState, threadWaitReason = GetThreadWaitReason((int)information2.WaitReason) }; info.threadInfoList.Add(info2); try { ptr = (IntPtr)(((long)ptr) + Marshal.SizeOf(information2)); } catch { } } if (structure.NextEntryOffset != 0) { num += (uint)structure.NextEntryOffset; goto Label_000B; } ProcessInfo[] array = new ProcessInfo[hashtable.Values.Count]; hashtable.Values.CopyTo(array, 0); return(array); }
private static ProcessInfo[] GetProcessInfos(IntPtr dataPtr) { IntPtr ptr; Hashtable hashtable = new Hashtable(60); long num = 0L; Label_000B: ptr = (IntPtr)(((long)dataPtr) + num); SystemProcessInformation structure = new SystemProcessInformation(); Marshal.PtrToStructure(ptr, structure); ProcessInfo info = new ProcessInfo { processId = structure.UniqueProcessId.ToInt32(), handleCount = (int)structure.HandleCount, sessionId = (int)structure.SessionId, poolPagedBytes = (long)((ulong)structure.QuotaPagedPoolUsage), poolNonpagedBytes = (long)((ulong)structure.QuotaNonPagedPoolUsage), virtualBytes = (long)((ulong)structure.VirtualSize), virtualBytesPeak = (long)((ulong)structure.PeakVirtualSize), workingSetPeak = (long)((ulong)structure.PeakWorkingSetSize), workingSet = (long)((ulong)structure.WorkingSetSize), pageFileBytesPeak = (long)((ulong)structure.PeakPagefileUsage), pageFileBytes = (long)((ulong)structure.PagefileUsage), privateBytes = (long)((ulong)structure.PrivatePageCount), basePriority = structure.BasePriority }; if (structure.NamePtr == IntPtr.Zero) { if (info.processId == NtProcessManager.SystemProcessID) { info.processName = "System"; } else if (info.processId == 0) { info.processName = "Idle"; } else { info.processName = info.processId.ToString(CultureInfo.InvariantCulture); } } else { string processShortName = GetProcessShortName(Marshal.PtrToStringUni(structure.NamePtr, structure.NameLength / 2)); if (ProcessManager.IsOSOlderThanXP && (processShortName.Length == 15)) { if (processShortName.EndsWith(".", StringComparison.OrdinalIgnoreCase)) { processShortName = processShortName.Substring(0, 14); } else if (processShortName.EndsWith(".e", StringComparison.OrdinalIgnoreCase)) { processShortName = processShortName.Substring(0, 13); } else if (processShortName.EndsWith(".ex", StringComparison.OrdinalIgnoreCase)) { processShortName = processShortName.Substring(0, 12); } } info.processName = processShortName; } hashtable[info.processId] = info; ptr = (IntPtr)(((long)ptr) + Marshal.SizeOf(structure)); for (int i = 0; i < structure.NumberOfThreads; i++) { SystemThreadInformation information2 = new SystemThreadInformation(); Marshal.PtrToStructure(ptr, information2); ThreadInfo info2 = new ThreadInfo { processId = (int)information2.UniqueProcess, threadId = (int)information2.UniqueThread, basePriority = information2.BasePriority, currentPriority = information2.Priority, startAddress = information2.StartAddress, threadState = (ThreadState)information2.ThreadState, threadWaitReason = NtProcessManager.GetThreadWaitReason((int)information2.WaitReason) }; info.threadInfoList.Add(info2); ptr = (IntPtr)(((long)ptr) + Marshal.SizeOf(information2)); } if (structure.NextEntryOffset != 0) { num += structure.NextEntryOffset; goto Label_000B; } ProcessInfo[] array = new ProcessInfo[hashtable.Values.Count]; hashtable.Values.CopyTo(array, 0); return(array); }
/// <summary> /// Gets a dictionary containing the threads owned by the specified process. /// </summary> /// <param name="pid">A process ID.</param> /// <returns>A dictionary, indexed by thread ID.</returns> public static Dictionary <int, SystemThreadInformation> GetProcessThreads(int pid) { int retLength; if (_processesBuffer == null) { _processesBuffer = new MemoryAlloc(0x10000); } MemoryAlloc data = _processesBuffer; NtStatus status; int attempts = 0; while (true) { attempts++; if ((status = Win32.NtQuerySystemInformation( SystemInformationClass.SystemProcessInformation, data.Memory, data.Size, out retLength) ).IsError()) { if (attempts > 3) { Win32.Throw(status); } data.ResizeNew(retLength); } else { break; } } int i = 0; SystemProcessInformation process; do { unsafe { //process = data.ReadStruct<SystemProcessInformation>(i, 0); process = *(SystemProcessInformation *)((byte *)data.Memory + i); } if (process.ProcessId == pid) { Dictionary <int, SystemThreadInformation> threads = new Dictionary <int, SystemThreadInformation>(); for (int j = 0; j < process.NumberOfThreads; j++) { SystemThreadInformation thread = data.ReadStruct <SystemThreadInformation>(i + SystemProcessInformation.SizeOf, SystemThreadInformation.SizeOf, j); if (pid != 0) { threads.Add(thread.ClientId.ThreadId, thread); } else { // Fix System Idle Process threads. // There is one thread per CPU, but they // all have a TID of 0. Assign unique TIDs. threads.Add(j, thread); } } return(threads); } i += process.NextEntryOffset; } while (process.NextEntryOffset != 0); return(null); }