2 namespace System
.Diagnostics
{
4 using System
.Threading
;
5 using System
.Runtime
.InteropServices
;
6 using System
.ComponentModel
;
7 using System
.ComponentModel
.Design
;
8 using System
.Diagnostics
;
10 using System
.Collections
;
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
;
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
28 internal class MainWindowFinder
{
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
);
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
)))
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)
59 if (builder.ToString() == string.Empty)
66 [ResourceExposure(ResourceScope
.Machine
)]
67 [ResourceConsumption(ResourceScope
.Machine
)]
68 bool EnumWindowsCallback(IntPtr handle
, IntPtr extraParameter
) {
70 NativeMethods
.GetWindowThreadProcessId(new HandleRef(this, handle
), out processId
);
71 if (processId
== this.processId
) {
72 if (IsMainWindow(handle
)) {
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
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
)) {
105 IntPtr tokenHandle
= IntPtr
.Zero
;
107 if( !NativeMethods
.OpenProcessToken(
108 new HandleRef(null, NativeMethods
.GetCurrentProcess()),
109 (int)TokenAccessLevels
.AdjustPrivileges
,
114 NativeMethods
.TokenPrivileges tp
= new NativeMethods
.TokenPrivileges();
115 tp
.PrivilegeCount
= 1;
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
);
123 if( tokenHandle
!= IntPtr
.Zero
) {
124 SafeNativeMethods
.CloseHandle(tokenHandle
);
131 public static bool IsNt
{
133 return Environment
.OSVersion
.Platform
== PlatformID
.Win32NT
;
137 public static bool IsOSOlderThanXP
{
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
);
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
);
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() {
166 return NtProcessManager
.GetProcessIds();
168 return WinProcessManager
.GetProcessIds();
172 [ResourceExposure(ResourceScope
.Machine
)]
173 [ResourceConsumption(ResourceScope
.Machine
)]
174 public static int[] GetProcessIds(string machineName
) {
175 if (IsRemoteMachine(machineName
)) {
177 return NtProcessManager
.GetProcessIds(machineName
, true);
180 throw new PlatformNotSupportedException(SR
.GetString(SR
.WinNTRequiredForRemote
));
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
)
207 [ResourceExposure(ResourceScope
.Machine
)]
208 [ResourceConsumption(ResourceScope
.Machine
)]
209 public static int GetProcessIdFromHandle(SafeProcessHandle processHandle
) {
211 return NtProcessManager
.GetProcessIdFromHandle(processHandle
);
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
) {
227 return NtProcessManager
.GetModuleInfos(processId
);
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
)) {
248 throw new InvalidOperationException(SR
.GetString(SR
.ProcessHasExited
, processId
.ToString(CultureInfo
.CurrentCulture
)));
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
) {
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
);
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
));
286 if (machineName
.StartsWith("\\", StringComparison
.Ordinal
))
287 baseName
= machineName
.Substring(2);
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;
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.
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
;
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();
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
)) {
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
)) {
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
);
375 // throw new InvalidOperationException(SR.GetString(SR.ProcessNotFound, threadInfo.threadId.ToString(), threadInfo.processId.ToString()));
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);
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();
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
)) {
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
));
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);
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.
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
{
478 const int systemProcessIDOnXP
= 4;
479 const int systemProcessIDOn2K
= 8;
481 if( ProcessManager
.IsOSOlderThanXP
) {
482 return systemProcessIDOn2K
;
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
;
500 [ResourceExposure(ResourceScope
.Machine
)]
501 [ResourceConsumption(ResourceScope
.Machine
)]
502 public static int[] GetProcessIds() {
503 int[] processIds
= new int[256];
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];
514 int[] ids
= new int[size
/ 4];
515 Array
.Copy(processIds
, ids
, ids
.Length
);
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) {
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
;
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();
556 bool enumResult
= false;
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.
579 bool sourceProcessIsWow64
= false;
580 bool targetProcessIsWow64
= false;
581 if (!ProcessManager
.IsOSOlderThanXP
) {
582 SafeProcessHandle hCurProcess
= SafeProcessHandle
.InvalidHandle
;
584 hCurProcess
= ProcessManager
.OpenProcess(NativeMethods
.GetCurrentProcessId(), NativeMethods
.PROCESS_QUERY_INFORMATION
, true);
587 wow64Ret
= SafeNativeMethods
.IsWow64Process(hCurProcess
, ref sourceProcessIsWow64
);
589 throw new Win32Exception();
592 wow64Ret
= SafeNativeMethods
.IsWow64Process(processHandle
, ref targetProcessIsWow64
);
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
));
603 if (hCurProcess
!= SafeProcessHandle
.InvalidHandle
) {
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
);
620 moduleHandlesArrayHandle
.Free();
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();
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
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);
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);
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;
722 library
= PerformanceCounterLib
.GetPerformanceCounterLib(machineName
, new CultureInfo(0x009));
723 return GetProcessInfos(library
);
726 if( isRemoteMachine
) {
727 throw new InvalidOperationException(SR
.GetString(SR
.CouldntConnectToRemoteMachine
), 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;
742 while (processInfos
.Length
== 0 && retryCount
!= 0) {
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
);
754 if (processInfos
.Length
== 0)
755 throw new InvalidOperationException(SR
.GetString(SR
.ProcessDisabled
));
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();
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.");
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");
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
);
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);
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;
869 case ValueId
.ThreadId
:
870 threadInfo
.threadId
= (int)value;
872 case ValueId
.BasePriority
:
873 threadInfo
.basePriority
= (int)value;
875 case ValueId
.CurrentPriority
:
876 threadInfo
.currentPriority
= (int)value;
878 case ValueId
.StartAddress
:
879 threadInfo
.startAddress
= (IntPtr
)value;
881 case ValueId
.ThreadState
:
882 threadInfo
.threadState
= (ThreadState
)value;
884 case ValueId
.ThreadWaitReason
:
885 threadInfo
.threadWaitReason
= GetThreadWaitReason((int)value);
893 internal static ThreadWaitReason
GetThreadWaitReason(int value) {
896 case 7: return ThreadWaitReason
.Executive
;
898 case 8: return ThreadWaitReason
.FreePage
;
900 case 9: return ThreadWaitReason
.PageIn
;
902 case 10: return ThreadWaitReason
.SystemAllocation
;
904 case 11: return ThreadWaitReason
.ExecutionDelay
;
906 case 12: return ThreadWaitReason
.Suspended
;
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;
928 case ValueId
.HandleCount
:
929 processInfo
.handleCount
= (int)value;
931 case ValueId
.PoolPagedBytes
:
932 processInfo
.poolPagedBytes
= value;
934 case ValueId
.PoolNonpagedBytes
:
935 processInfo
.poolNonpagedBytes
= value;
937 case ValueId
.VirtualBytes
:
938 processInfo
.virtualBytes
= value;
940 case ValueId
.VirtualBytesPeak
:
941 processInfo
.virtualBytesPeak
= value;
943 case ValueId
.WorkingSetPeak
:
944 processInfo
.workingSetPeak
= value;
946 case ValueId
.WorkingSet
:
947 processInfo
.workingSet
= value;
949 case ValueId
.PageFileBytesPeak
:
950 processInfo
.pageFileBytesPeak
= value;
952 case ValueId
.PageFileBytes
:
953 processInfo
.pageFileBytes
= value;
955 case ValueId
.PrivateBytes
:
956 processInfo
.privateBytes
= value;
958 case ValueId
.BasePriority
:
959 processInfo
.basePriority
= (int)value;
966 static ValueId
GetValueId(string counterName
) {
967 if (counterName
!= null) {
968 object id
= valueIds
[counterName
];
972 return ValueId
.Unknown
;
975 static long ReadCounterValue(int counterType
, IntPtr dataPtr
) {
976 if ((counterType
& NativeMethods
.NtPerfCounterSizeLarge
) != 0)
977 return Marshal
.ReadInt64(dataPtr
);
979 return(long)Marshal
.ReadInt32(dataPtr
);
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();
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();
1033 #pragma warning disable 169
1034 public static ProcessInfo
[] GetProcessInfos() {
1036 int requiredSize
= 0;
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);
1049 // Retry until we get all the data
1053 // Allocate buffer of longs since some platforms require the buffer to be 64-bit aligned.
1054 buffer
= new long[(bufferSize
+ 7) / 8];
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(),
1069 if ((uint)status
== NativeMethods
.STATUS_INFO_LENGTH_MISMATCH
)
1071 if (bufferHandle
.IsAllocated
) bufferHandle
.Free();
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());
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.
1096 private const int DefaultCachedBufferSize
= 1024;
1098 private const int DefaultCachedBufferSize
= 128 * 1024;
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;
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";
1142 // for normal process without name, using the process ID.
1143 processInfo
.processName
= processInfo
.processId
.ToString(CultureInfo
.InvariantCulture
);
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
));
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
));
1192 if (pi
.NextEntryOffset
== 0) {
1195 totalOffset
+= pi
.NextEntryOffset
;
1198 ProcessInfo
[] temp
= new ProcessInfo
[processInfos
.Values
.Count
];
1199 processInfos
.Values
.CopyTo(temp
, 0);
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
;
1216 for (int i
= 0; i
< name
.Length
; i
++) {
1217 if (name
[i
] == '\\')
1219 else if (name
[i
] == '.')
1224 period
= name
.Length
- 1; // set to end of string
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
1234 period
= name
.Length
- 1; // set to end of string
1238 slash
= 0; // set to start of string
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
;
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
{
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