[LoongArch64] Part-5:add loongarch support in some files for LoongArch64. (#21769)
[mono-project.git] / mcs / class / referencesource / System / services / monitoring / system / diagnosticts / ProcessManager.cs
blob9c9d5e9e41e9e8c12b76bead27329801973e2b16
1 #if !FEATURE_PAL
2 namespace System.Diagnostics {
3 using System.Text;
4 using System.Threading;
5 using System.Runtime.InteropServices;
6 using System.ComponentModel;
7 using System.ComponentModel.Design;
8 using System.Diagnostics;
9 using System;
10 using System.Collections;
11 using System.IO;
12 using Microsoft.Win32;
13 using Microsoft.Win32.SafeHandles;
14 using System.Collections.Specialized;
15 using System.Globalization;
16 using System.Security;
17 using System.Security.Permissions;
18 using System.Security.Principal;
19 using System.Runtime.Versioning;
20 using System.Diagnostics.Contracts;
22 /// <devdoc>
23 /// This class finds the main window of a process. It needs to be
24 /// class because we need to store state while searching the set
25 /// of windows.
26 /// </devdoc>
27 /// <internalonly/>
28 internal class MainWindowFinder {
29 IntPtr bestHandle;
30 int processId;
32 [ResourceExposure(ResourceScope.Process)]
33 [ResourceConsumption(ResourceScope.Process)]
34 public IntPtr FindMainWindow(int processId) {
35 bestHandle = (IntPtr)0;
36 this.processId = processId;
38 NativeMethods.EnumThreadWindowsCallback callback = new NativeMethods.EnumThreadWindowsCallback(this.EnumWindowsCallback);
39 NativeMethods.EnumWindows(callback, IntPtr.Zero);
41 GC.KeepAlive(callback);
42 return bestHandle;
45 [ResourceExposure(ResourceScope.Process)]
46 [ResourceConsumption(ResourceScope.Process)]
47 bool IsMainWindow(IntPtr handle) {
49 if (NativeMethods.GetWindow(new HandleRef(this, handle), NativeMethods.GW_OWNER) != (IntPtr)0 || !NativeMethods.IsWindowVisible(new HandleRef(this, handle)))
50 return false;
52 // Microsoft: should we use no window title to mean not a main window? (task man does)
55 int length = NativeMethods.GetWindowTextLength(handle) * 2;
56 StringBuilder builder = new StringBuilder(length);
57 if (NativeMethods.GetWindowText(handle, builder, builder.Capacity) == 0)
58 return false;
59 if (builder.ToString() == string.Empty)
60 return false;
63 return true;
66 [ResourceExposure(ResourceScope.Machine)]
67 [ResourceConsumption(ResourceScope.Machine)]
68 bool EnumWindowsCallback(IntPtr handle, IntPtr extraParameter) {
69 int processId;
70 NativeMethods.GetWindowThreadProcessId(new HandleRef(this, handle), out processId);
71 if (processId == this.processId) {
72 if (IsMainWindow(handle)) {
73 bestHandle = handle;
74 return false;
77 return true;
81 /// <devdoc>
82 /// This static class is a platform independent Api for querying information
83 /// about processes, threads and modules. It delegates to the platform
84 /// specific classes WinProcessManager for Win9x and NtProcessManager
85 /// for WinNt.
86 /// </devdoc>
87 /// <internalonly/>
88 internal static class ProcessManager {
90 [ResourceExposure(ResourceScope.Process)]
91 [ResourceConsumption(ResourceScope.Process)]
92 static ProcessManager() {
93 // In order to query information (OpenProcess) on some protected processes
94 // like csrss, we need SeDebugPrivilege privilege.
95 // After removing the depenecy on Performance Counter, we don't have a chance
96 // to run the code in CLR performance counter to ask for this privilege.
97 // So we will try to get the privilege here.
98 // We could fail if the user account doesn't have right to do this, but that's fair.
100 NativeMethods.LUID luid = new NativeMethods.LUID();
101 if (!NativeMethods.LookupPrivilegeValue(null, "SeDebugPrivilege", out luid)) {
102 return;
105 IntPtr tokenHandle = IntPtr.Zero;
106 try {
107 if( !NativeMethods.OpenProcessToken(
108 new HandleRef(null, NativeMethods.GetCurrentProcess()),
109 (int)TokenAccessLevels.AdjustPrivileges,
110 out tokenHandle)) {
111 return;
114 NativeMethods.TokenPrivileges tp = new NativeMethods.TokenPrivileges();
115 tp.PrivilegeCount = 1;
116 tp.Luid = luid;
117 tp.Attributes = NativeMethods.SE_PRIVILEGE_ENABLED;
119 // AdjustTokenPrivileges can return true even if it didn't succeed (when ERROR_NOT_ALL_ASSIGNED is returned).
120 NativeMethods.AdjustTokenPrivileges(new HandleRef(null,tokenHandle), false, tp, 0, IntPtr.Zero, IntPtr.Zero);
122 finally {
123 if( tokenHandle != IntPtr.Zero) {
124 SafeNativeMethods.CloseHandle(tokenHandle);
131 public static bool IsNt {
132 get {
133 return Environment.OSVersion.Platform == PlatformID.Win32NT;
137 public static bool IsOSOlderThanXP {
138 get {
139 return Environment.OSVersion.Version.Major < 5 ||
140 (Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor == 0);
144 public static ProcessInfo[] GetProcessInfos(string machineName) {
145 bool isRemoteMachine = IsRemoteMachine(machineName);
146 if (IsNt) {
147 // Do not use performance counter for local machine with Win2000 and above
148 if( !isRemoteMachine &&
149 (Environment.OSVersion.Version.Major >= 5 )) {
150 return NtProcessInfoHelper.GetProcessInfos();
152 return NtProcessManager.GetProcessInfos(machineName, isRemoteMachine);
155 else {
156 if (isRemoteMachine)
157 throw new PlatformNotSupportedException(SR.GetString(SR.WinNTRequiredForRemote));
158 return WinProcessManager.GetProcessInfos();
162 [ResourceExposure(ResourceScope.Machine)]
163 [ResourceConsumption(ResourceScope.Machine)]
164 public static int[] GetProcessIds() {
165 if (IsNt)
166 return NtProcessManager.GetProcessIds();
167 else {
168 return WinProcessManager.GetProcessIds();
172 [ResourceExposure(ResourceScope.Machine)]
173 [ResourceConsumption(ResourceScope.Machine)]
174 public static int[] GetProcessIds(string machineName) {
175 if (IsRemoteMachine(machineName)) {
176 if (IsNt) {
177 return NtProcessManager.GetProcessIds(machineName, true);
179 else {
180 throw new PlatformNotSupportedException(SR.GetString(SR.WinNTRequiredForRemote));
183 else {
184 return GetProcessIds();
188 [ResourceExposure(ResourceScope.None)]
189 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
190 public static bool IsProcessRunning(int processId, string machineName) {
191 return IsProcessRunning(processId, GetProcessIds(machineName));
194 [ResourceExposure(ResourceScope.None)]
195 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
196 public static bool IsProcessRunning(int processId) {
197 return IsProcessRunning(processId, GetProcessIds());
200 static bool IsProcessRunning(int processId, int[] processIds) {
201 for (int i = 0; i < processIds.Length; i++)
202 if (processIds[i] == processId)
203 return true;
204 return false;
207 [ResourceExposure(ResourceScope.Machine)]
208 [ResourceConsumption(ResourceScope.Machine)]
209 public static int GetProcessIdFromHandle(SafeProcessHandle processHandle) {
210 if (IsNt)
211 return NtProcessManager.GetProcessIdFromHandle(processHandle);
212 else
213 throw new PlatformNotSupportedException(SR.GetString(SR.WinNTRequired));
216 [ResourceExposure(ResourceScope.Machine)]
217 [ResourceConsumption(ResourceScope.Machine)]
218 public static IntPtr GetMainWindowHandle(int processId) {
219 MainWindowFinder finder = new MainWindowFinder();
220 return finder.FindMainWindow(processId);
223 [ResourceExposure(ResourceScope.Process)]
224 [ResourceConsumption(ResourceScope.Process)]
225 public static ModuleInfo[] GetModuleInfos(int processId) {
226 if (IsNt)
227 return NtProcessManager.GetModuleInfos(processId);
228 else
229 return WinProcessManager.GetModuleInfos(processId);
232 [ResourceExposure(ResourceScope.Machine)]
233 [ResourceConsumption(ResourceScope.Machine)]
234 public static SafeProcessHandle OpenProcess(int processId, int access, bool throwIfExited) {
235 SafeProcessHandle processHandle = NativeMethods.OpenProcess(access, false, processId);
236 int result = Marshal.GetLastWin32Error();
237 if (!processHandle.IsInvalid) {
238 return processHandle;
241 if (processId == 0) {
242 throw new Win32Exception(5);
245 // If the handle is invalid because the process has exited, only throw an exception if throwIfExited is true.
246 if (!IsProcessRunning(processId)) {
247 if (throwIfExited) {
248 throw new InvalidOperationException(SR.GetString(SR.ProcessHasExited, processId.ToString(CultureInfo.CurrentCulture)));
250 else {
251 return SafeProcessHandle.InvalidHandle;
254 throw new Win32Exception(result);
257 [ResourceExposure(ResourceScope.Process)]
258 [ResourceConsumption(ResourceScope.Process)]
259 public static SafeThreadHandle OpenThread(int threadId, int access) {
260 try {
261 SafeThreadHandle threadHandle = NativeMethods.OpenThread(access, false, threadId);
262 int result = Marshal.GetLastWin32Error();
263 if (threadHandle.IsInvalid) {
264 if (result == NativeMethods.ERROR_INVALID_PARAMETER)
265 throw new InvalidOperationException(SR.GetString(SR.ThreadExited, threadId.ToString(CultureInfo.CurrentCulture)));
266 throw new Win32Exception(result);
268 return threadHandle;
270 catch (EntryPointNotFoundException x) {
271 throw new PlatformNotSupportedException(SR.GetString(SR.Win2000Required), x);
277 public static bool IsRemoteMachine(string machineName) {
278 if (machineName == null)
279 throw new ArgumentNullException("machineName");
281 if (machineName.Length == 0)
282 throw new ArgumentException(SR.GetString(SR.InvalidParameter, "machineName", machineName));
284 string baseName;
286 if (machineName.StartsWith("\\", StringComparison.Ordinal))
287 baseName = machineName.Substring(2);
288 else
289 baseName = machineName;
290 if (baseName.Equals(".")) return false;
292 StringBuilder sb = new StringBuilder(256);
293 SafeNativeMethods.GetComputerName(sb, new int[] {sb.Capacity});
294 string computerName = sb.ToString();
295 if (String.Compare(computerName, baseName, StringComparison.OrdinalIgnoreCase) == 0) return false;
296 return true;
300 /// <devdoc>
301 /// This static class provides the process api for the Win9x platform.
302 /// We use the toolhelp32 api to query process, thread and module information.
303 /// </devdoc>
304 /// <internalonly/>
305 internal static class WinProcessManager {
307 // This is expensive. We should specialize getprocessinfos and only get
308 // the ids instead of getting all the info and then copying the ids out.
309 public static int[] GetProcessIds() {
310 ProcessInfo[] infos = GetProcessInfos();
311 int[] ids = new int[infos.Length];
312 for (int i = 0; i < infos.Length; i++) {
313 ids[i] = infos[i].processId;
315 return ids;
318 [ResourceExposure(ResourceScope.None)]
319 [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
320 public static ProcessInfo[] GetProcessInfos() {
321 IntPtr handle = (IntPtr)(-1);
322 GCHandle bufferHandle = new GCHandle();
323 ArrayList threadInfos = new ArrayList();
324 Hashtable processInfos = new Hashtable();
326 try {
327 handle = NativeMethods.CreateToolhelp32Snapshot(NativeMethods.TH32CS_SNAPPROCESS | NativeMethods.TH32CS_SNAPTHREAD, 0);
328 if (handle == (IntPtr)(-1)) throw new Win32Exception();
329 int entrySize = (int)Marshal.SizeOf(typeof(NativeMethods.WinProcessEntry));
330 int bufferSize = entrySize + NativeMethods.WinProcessEntry.sizeofFileName;
331 int[] buffer = new int[bufferSize / 4];
332 bufferHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
333 IntPtr bufferPtr = bufferHandle.AddrOfPinnedObject();
334 Marshal.WriteInt32(bufferPtr, bufferSize);
336 HandleRef handleRef = new HandleRef(null, handle);
338 if (NativeMethods.Process32First(handleRef, bufferPtr)) {
339 do {
340 NativeMethods.WinProcessEntry process = new NativeMethods.WinProcessEntry();
341 Marshal.PtrToStructure(bufferPtr, process);
342 ProcessInfo processInfo = new ProcessInfo();
343 String name = Marshal.PtrToStringAnsi((IntPtr)((long)bufferPtr + entrySize));
344 processInfo.processName = Path.ChangeExtension(Path.GetFileName(name), null);
345 processInfo.handleCount = process.cntUsage;
346 processInfo.processId = process.th32ProcessID;
347 processInfo.basePriority = process.pcPriClassBase;
348 processInfo.mainModuleId = process.th32ModuleID;
349 processInfos.Add(processInfo.processId, processInfo);
350 Marshal.WriteInt32(bufferPtr, bufferSize);
352 while (NativeMethods.Process32Next(handleRef, bufferPtr));
355 NativeMethods.WinThreadEntry thread = new NativeMethods.WinThreadEntry();
356 thread.dwSize = Marshal.SizeOf(thread);
357 if (NativeMethods.Thread32First(handleRef, thread)) {
358 do {
359 ThreadInfo threadInfo = new ThreadInfo();
360 threadInfo.threadId = thread.th32ThreadID;
361 threadInfo.processId = thread.th32OwnerProcessID;
362 threadInfo.basePriority = thread.tpBasePri;
363 threadInfo.currentPriority = thread.tpBasePri + thread.tpDeltaPri;
364 threadInfos.Add(threadInfo);
366 while (NativeMethods.Thread32Next(handleRef, thread));
369 for (int i = 0; i < threadInfos.Count; i++) {
370 ThreadInfo threadInfo = (ThreadInfo)threadInfos[i];
371 ProcessInfo processInfo = (ProcessInfo)processInfos[threadInfo.processId];
372 if (processInfo != null)
373 processInfo.threadInfoList.Add(threadInfo);
374 //else
375 // throw new InvalidOperationException(SR.GetString(SR.ProcessNotFound, threadInfo.threadId.ToString(), threadInfo.processId.ToString()));
378 finally {
379 if (bufferHandle.IsAllocated) bufferHandle.Free();
380 Debug.WriteLineIf(Process.processTracing.TraceVerbose, "Process - CloseHandle(toolhelp32 snapshot handle)");
381 if (handle != (IntPtr)(-1)) SafeNativeMethods.CloseHandle(handle);
384 ProcessInfo[] temp = new ProcessInfo[processInfos.Values.Count];
385 processInfos.Values.CopyTo(temp, 0);
386 return temp;
389 [ResourceExposure(ResourceScope.Process)]
390 [ResourceConsumption(ResourceScope.Process)]
391 public static ModuleInfo[] GetModuleInfos(int processId) {
392 IntPtr handle = (IntPtr)(-1);
393 GCHandle bufferHandle = new GCHandle();
394 ArrayList moduleInfos = new ArrayList();
396 try {
397 handle = NativeMethods.CreateToolhelp32Snapshot(NativeMethods.TH32CS_SNAPMODULE, processId);
398 if (handle == (IntPtr)(-1)) throw new Win32Exception();
399 int entrySize = Marshal.SizeOf(typeof(NativeMethods.WinModuleEntry));
400 int bufferSize = entrySize + NativeMethods.WinModuleEntry.sizeofFileName + NativeMethods.WinModuleEntry.sizeofModuleName;
401 int[] buffer = new int[bufferSize / 4];
402 bufferHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
403 IntPtr bufferPtr = bufferHandle.AddrOfPinnedObject();
404 Marshal.WriteInt32(bufferPtr, bufferSize);
406 HandleRef handleRef = new HandleRef(null, handle);
408 if (NativeMethods.Module32First(handleRef, bufferPtr)) {
409 do {
410 NativeMethods.WinModuleEntry module = new NativeMethods.WinModuleEntry();
411 Marshal.PtrToStructure(bufferPtr, module);
412 ModuleInfo moduleInfo = new ModuleInfo();
413 moduleInfo.baseName = Marshal.PtrToStringAnsi((IntPtr)((long)bufferPtr + entrySize));
414 moduleInfo.fileName = Marshal.PtrToStringAnsi((IntPtr)((long)bufferPtr + entrySize + NativeMethods.WinModuleEntry.sizeofModuleName));
415 moduleInfo.baseOfDll = module.modBaseAddr;
416 moduleInfo.sizeOfImage = module.modBaseSize;
417 moduleInfo.Id = module.th32ModuleID;
418 moduleInfos.Add(moduleInfo);
419 Marshal.WriteInt32(bufferPtr, bufferSize);
421 while (NativeMethods.Module32Next(handleRef, bufferPtr));
424 finally {
425 if (bufferHandle.IsAllocated) bufferHandle.Free();
426 Debug.WriteLineIf(Process.processTracing.TraceVerbose, "Process - CloseHandle(toolhelp32 snapshot handle)");
427 if (handle != (IntPtr)(-1)) SafeNativeMethods.CloseHandle(handle);
430 ModuleInfo[] temp = new ModuleInfo[moduleInfos.Count];
431 moduleInfos.CopyTo(temp, 0);
432 return temp;
438 /// <devdoc>
439 /// This static class provides the process api for the WinNt platform.
440 /// We use the performance counter api to query process and thread
441 /// information. Module information is obtained using PSAPI.
442 /// </devdoc>
443 /// <internalonly/>
444 internal static class NtProcessManager {
445 private const int ProcessPerfCounterId = 230;
446 private const int ThreadPerfCounterId = 232;
447 private const string PerfCounterQueryString = "230 232";
448 internal const int IdleProcessID = 0;
450 static Hashtable valueIds;
452 static NtProcessManager() {
453 valueIds = new Hashtable();
454 valueIds.Add("Handle Count", ValueId.HandleCount);
455 valueIds.Add("Pool Paged Bytes", ValueId.PoolPagedBytes);
456 valueIds.Add("Pool Nonpaged Bytes", ValueId.PoolNonpagedBytes);
457 valueIds.Add("Elapsed Time", ValueId.ElapsedTime);
458 valueIds.Add("Virtual Bytes Peak", ValueId.VirtualBytesPeak);
459 valueIds.Add("Virtual Bytes", ValueId.VirtualBytes);
460 valueIds.Add("Private Bytes", ValueId.PrivateBytes);
461 valueIds.Add("Page File Bytes", ValueId.PageFileBytes);
462 valueIds.Add("Page File Bytes Peak", ValueId.PageFileBytesPeak);
463 valueIds.Add("Working Set Peak", ValueId.WorkingSetPeak);
464 valueIds.Add("Working Set", ValueId.WorkingSet);
465 valueIds.Add("ID Thread", ValueId.ThreadId);
466 valueIds.Add("ID Process", ValueId.ProcessId);
467 valueIds.Add("Priority Base", ValueId.BasePriority);
468 valueIds.Add("Priority Current", ValueId.CurrentPriority);
469 valueIds.Add("% User Time", ValueId.UserTime);
470 valueIds.Add("% Privileged Time", ValueId.PrivilegedTime);
471 valueIds.Add("Start Address", ValueId.StartAddress);
472 valueIds.Add("Thread State", ValueId.ThreadState);
473 valueIds.Add("Thread Wait Reason", ValueId.ThreadWaitReason);
476 internal static int SystemProcessID {
477 get {
478 const int systemProcessIDOnXP = 4;
479 const int systemProcessIDOn2K = 8;
481 if( ProcessManager.IsOSOlderThanXP) {
482 return systemProcessIDOn2K;
484 else {
485 return systemProcessIDOnXP;
490 [ResourceExposure(ResourceScope.Machine)]
491 [ResourceConsumption(ResourceScope.Machine)]
492 public static int[] GetProcessIds(string machineName, bool isRemoteMachine) {
493 ProcessInfo[] infos = GetProcessInfos(machineName, isRemoteMachine);
494 int[] ids = new int[infos.Length];
495 for (int i = 0; i < infos.Length; i++)
496 ids[i] = infos[i].processId;
497 return ids;
500 [ResourceExposure(ResourceScope.Machine)]
501 [ResourceConsumption(ResourceScope.Machine)]
502 public static int[] GetProcessIds() {
503 int[] processIds = new int[256];
504 int size;
505 for (;;) {
506 if (!NativeMethods.EnumProcesses(processIds, processIds.Length * 4, out size))
507 throw new Win32Exception();
508 if (size == processIds.Length * 4) {
509 processIds = new int[processIds.Length * 2];
510 continue;
512 break;
514 int[] ids = new int[size / 4];
515 Array.Copy(processIds, ids, ids.Length);
516 return ids;
519 [ResourceExposure(ResourceScope.Process)]
520 [ResourceConsumption(ResourceScope.Process)]
521 public static ModuleInfo[] GetModuleInfos(int processId) {
522 return GetModuleInfos(processId, false);
525 [ResourceExposure(ResourceScope.Process)]
526 [ResourceConsumption(ResourceScope.Process)]
527 public static ModuleInfo GetFirstModuleInfo(int processId) {
528 ModuleInfo[] moduleInfos = GetModuleInfos(processId, true);
529 if( moduleInfos.Length == 0) {
530 return null;
532 else {
533 return moduleInfos[0];
537 [ResourceExposure(ResourceScope.None)]
538 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
539 private static ModuleInfo[] GetModuleInfos(int processId, bool firstModuleOnly) {
540 Contract.Ensures(Contract.Result<ModuleInfo[]>().Length >= 1);
542 // preserving Everett behavior.
543 if( processId == SystemProcessID || processId == IdleProcessID) {
544 // system process and idle process doesn't have any modules
545 throw new Win32Exception(HResults.EFail,SR.GetString(SR.EnumProcessModuleFailed));
548 SafeProcessHandle processHandle = SafeProcessHandle.InvalidHandle;
549 try {
550 processHandle = ProcessManager.OpenProcess(processId, NativeMethods.PROCESS_QUERY_INFORMATION | NativeMethods.PROCESS_VM_READ, true);
552 IntPtr[] moduleHandles = new IntPtr[64];
553 GCHandle moduleHandlesArrayHandle = new GCHandle();
554 int moduleCount = 0;
555 for (;;) {
556 bool enumResult = false;
557 try {
558 moduleHandlesArrayHandle = GCHandle.Alloc(moduleHandles, GCHandleType.Pinned);
559 enumResult = NativeMethods.EnumProcessModules(processHandle, moduleHandlesArrayHandle.AddrOfPinnedObject(), moduleHandles.Length * IntPtr.Size, ref moduleCount);
561 // The API we need to use to enumerate process modules differs on two factors:
562 // 1) If our process is running in WOW64.
563 // 2) The bitness of the process we wish to introspect.
565 // If we are not running in WOW64 or we ARE in WOW64 but want to inspect a 32 bit process
566 // we can call psapi!EnumProcessModules.
568 // If we are running in WOW64 and we want to inspect the modules of a 64 bit process then
569 // psapi!EnumProcessModules will return false with ERROR_PARTIAL_COPY (299). In this case we can't
570 // do the enumeration at all. So we'll detect this case and bail out.
572 // Also, EnumProcessModules is not a reliable method to get the modules for a process.
573 // If OS loader is touching module information, this method might fail and copy part of the data.
574 // This is no easy solution to this problem. The only reliable way to fix this is to
575 // suspend all the threads in target process. Of course we don't want to do this in Process class.
576 // So we just to try avoid the ---- by calling the same method 50 (an arbitary number) times.
578 if (!enumResult) {
579 bool sourceProcessIsWow64 = false;
580 bool targetProcessIsWow64 = false;
581 if (!ProcessManager.IsOSOlderThanXP) {
582 SafeProcessHandle hCurProcess = SafeProcessHandle.InvalidHandle;
583 try {
584 hCurProcess = ProcessManager.OpenProcess(NativeMethods.GetCurrentProcessId(), NativeMethods.PROCESS_QUERY_INFORMATION, true);
585 bool wow64Ret;
587 wow64Ret = SafeNativeMethods.IsWow64Process(hCurProcess, ref sourceProcessIsWow64);
588 if (!wow64Ret) {
589 throw new Win32Exception();
592 wow64Ret = SafeNativeMethods.IsWow64Process(processHandle, ref targetProcessIsWow64);
593 if (!wow64Ret) {
594 throw new Win32Exception();
597 if (sourceProcessIsWow64 && !targetProcessIsWow64) {
598 // Wow64 isn't going to allow this to happen, the best we can do is give a descriptive error to the user.
599 throw new Win32Exception(NativeMethods.ERROR_PARTIAL_COPY, SR.GetString(SR.EnumProcessModuleFailedDueToWow));
602 } finally {
603 if (hCurProcess != SafeProcessHandle.InvalidHandle) {
604 hCurProcess.Close();
609 // If the failure wasn't due to Wow64, try again.
610 for (int i = 0; i < 50; i++) {
611 enumResult = NativeMethods.EnumProcessModules(processHandle, moduleHandlesArrayHandle.AddrOfPinnedObject(), moduleHandles.Length * IntPtr.Size, ref moduleCount);
612 if (enumResult) {
613 break;
615 Thread.Sleep(1);
619 finally {
620 moduleHandlesArrayHandle.Free();
623 if (!enumResult) {
624 throw new Win32Exception();
627 moduleCount /= IntPtr.Size;
628 if (moduleCount <= moduleHandles.Length) break;
629 moduleHandles = new IntPtr[moduleHandles.Length * 2];
631 ArrayList moduleInfos = new ArrayList();
633 int ret;
634 for (int i = 0; i < moduleCount; i++) {
637 ModuleInfo moduleInfo = new ModuleInfo();
638 IntPtr moduleHandle = moduleHandles[i];
639 NativeMethods.NtModuleInfo ntModuleInfo = new NativeMethods.NtModuleInfo();
640 if (!NativeMethods.GetModuleInformation(processHandle, new HandleRef(null, moduleHandle), ntModuleInfo, Marshal.SizeOf(ntModuleInfo)))
641 throw new Win32Exception();
642 moduleInfo.sizeOfImage = ntModuleInfo.SizeOfImage;
643 moduleInfo.entryPoint = ntModuleInfo.EntryPoint;
644 moduleInfo.baseOfDll = ntModuleInfo.BaseOfDll;
646 StringBuilder baseName = new StringBuilder(1024);
647 ret = NativeMethods.GetModuleBaseName(processHandle, new HandleRef(null, moduleHandle), baseName, baseName.Capacity * 2);
648 if (ret == 0) throw new Win32Exception();
649 moduleInfo.baseName = baseName.ToString();
651 StringBuilder fileName = new StringBuilder(1024);
652 ret = NativeMethods.GetModuleFileNameEx(processHandle, new HandleRef(null, moduleHandle), fileName, fileName.Capacity * 2);
653 if (ret == 0) throw new Win32Exception();
654 moduleInfo.fileName = fileName.ToString();
656 // smss.exe is started before the win32 subsystem so it get this funny "\systemroot\.." path.
657 // We change this to the actual path by appending "smss.exe" to GetSystemDirectory()
658 if (string.Compare(moduleInfo.fileName, "\\SystemRoot\\System32\\smss.exe", StringComparison.OrdinalIgnoreCase) == 0) {
659 moduleInfo.fileName = Path.Combine(Environment.SystemDirectory, "smss.exe");
661 // Avoid returning Unicode-style long string paths. IO methods cannot handle them.
662 if (moduleInfo.fileName != null
663 && moduleInfo.fileName.Length >= 4
664 && moduleInfo.fileName.StartsWith(@"\\?\", StringComparison.Ordinal)) {
666 moduleInfo.fileName = moduleInfo.fileName.Substring(4);
669 moduleInfos.Add(moduleInfo);
671 catch (Win32Exception e)
673 if (e.NativeErrorCode == NativeMethods.ERROR_INVALID_HANDLE || e.NativeErrorCode == NativeMethods.ERROR_PARTIAL_COPY)
675 // It's possible that another thread casued this module to become
676 // unloaded (e.g FreeLibrary was called on the module). Ignore it and
677 // move on.
679 else
681 throw;
686 // If the user is only interested in the main module, break now.
687 // This avoid some waste of time. In addition, if the application unloads a DLL
688 // we will not get an exception.
690 if( firstModuleOnly) { break; }
692 ModuleInfo[] temp = new ModuleInfo[moduleInfos.Count];
693 moduleInfos.CopyTo(temp, 0);
694 return temp;
696 finally {
697 Debug.WriteLineIf(Process.processTracing.TraceVerbose, "Process - CloseHandle(process)");
698 if (!processHandle.IsInvalid ) {
699 processHandle.Close();
704 [ResourceExposure(ResourceScope.Machine)]
705 [ResourceConsumption(ResourceScope.Machine)]
706 public static int GetProcessIdFromHandle(SafeProcessHandle processHandle) {
707 NativeMethods.NtProcessBasicInfo info = new NativeMethods.NtProcessBasicInfo();
708 int status = NativeMethods.NtQueryInformationProcess(processHandle, NativeMethods.NtQueryProcessBasicInfo, info, (int)Marshal.SizeOf(info), null);
709 if (status != 0) {
710 throw new InvalidOperationException(SR.GetString(SR.CantGetProcessId), new Win32Exception(status));
712 // We should change the signature of this function and ID property in process class.
713 return info.UniqueProcessId.ToInt32();
716 public static ProcessInfo[] GetProcessInfos(string machineName, bool isRemoteMachine) {
717 // We demand unmanaged code here because PerformanceCounterLib doesn't demand
718 // anything. This is the only place we do GetPerformanceCounterLib, and it isn't cached.
719 new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand();
720 PerformanceCounterLib library = null;
721 try {
722 library = PerformanceCounterLib.GetPerformanceCounterLib(machineName, new CultureInfo(0x009));
723 return GetProcessInfos(library);
725 catch(Exception e) {
726 if( isRemoteMachine) {
727 throw new InvalidOperationException(SR.GetString(SR.CouldntConnectToRemoteMachine), e);
729 else {
730 throw e;
733 // We don't want to call library.Close() here because that would cause us to unload all of the perflibs.
734 // On the next call to GetProcessInfos, we'd have to load them all up again, which is SLOW!
737 static ProcessInfo[] GetProcessInfos(PerformanceCounterLib library) {
738 ProcessInfo[] processInfos = new ProcessInfo[0] ;
739 byte[] dataPtr = null;
741 int retryCount = 5;
742 while (processInfos.Length == 0 && retryCount != 0) {
743 try {
744 dataPtr = library.GetPerformanceData(PerfCounterQueryString);
745 processInfos = GetProcessInfos(library, ProcessPerfCounterId, ThreadPerfCounterId, dataPtr);
747 catch (Exception e) {
748 throw new InvalidOperationException(SR.GetString(SR.CouldntGetProcessInfos), e);
751 --retryCount;
754 if (processInfos.Length == 0)
755 throw new InvalidOperationException(SR.GetString(SR.ProcessDisabled));
757 return processInfos;
761 static ProcessInfo[] GetProcessInfos(PerformanceCounterLib library, int processIndex, int threadIndex, byte[] data) {
762 Debug.WriteLineIf(Process.processTracing.TraceVerbose, "GetProcessInfos()");
763 Hashtable processInfos = new Hashtable();
764 ArrayList threadInfos = new ArrayList();
766 GCHandle dataHandle = new GCHandle();
767 try {
768 dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
769 IntPtr dataBlockPtr = dataHandle.AddrOfPinnedObject();
770 NativeMethods.PERF_DATA_BLOCK dataBlock = new NativeMethods.PERF_DATA_BLOCK();
771 Marshal.PtrToStructure(dataBlockPtr, dataBlock);
772 IntPtr typePtr = (IntPtr)((long)dataBlockPtr + dataBlock.HeaderLength);
773 NativeMethods.PERF_INSTANCE_DEFINITION instance = new NativeMethods.PERF_INSTANCE_DEFINITION();
774 NativeMethods.PERF_COUNTER_BLOCK counterBlock = new NativeMethods.PERF_COUNTER_BLOCK();
775 for (int i = 0; i < dataBlock.NumObjectTypes; i++) {
776 NativeMethods.PERF_OBJECT_TYPE type = new NativeMethods.PERF_OBJECT_TYPE();
777 Marshal.PtrToStructure(typePtr, type);
778 IntPtr instancePtr = (IntPtr)((long)typePtr + type.DefinitionLength);
779 IntPtr counterPtr = (IntPtr)((long)typePtr + type.HeaderLength);
780 ArrayList counterList = new ArrayList();
782 for (int j = 0; j < type.NumCounters; j++) {
783 NativeMethods.PERF_COUNTER_DEFINITION counter = new NativeMethods.PERF_COUNTER_DEFINITION();
784 Marshal.PtrToStructure(counterPtr, counter);
785 string counterName = library.GetCounterName(counter.CounterNameTitleIndex);
787 if (type.ObjectNameTitleIndex == processIndex)
788 counter.CounterNameTitlePtr = (int)GetValueId(counterName);
789 else if (type.ObjectNameTitleIndex == threadIndex)
790 counter.CounterNameTitlePtr = (int)GetValueId(counterName);
791 counterList.Add(counter);
792 counterPtr = (IntPtr)((long)counterPtr + counter.ByteLength);
794 NativeMethods.PERF_COUNTER_DEFINITION[] counters = new NativeMethods.PERF_COUNTER_DEFINITION[counterList.Count];
795 counterList.CopyTo(counters, 0);
796 for (int j = 0; j < type.NumInstances; j++) {
797 Marshal.PtrToStructure(instancePtr, instance);
798 IntPtr namePtr = (IntPtr)((long)instancePtr + instance.NameOffset);
799 string instanceName = Marshal.PtrToStringUni(namePtr);
800 if (instanceName.Equals("_Total")) continue;
801 IntPtr counterBlockPtr = (IntPtr)((long)instancePtr + instance.ByteLength);
802 Marshal.PtrToStructure(counterBlockPtr, counterBlock);
803 if (type.ObjectNameTitleIndex == processIndex) {
804 ProcessInfo processInfo = GetProcessInfo(type, (IntPtr)((long)instancePtr + instance.ByteLength), counters);
805 if (processInfo.processId == 0 && string.Compare(instanceName, "Idle", StringComparison.OrdinalIgnoreCase) != 0) {
806 // Sometimes we'll get a process structure that is not completely filled in.
807 // We can catch some of these by looking for non-"idle" processes that have id 0
808 // and ignoring those.
809 Debug.WriteLineIf(Process.processTracing.TraceVerbose, "GetProcessInfos() - found a non-idle process with id 0; ignoring.");
811 else {
812 if (processInfos[processInfo.processId] != null) {
813 // We've found two entries in the perfcounters that claim to be the
814 // same process. We throw an exception. Is this really going to be
815 // helpfull to the user? Should we just ignore?
816 Debug.WriteLineIf(Process.processTracing.TraceVerbose, "GetProcessInfos() - found a duplicate process id");
818 else {
819 // the performance counters keep a 15 character prefix of the exe name, and then delete the ".exe",
820 // if it's in the first 15. The problem is that sometimes that will leave us with part of ".exe"
821 // at the end. If instanceName ends in ".", ".e", or ".ex" we remove it.
822 string processName = instanceName;
823 if (processName.Length == 15) {
824 if (instanceName.EndsWith(".", StringComparison.Ordinal )) processName = instanceName.Substring(0, 14);
825 else if (instanceName.EndsWith(".e", StringComparison.Ordinal )) processName = instanceName.Substring(0, 13);
826 else if (instanceName.EndsWith(".ex", StringComparison.Ordinal)) processName = instanceName.Substring(0, 12);
828 processInfo.processName = processName;
829 processInfos.Add(processInfo.processId, processInfo);
833 else if (type.ObjectNameTitleIndex == threadIndex) {
834 ThreadInfo threadInfo = GetThreadInfo(type, (IntPtr)((long)instancePtr + instance.ByteLength), counters);
835 if (threadInfo.threadId != 0) threadInfos.Add(threadInfo);
837 instancePtr = (IntPtr)((long)instancePtr + instance.ByteLength + counterBlock.ByteLength);
840 typePtr = (IntPtr)((long)typePtr + type.TotalByteLength);
843 finally {
844 if (dataHandle.IsAllocated) dataHandle.Free();
847 for (int i = 0; i < threadInfos.Count; i++) {
848 ThreadInfo threadInfo = (ThreadInfo)threadInfos[i];
849 ProcessInfo processInfo = (ProcessInfo)processInfos[threadInfo.processId];
850 if (processInfo != null) {
851 processInfo.threadInfoList.Add(threadInfo);
855 ProcessInfo[] temp = new ProcessInfo[processInfos.Values.Count];
856 processInfos.Values.CopyTo(temp, 0);
857 return temp;
860 static ThreadInfo GetThreadInfo(NativeMethods.PERF_OBJECT_TYPE type, IntPtr instancePtr, NativeMethods.PERF_COUNTER_DEFINITION[] counters) {
861 ThreadInfo threadInfo = new ThreadInfo();
862 for (int i = 0; i < counters.Length; i++) {
863 NativeMethods.PERF_COUNTER_DEFINITION counter = counters[i];
864 long value = ReadCounterValue(counter.CounterType, (IntPtr)((long)instancePtr + counter.CounterOffset));
865 switch ((ValueId)counter.CounterNameTitlePtr) {
866 case ValueId.ProcessId:
867 threadInfo.processId = (int)value;
868 break;
869 case ValueId.ThreadId:
870 threadInfo.threadId = (int)value;
871 break;
872 case ValueId.BasePriority:
873 threadInfo.basePriority = (int)value;
874 break;
875 case ValueId.CurrentPriority:
876 threadInfo.currentPriority = (int)value;
877 break;
878 case ValueId.StartAddress:
879 threadInfo.startAddress = (IntPtr)value;
880 break;
881 case ValueId.ThreadState:
882 threadInfo.threadState = (ThreadState)value;
883 break;
884 case ValueId.ThreadWaitReason:
885 threadInfo.threadWaitReason = GetThreadWaitReason((int)value);
886 break;
890 return threadInfo;
893 internal static ThreadWaitReason GetThreadWaitReason(int value) {
894 switch (value) {
895 case 0:
896 case 7: return ThreadWaitReason.Executive;
897 case 1:
898 case 8: return ThreadWaitReason.FreePage;
899 case 2:
900 case 9: return ThreadWaitReason.PageIn;
901 case 3:
902 case 10: return ThreadWaitReason.SystemAllocation;
903 case 4:
904 case 11: return ThreadWaitReason.ExecutionDelay;
905 case 5:
906 case 12: return ThreadWaitReason.Suspended;
907 case 6:
908 case 13: return ThreadWaitReason.UserRequest;
909 case 14: return ThreadWaitReason.EventPairHigh;;
910 case 15: return ThreadWaitReason.EventPairLow;
911 case 16: return ThreadWaitReason.LpcReceive;
912 case 17: return ThreadWaitReason.LpcReply;
913 case 18: return ThreadWaitReason.VirtualMemory;
914 case 19: return ThreadWaitReason.PageOut;
915 default: return ThreadWaitReason.Unknown;
919 static ProcessInfo GetProcessInfo(NativeMethods.PERF_OBJECT_TYPE type, IntPtr instancePtr, NativeMethods.PERF_COUNTER_DEFINITION[] counters) {
920 ProcessInfo processInfo = new ProcessInfo();
921 for (int i = 0; i < counters.Length; i++) {
922 NativeMethods.PERF_COUNTER_DEFINITION counter = counters[i];
923 long value = ReadCounterValue(counter.CounterType, (IntPtr)((long)instancePtr + counter.CounterOffset));
924 switch ((ValueId)counter.CounterNameTitlePtr) {
925 case ValueId.ProcessId:
926 processInfo.processId = (int)value;
927 break;
928 case ValueId.HandleCount:
929 processInfo.handleCount = (int)value;
930 break;
931 case ValueId.PoolPagedBytes:
932 processInfo.poolPagedBytes = value;
933 break;
934 case ValueId.PoolNonpagedBytes:
935 processInfo.poolNonpagedBytes = value;
936 break;
937 case ValueId.VirtualBytes:
938 processInfo.virtualBytes = value;
939 break;
940 case ValueId.VirtualBytesPeak:
941 processInfo.virtualBytesPeak = value;
942 break;
943 case ValueId.WorkingSetPeak:
944 processInfo.workingSetPeak = value;
945 break;
946 case ValueId.WorkingSet:
947 processInfo.workingSet = value;
948 break;
949 case ValueId.PageFileBytesPeak:
950 processInfo.pageFileBytesPeak = value;
951 break;
952 case ValueId.PageFileBytes:
953 processInfo.pageFileBytes = value;
954 break;
955 case ValueId.PrivateBytes:
956 processInfo.privateBytes = value;
957 break;
958 case ValueId.BasePriority:
959 processInfo.basePriority = (int)value;
960 break;
963 return processInfo;
966 static ValueId GetValueId(string counterName) {
967 if (counterName != null) {
968 object id = valueIds[counterName];
969 if (id != null)
970 return(ValueId)id;
972 return ValueId.Unknown;
975 static long ReadCounterValue(int counterType, IntPtr dataPtr) {
976 if ((counterType & NativeMethods.NtPerfCounterSizeLarge) != 0)
977 return Marshal.ReadInt64(dataPtr);
978 else
979 return(long)Marshal.ReadInt32(dataPtr);
982 enum ValueId {
983 Unknown = -1,
984 HandleCount,
985 PoolPagedBytes,
986 PoolNonpagedBytes,
987 ElapsedTime,
988 VirtualBytesPeak,
989 VirtualBytes,
990 PrivateBytes,
991 PageFileBytes,
992 PageFileBytesPeak,
993 WorkingSetPeak,
994 WorkingSet,
995 ThreadId,
996 ProcessId,
997 BasePriority,
998 CurrentPriority,
999 UserTime,
1000 PrivilegedTime,
1001 StartAddress,
1002 ThreadState,
1003 ThreadWaitReason
1007 internal static class NtProcessInfoHelper {
1008 private static int GetNewBufferSize(int existingBufferSize, int requiredSize) {
1009 if( requiredSize == 0) {
1011 // On some old OS like win2000, requiredSize will not be set if the buffer
1012 // passed to NtQuerySystemInformation is not enough.
1014 int newSize = existingBufferSize * 2;
1015 if ( newSize < existingBufferSize ) {
1016 // In reality, we should never overflow.
1017 // Adding the code here just in case it happens.
1018 throw new OutOfMemoryException();
1020 return newSize;
1022 else {
1023 // allocating a few more kilo bytes just in case there are some new process
1024 // kicked in since new call to NtQuerySystemInformation
1025 int newSize = requiredSize + 1024 * 10;
1026 if ( newSize < requiredSize ) {
1027 throw new OutOfMemoryException();
1029 return newSize;
1033 #pragma warning disable 169
1034 public static ProcessInfo[] GetProcessInfos() {
1036 int requiredSize = 0;
1037 int status;
1039 ProcessInfo[] processInfos;
1040 GCHandle bufferHandle = new GCHandle();
1042 // Start with the default buffer size.
1043 int bufferSize = DefaultCachedBufferSize;
1045 // Get the cached buffer.
1046 long[] buffer = Interlocked.Exchange(ref CachedBuffer, null);
1048 try {
1049 // Retry until we get all the data
1050 do {
1051 if (buffer == null)
1053 // Allocate buffer of longs since some platforms require the buffer to be 64-bit aligned.
1054 buffer = new long[(bufferSize + 7) / 8];
1056 else
1058 // If we have cached buffer, set the size properly.
1059 bufferSize = buffer.Length * sizeof(long);
1061 bufferHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
1063 status = NativeMethods.NtQuerySystemInformation(
1064 NativeMethods.NtQuerySystemProcessInformation,
1065 bufferHandle.AddrOfPinnedObject(),
1066 bufferSize,
1067 out requiredSize);
1069 if ((uint)status == NativeMethods.STATUS_INFO_LENGTH_MISMATCH)
1071 if (bufferHandle.IsAllocated) bufferHandle.Free();
1072 buffer = null;
1073 bufferSize = GetNewBufferSize(bufferSize, requiredSize);
1075 } while ((uint)status == NativeMethods.STATUS_INFO_LENGTH_MISMATCH);
1077 if (status < 0) { // see definition of NT_SUCCESS(Status) in SDK
1078 throw new InvalidOperationException(SR.GetString(SR.CouldntGetProcessInfos), new Win32Exception(status));
1081 // Parse the data block to get process information
1082 processInfos = GetProcessInfos(bufferHandle.AddrOfPinnedObject());
1084 finally {
1085 // Cache the final buffer for use on the next call.
1086 Interlocked.Exchange(ref CachedBuffer, buffer);
1088 if (bufferHandle.IsAllocated) bufferHandle.Free();
1091 return processInfos;
1094 // Use a smaller buffer size on debug to ensure we hit the retry path.
1095 #if DEBUG
1096 private const int DefaultCachedBufferSize = 1024;
1097 #else
1098 private const int DefaultCachedBufferSize = 128 * 1024;
1099 #endif
1101 // Cache a single buffer for use in GetProcessInfos().
1102 private static long[] CachedBuffer;
1104 static ProcessInfo[] GetProcessInfos(IntPtr dataPtr) {
1105 // 60 is a reasonable number for processes on a normal machine.
1106 Hashtable processInfos = new Hashtable(60);
1108 long totalOffset = 0;
1110 while(true) {
1111 IntPtr currentPtr = (IntPtr)((long)dataPtr + totalOffset);
1112 SystemProcessInformation pi = new SystemProcessInformation();
1114 Marshal.PtrToStructure(currentPtr, pi);
1116 // get information for a process
1117 ProcessInfo processInfo = new ProcessInfo();
1118 // Process ID shouldn't overflow. OS API GetCurrentProcessID returns DWORD.
1119 processInfo.processId = pi.UniqueProcessId.ToInt32();
1120 processInfo.handleCount = (int)pi.HandleCount;
1121 processInfo.sessionId = (int)pi.SessionId;
1122 processInfo.poolPagedBytes = (long)pi.QuotaPagedPoolUsage;;
1123 processInfo.poolNonpagedBytes = (long)pi.QuotaNonPagedPoolUsage;
1124 processInfo.virtualBytes = (long)pi.VirtualSize;
1125 processInfo.virtualBytesPeak = (long)pi.PeakVirtualSize;
1126 processInfo.workingSetPeak = (long)pi.PeakWorkingSetSize;
1127 processInfo.workingSet = (long)pi.WorkingSetSize;
1128 processInfo.pageFileBytesPeak = (long)pi.PeakPagefileUsage;
1129 processInfo.pageFileBytes = (long)pi.PagefileUsage;
1130 processInfo.privateBytes = (long)pi.PrivatePageCount;
1131 processInfo.basePriority = pi.BasePriority;
1134 if( pi.NamePtr == IntPtr.Zero) {
1135 if( processInfo.processId == NtProcessManager.SystemProcessID) {
1136 processInfo.processName = "System";
1138 else if( processInfo.processId == NtProcessManager.IdleProcessID) {
1139 processInfo.processName = "Idle";
1141 else {
1142 // for normal process without name, using the process ID.
1143 processInfo.processName = processInfo.processId.ToString(CultureInfo.InvariantCulture);
1146 else {
1147 string processName = GetProcessShortName(Marshal.PtrToStringUni(pi.NamePtr, pi.NameLength/sizeof(char)));
1149 // On old operating system (NT4 and windows 2000), the process name might be truncated to 15
1150 // characters. For example, aspnet_admin.exe will show up in performance counter as aspnet_admin.ex.
1151 // Process class try to return a nicer name. We used to get the main module name for a process and
1152 // use that as the process name. However normal user doesn't have access to module information,
1153 // so normal user will see an exception when we try to get a truncated process name.
1155 if (ProcessManager.IsOSOlderThanXP && (processName.Length == 15)) {
1156 if (processName.EndsWith(".", StringComparison.OrdinalIgnoreCase)) {
1157 processName = processName.Substring(0, 14);
1159 else if (processName.EndsWith(".e", StringComparison.OrdinalIgnoreCase)) {
1160 processName = processName.Substring(0, 13);
1162 else if (processName.EndsWith(".ex", StringComparison.OrdinalIgnoreCase)) {
1163 processName = processName.Substring(0, 12);
1166 processInfo.processName = processName;
1169 // get the threads for current process
1170 processInfos[processInfo.processId] = processInfo;
1172 currentPtr = (IntPtr)((long)currentPtr + Marshal.SizeOf(pi));
1173 int i = 0;
1174 while( i < pi.NumberOfThreads) {
1175 SystemThreadInformation ti = new SystemThreadInformation();
1176 Marshal.PtrToStructure(currentPtr, ti);
1177 ThreadInfo threadInfo = new ThreadInfo();
1179 threadInfo.processId = (int)ti.UniqueProcess;
1180 threadInfo.threadId = (int)ti.UniqueThread;
1181 threadInfo.basePriority = ti.BasePriority;
1182 threadInfo.currentPriority = ti.Priority;
1183 threadInfo.startAddress = ti.StartAddress;
1184 threadInfo.threadState = (ThreadState)ti.ThreadState;
1185 threadInfo.threadWaitReason = NtProcessManager.GetThreadWaitReason((int)ti.WaitReason);
1187 processInfo.threadInfoList.Add(threadInfo);
1188 currentPtr = (IntPtr)((long)currentPtr + Marshal.SizeOf(ti));
1189 i++;
1192 if (pi.NextEntryOffset == 0) {
1193 break;
1195 totalOffset += pi.NextEntryOffset;
1198 ProcessInfo[] temp = new ProcessInfo[processInfos.Values.Count];
1199 processInfos.Values.CopyTo(temp, 0);
1200 return temp;
1203 // This function generates the short form of process name.
1205 // This is from GetProcessShortName in NT code base.
1206 // Check base\screg\winreg\perfdlls\process\perfsprc.c for details.
1207 internal static string GetProcessShortName(String name) {
1208 if (String.IsNullOrEmpty(name)) {
1209 Debug.WriteLineIf(Process.processTracing.TraceVerbose, "GetProcessInfos() - unexpected blank ProcessName");
1210 return String.Empty;
1213 int slash = -1;
1214 int period = -1;
1216 for (int i = 0; i < name.Length; i++) {
1217 if (name[i] == '\\')
1218 slash = i;
1219 else if (name[i] == '.')
1220 period = i;
1223 if (period == -1)
1224 period = name.Length - 1; // set to end of string
1225 else {
1226 // if a period was found, then see if the extension is
1227 // .EXE, if so drop it, if not, then use end of string
1228 // (i.e. include extension in name)
1229 String extension = name.Substring(period);
1231 if(String.Equals(".exe", extension, StringComparison.OrdinalIgnoreCase) )
1232 period--; // point to character before period
1233 else
1234 period = name.Length - 1; // set to end of string
1237 if (slash == -1)
1238 slash = 0; // set to start of string
1239 else
1240 slash++; // point to character next to slash
1242 // copy characters between period (or end of string) and
1243 // slash (or start of string) to make image name
1244 return name.Substring(slash, period - slash + 1);
1247 // native struct defined in ntexapi.h
1248 [StructLayout(LayoutKind.Sequential)]
1249 internal class SystemProcessInformation {
1250 internal uint NextEntryOffset;
1251 internal uint NumberOfThreads;
1252 long SpareLi1;
1253 long SpareLi2;
1254 long SpareLi3;
1255 long CreateTime;
1256 long UserTime;
1257 long KernelTime;
1259 internal ushort NameLength; // UNICODE_STRING
1260 internal ushort MaximumNameLength;
1261 internal IntPtr NamePtr; // This will point into the data block returned by NtQuerySystemInformation
1263 internal int BasePriority;
1264 internal IntPtr UniqueProcessId;
1265 internal IntPtr InheritedFromUniqueProcessId;
1266 internal uint HandleCount;
1267 internal uint SessionId;
1268 internal UIntPtr PageDirectoryBase;
1269 internal UIntPtr PeakVirtualSize; // SIZE_T
1270 internal UIntPtr VirtualSize;
1271 internal uint PageFaultCount;
1273 internal UIntPtr PeakWorkingSetSize;
1274 internal UIntPtr WorkingSetSize;
1275 internal UIntPtr QuotaPeakPagedPoolUsage;
1276 internal UIntPtr QuotaPagedPoolUsage;
1277 internal UIntPtr QuotaPeakNonPagedPoolUsage;
1278 internal UIntPtr QuotaNonPagedPoolUsage;
1279 internal UIntPtr PagefileUsage;
1280 internal UIntPtr PeakPagefileUsage;
1281 internal UIntPtr PrivatePageCount;
1283 long ReadOperationCount;
1284 long WriteOperationCount;
1285 long OtherOperationCount;
1286 long ReadTransferCount;
1287 long WriteTransferCount;
1288 long OtherTransferCount;
1291 [StructLayout(LayoutKind.Sequential)]
1292 internal class SystemThreadInformation {
1293 long KernelTime;
1294 long UserTime;
1295 long CreateTime;
1297 uint WaitTime;
1298 internal IntPtr StartAddress;
1299 internal IntPtr UniqueProcess;
1300 internal IntPtr UniqueThread;
1301 internal int Priority;
1302 internal int BasePriority;
1303 internal uint ContextSwitches;
1304 internal uint ThreadState;
1305 internal uint WaitReason;
1307 #pragma warning restore 169
1310 #endif // !FEATURE_PAL