|
#if !FEATURE_PAL
namespace System.Diagnostics {
using System.Text;
using System.Threading;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Diagnostics;
using System;
using System.Collections;
using System.IO;
using Microsoft.Win32;
using Microsoft.Win32.SafeHandles;
using System.Collections.Specialized;
using System.Globalization;
using System.Security;
using System.Security.Permissions;
using System.Security.Principal;
using System.Runtime.Versioning;
using System.Diagnostics.Contracts;
/// <devdoc>
/// This class finds the main window of a process. It needs to be
/// class because we need to store state while searching the set
/// of windows.
/// </devdoc>
/// <internalonly/>
internal class MainWindowFinder {
IntPtr bestHandle;
int processId;
[ResourceExposure(ResourceScope.Process)]
[ResourceConsumption(ResourceScope.Process)]
public IntPtr FindMainWindow(int processId) {
bestHandle = (IntPtr)0;
this.processId = processId;
NativeMethods.EnumThreadWindowsCallback callback = new NativeMethods.EnumThreadWindowsCallback(this.EnumWindowsCallback);
NativeMethods.EnumWindows(callback, IntPtr.Zero);
GC.KeepAlive(callback);
return bestHandle;
}
[ResourceExposure(ResourceScope.Process)]
[ResourceConsumption(ResourceScope.Process)]
bool IsMainWindow(IntPtr handle) {
if (NativeMethods.GetWindow(new HandleRef(this, handle), NativeMethods.GW_OWNER) != (IntPtr)0 || !NativeMethods.IsWindowVisible(new HandleRef(this, handle)))
return false;
// Microsoft: should we use no window title to mean not a main window? (task man does)
/*
int length = NativeMethods.GetWindowTextLength(handle) * 2;
StringBuilder builder = new StringBuilder(length);
if (NativeMethods.GetWindowText(handle, builder, builder.Capacity) == 0)
return false;
if (builder.ToString() == string.Empty)
return false;
*/
return true;
}
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
bool EnumWindowsCallback(IntPtr handle, IntPtr extraParameter) {
int processId;
NativeMethods.GetWindowThreadProcessId(new HandleRef(this, handle), out processId);
if (processId == this.processId) {
if (IsMainWindow(handle)) {
bestHandle = handle;
return false;
}
}
return true;
}
}
/// <devdoc>
/// This static class is a platform independent Api for querying information
/// about processes, threads and modules. It delegates to the platform
/// specific classes WinProcessManager for Win9x and NtProcessManager
/// for WinNt.
/// </devdoc>
/// <internalonly/>
internal static class ProcessManager {
[ResourceExposure(ResourceScope.Process)]
[ResourceConsumption(ResourceScope.Process)]
static ProcessManager() {
// In order to query information (OpenProcess) on some protected processes
// like csrss, we need SeDebugPrivilege privilege.
// After removing the depenecy on Performance Counter, we don't have a chance
// to run the code in CLR performance counter to ask for this privilege.
// So we will try to get the privilege here.
// We could fail if the user account doesn't have right to do this, but that's fair.
NativeMethods.LUID luid = new NativeMethods.LUID();
if (!NativeMethods.LookupPrivilegeValue(null, "SeDebugPrivilege", out luid)) {
return;
}
IntPtr tokenHandle = IntPtr.Zero;
try {
if( !NativeMethods.OpenProcessToken(
new HandleRef(null, NativeMethods.GetCurrentProcess()),
(int)TokenAccessLevels.AdjustPrivileges,
out tokenHandle)) {
return;
}
NativeMethods.TokenPrivileges tp = new NativeMethods.TokenPrivileges();
tp.PrivilegeCount = 1;
tp.Luid = luid;
tp.Attributes = NativeMethods.SE_PRIVILEGE_ENABLED;
// AdjustTokenPrivileges can return true even if it didn't succeed (when ERROR_NOT_ALL_ASSIGNED is returned).
NativeMethods.AdjustTokenPrivileges(new HandleRef(null,tokenHandle), false, tp, 0, IntPtr.Zero, IntPtr.Zero);
}
finally {
if( tokenHandle != IntPtr.Zero) {
SafeNativeMethods.CloseHandle(tokenHandle);
}
}
}
public static bool IsNt {
get {
return Environment.OSVersion.Platform == PlatformID.Win32NT;
}
}
public static bool IsOSOlderThanXP {
get {
return Environment.OSVersion.Version.Major < 5 ||
(Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor == 0);
}
}
/// <summary>Gets the ProcessInfo for the specified process ID on the specified machine.</summary>
/// <param name="processId">The process ID.</param>
/// <param name="machineName">The machine name.</param>
/// <returns>The ProcessInfo for the process if it could be found; otherwise, null.</returns>
public static ProcessInfo GetProcessInfo(int processId, string machineName) {
bool isRemoteMachine = IsRemoteMachine(machineName);
if (!isRemoteMachine && IsNt && (Environment.OSVersion.Version.Major >= 5)) {
ProcessInfo[] processInfos = NtProcessInfoHelper.GetProcessInfos(pid => pid == processId);
if (processInfos.Length == 1) {
return processInfos[0];
}
}
else {
ProcessInfo[] processInfos = ProcessManager.GetProcessInfosCore(machineName, isRemoteMachine);
foreach (ProcessInfo processInfo in processInfos) {
if (processInfo.processId == processId) {
return processInfo;
}
}
}
return null;
}
public static ProcessInfo[] GetProcessInfos(string machineName) {
bool isRemoteMachine = IsRemoteMachine(machineName);
return GetProcessInfosCore(machineName, isRemoteMachine);
}
private static ProcessInfo[] GetProcessInfosCore(string machineName, bool isRemoteMachine) {
if (IsNt) {
// Do not use performance counter for local machine with Win2000 and above
if( !isRemoteMachine &&
(Environment.OSVersion.Version.Major >= 5 )) {
return NtProcessInfoHelper.GetProcessInfos();
}
return NtProcessManager.GetProcessInfos(machineName, isRemoteMachine);
}
else {
if (isRemoteMachine)
throw new PlatformNotSupportedException(SR.GetString(SR.WinNTRequiredForRemote));
return WinProcessManager.GetProcessInfos();
}
}
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
public static int[] GetProcessIds() {
if (IsNt)
return NtProcessManager.GetProcessIds();
else {
return WinProcessManager.GetProcessIds();
}
}
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
public static int[] GetProcessIds(string machineName) {
if (IsRemoteMachine(machineName)) {
if (IsNt) {
return NtProcessManager.GetProcessIds(machineName, true);
}
else {
throw new PlatformNotSupportedException(SR.GetString(SR.WinNTRequiredForRemote));
}
}
else {
return GetProcessIds();
}
}
[ResourceExposure(ResourceScope.None)]
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
public static bool IsProcessRunning(int processId, string machineName) {
return IsProcessRunning(processId, GetProcessIds(machineName));
}
[ResourceExposure(ResourceScope.None)]
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
public static bool IsProcessRunning(int processId) {
return IsProcessRunning(processId, GetProcessIds());
}
static bool IsProcessRunning(int processId, int[] processIds) {
for (int i = 0; i < processIds.Length; i++)
if (processIds[i] == processId)
return true;
return false;
}
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
public static int GetProcessIdFromHandle(SafeProcessHandle processHandle) {
if (IsNt)
return NtProcessManager.GetProcessIdFromHandle(processHandle);
else
throw new PlatformNotSupportedException(SR.GetString(SR.WinNTRequired));
}
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
public static IntPtr GetMainWindowHandle(int processId) {
MainWindowFinder finder = new MainWindowFinder();
return finder.FindMainWindow(processId);
}
[ResourceExposure(ResourceScope.Process)]
[ResourceConsumption(ResourceScope.Process)]
public static ModuleInfo[] GetModuleInfos(int processId) {
if (IsNt)
return NtProcessManager.GetModuleInfos(processId);
else
return WinProcessManager.GetModuleInfos(processId);
}
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
public static SafeProcessHandle OpenProcess(int processId, int access, bool throwIfExited) {
SafeProcessHandle processHandle = NativeMethods.OpenProcess(access, false, processId);
int result = Marshal.GetLastWin32Error();
if (!processHandle.IsInvalid) {
return processHandle;
}
if (processId == 0) {
throw new Win32Exception(5);
}
// If the handle is invalid because the process has exited, only throw an exception if throwIfExited is true.
if (!IsProcessRunning(processId)) {
if (throwIfExited) {
throw new InvalidOperationException(SR.GetString(SR.ProcessHasExited, processId.ToString(CultureInfo.CurrentCulture)));
}
else {
return SafeProcessHandle.InvalidHandle;
}
}
throw new Win32Exception(result);
}
[ResourceExposure(ResourceScope.Process)]
[ResourceConsumption(ResourceScope.Process)]
public static SafeThreadHandle OpenThread(int threadId, int access) {
try {
SafeThreadHandle threadHandle = NativeMethods.OpenThread(access, false, threadId);
int result = Marshal.GetLastWin32Error();
if (threadHandle.IsInvalid) {
if (result == NativeMethods.ERROR_INVALID_PARAMETER)
throw new InvalidOperationException(SR.GetString(SR.ThreadExited, threadId.ToString(CultureInfo.CurrentCulture)));
throw new Win32Exception(result);
}
return threadHandle;
}
catch (EntryPointNotFoundException x) {
throw new PlatformNotSupportedException(SR.GetString(SR.Win2000Required), x);
}
}
public static bool IsRemoteMachine(string machineName) {
if (machineName == null)
throw new ArgumentNullException("machineName");
if (machineName.Length == 0)
throw new ArgumentException(SR.GetString(SR.InvalidParameter, "machineName", machineName));
string baseName;
if (machineName.StartsWith("\\", StringComparison.Ordinal))
baseName = machineName.Substring(2);
else
baseName = machineName;
if (baseName.Equals(".")) return false;
StringBuilder sb = new StringBuilder(256);
SafeNativeMethods.GetComputerName(sb, new int[] {sb.Capacity});
string computerName = sb.ToString();
if (String.Compare(computerName, baseName, StringComparison.OrdinalIgnoreCase) == 0) return false;
return true;
}
}
/// <devdoc>
/// This static class provides the process api for the Win9x platform.
/// We use the toolhelp32 api to query process, thread and module information.
/// </devdoc>
/// <internalonly/>
internal static class WinProcessManager {
// This is expensive. We should specialize getprocessinfos and only get
// the ids instead of getting all the info and then copying the ids out.
public static int[] GetProcessIds() {
ProcessInfo[] infos = GetProcessInfos();
int[] ids = new int[infos.Length];
for (int i = 0; i < infos.Length; i++) {
ids[i] = infos[i].processId;
}
return ids;
}
[ResourceExposure(ResourceScope.None)]
[ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
public static ProcessInfo[] GetProcessInfos() {
IntPtr handle = (IntPtr)(-1);
GCHandle bufferHandle = new GCHandle();
ArrayList threadInfos = new ArrayList();
Hashtable processInfos = new Hashtable();
try {
handle = NativeMethods.CreateToolhelp32Snapshot(NativeMethods.TH32CS_SNAPPROCESS | NativeMethods.TH32CS_SNAPTHREAD, 0);
if (handle == (IntPtr)(-1)) throw new Win32Exception();
int entrySize = (int)Marshal.SizeOf(typeof(NativeMethods.WinProcessEntry));
int bufferSize = entrySize + NativeMethods.WinProcessEntry.sizeofFileName;
int[] buffer = new int[bufferSize / 4];
bufferHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
IntPtr bufferPtr = bufferHandle.AddrOfPinnedObject();
Marshal.WriteInt32(bufferPtr, bufferSize);
HandleRef handleRef = new HandleRef(null, handle);
if (NativeMethods.Process32First(handleRef, bufferPtr)) {
do {
NativeMethods.WinProcessEntry process = new NativeMethods.WinProcessEntry();
Marshal.PtrToStructure(bufferPtr, process);
ProcessInfo processInfo = new ProcessInfo();
String name = Marshal.PtrToStringAnsi((IntPtr)((long)bufferPtr + entrySize));
processInfo.processName = Path.ChangeExtension(Path.GetFileName(name), null);
processInfo.handleCount = process.cntUsage;
processInfo.processId = process.th32ProcessID;
processInfo.basePriority = process.pcPriClassBase;
processInfo.mainModuleId = process.th32ModuleID;
processInfos.Add(processInfo.processId, processInfo);
Marshal.WriteInt32(bufferPtr, bufferSize);
}
while (NativeMethods.Process32Next(handleRef, bufferPtr));
}
NativeMethods.WinThreadEntry thread = new NativeMethods.WinThreadEntry();
thread.dwSize = Marshal.SizeOf(thread);
if (NativeMethods.Thread32First(handleRef, thread)) {
do {
ThreadInfo threadInfo = new ThreadInfo();
threadInfo.threadId = thread.th32ThreadID;
threadInfo.processId = thread.th32OwnerProcessID;
threadInfo.basePriority = thread.tpBasePri;
threadInfo.currentPriority = thread.tpBasePri + thread.tpDeltaPri;
threadInfos.Add(threadInfo);
}
while (NativeMethods.Thread32Next(handleRef, thread));
}
for (int i = 0; i < threadInfos.Count; i++) {
ThreadInfo threadInfo = (ThreadInfo)threadInfos[i];
ProcessInfo processInfo = (ProcessInfo)processInfos[threadInfo.processId];
if (processInfo != null)
processInfo.threadInfoList.Add(threadInfo);
//else
// throw new InvalidOperationException(SR.GetString(SR.ProcessNotFound, threadInfo.threadId.ToString(), threadInfo.processId.ToString()));
}
}
finally {
if (bufferHandle.IsAllocated) bufferHandle.Free();
Debug.WriteLineIf(Process.processTracing.TraceVerbose, "Process - CloseHandle(toolhelp32 snapshot handle)");
if (handle != (IntPtr)(-1)) SafeNativeMethods.CloseHandle(handle);
}
ProcessInfo[] temp = new ProcessInfo[processInfos.Values.Count];
processInfos.Values.CopyTo(temp, 0);
return temp;
}
[ResourceExposure(ResourceScope.Process)]
[ResourceConsumption(ResourceScope.Process)]
public static ModuleInfo[] GetModuleInfos(int processId) {
IntPtr handle = (IntPtr)(-1);
GCHandle bufferHandle = new GCHandle();
ArrayList moduleInfos = new ArrayList();
try {
handle = NativeMethods.CreateToolhelp32Snapshot(NativeMethods.TH32CS_SNAPMODULE, processId);
if (handle == (IntPtr)(-1)) throw new Win32Exception();
int entrySize = Marshal.SizeOf(typeof(NativeMethods.WinModuleEntry));
int bufferSize = entrySize + NativeMethods.WinModuleEntry.sizeofFileName + NativeMethods.WinModuleEntry.sizeofModuleName;
int[] buffer = new int[bufferSize / 4];
bufferHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
IntPtr bufferPtr = bufferHandle.AddrOfPinnedObject();
Marshal.WriteInt32(bufferPtr, bufferSize);
HandleRef handleRef = new HandleRef(null, handle);
if (NativeMethods.Module32First(handleRef, bufferPtr)) {
do {
NativeMethods.WinModuleEntry module = new NativeMethods.WinModuleEntry();
Marshal.PtrToStructure(bufferPtr, module);
ModuleInfo moduleInfo = new ModuleInfo();
moduleInfo.baseName = Marshal.PtrToStringAnsi((IntPtr)((long)bufferPtr + entrySize));
moduleInfo.fileName = Marshal.PtrToStringAnsi((IntPtr)((long)bufferPtr + entrySize + NativeMethods.WinModuleEntry.sizeofModuleName));
moduleInfo.baseOfDll = module.modBaseAddr;
moduleInfo.sizeOfImage = module.modBaseSize;
moduleInfo.Id = module.th32ModuleID;
moduleInfos.Add(moduleInfo);
Marshal.WriteInt32(bufferPtr, bufferSize);
}
while (NativeMethods.Module32Next(handleRef, bufferPtr));
}
}
finally {
if (bufferHandle.IsAllocated) bufferHandle.Free();
Debug.WriteLineIf(Process.processTracing.TraceVerbose, "Process - CloseHandle(toolhelp32 snapshot handle)");
if (handle != (IntPtr)(-1)) SafeNativeMethods.CloseHandle(handle);
}
ModuleInfo[] temp = new ModuleInfo[moduleInfos.Count];
moduleInfos.CopyTo(temp, 0);
return temp;
}
}
/// <devdoc>
/// This static class provides the process api for the WinNt platform.
/// We use the performance counter api to query process and thread
/// information. Module information is obtained using PSAPI.
/// </devdoc>
/// <internalonly/>
internal static class NtProcessManager {
private const int ProcessPerfCounterId = 230;
private const int ThreadPerfCounterId = 232;
private const string PerfCounterQueryString = "230 232";
internal const int IdleProcessID = 0;
static Hashtable valueIds;
static NtProcessManager() {
valueIds = new Hashtable();
valueIds.Add("Handle Count", ValueId.HandleCount);
valueIds.Add("Pool Paged Bytes", ValueId.PoolPagedBytes);
valueIds.Add("Pool Nonpaged Bytes", ValueId.PoolNonpagedBytes);
valueIds.Add("Elapsed Time", ValueId.ElapsedTime);
valueIds.Add("Virtual Bytes Peak", ValueId.VirtualBytesPeak);
valueIds.Add("Virtual Bytes", ValueId.VirtualBytes);
valueIds.Add("Private Bytes", ValueId.PrivateBytes);
valueIds.Add("Page File Bytes", ValueId.PageFileBytes);
valueIds.Add("Page File Bytes Peak", ValueId.PageFileBytesPeak);
valueIds.Add("Working Set Peak", ValueId.WorkingSetPeak);
valueIds.Add("Working Set", ValueId.WorkingSet);
valueIds.Add("ID Thread", ValueId.ThreadId);
valueIds.Add("ID Process", ValueId.ProcessId);
valueIds.Add("Priority Base", ValueId.BasePriority);
valueIds.Add("Priority Current", ValueId.CurrentPriority);
valueIds.Add("% User Time", ValueId.UserTime);
valueIds.Add("% Privileged Time", ValueId.PrivilegedTime);
valueIds.Add("Start Address", ValueId.StartAddress);
valueIds.Add("Thread State", ValueId.ThreadState);
valueIds.Add("Thread Wait Reason", ValueId.ThreadWaitReason);
}
internal static int SystemProcessID {
get {
const int systemProcessIDOnXP = 4;
const int systemProcessIDOn2K = 8;
if( ProcessManager.IsOSOlderThanXP) {
return systemProcessIDOn2K;
}
else {
return systemProcessIDOnXP;
}
}
}
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
public static int[] GetProcessIds(string machineName, bool isRemoteMachine) {
ProcessInfo[] infos = GetProcessInfos(machineName, isRemoteMachine);
int[] ids = new int[infos.Length];
for (int i = 0; i < infos.Length; i++)
ids[i] = infos[i].processId;
return ids;
}
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
public static int[] GetProcessIds() {
int[] processIds = new int[256];
int size;
for (;;) {
if (!NativeMethods.EnumProcesses(processIds, processIds.Length * 4, out size))
throw new Win32Exception();
if (size == processIds.Length * 4) {
processIds = new int[processIds.Length * 2];
continue;
}
break;
}
int[] ids = new int[size / 4];
Array.Copy(processIds, ids, ids.Length);
return ids;
}
[ResourceExposure(ResourceScope.Process)]
[ResourceConsumption(ResourceScope.Process)]
public static ModuleInfo[] GetModuleInfos(int processId) {
return GetModuleInfos(processId, false);
}
[ResourceExposure(ResourceScope.Process)]
[ResourceConsumption(ResourceScope.Process)]
public static ModuleInfo GetFirstModuleInfo(int processId) {
ModuleInfo[] moduleInfos = GetModuleInfos(processId, true);
if( moduleInfos.Length == 0) {
return null;
}
else {
return moduleInfos[0];
}
}
[ResourceExposure(ResourceScope.None)]
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
private static ModuleInfo[] GetModuleInfos(int processId, bool firstModuleOnly) {
Contract.Ensures(Contract.Result<ModuleInfo[]>().Length >= 1);
// preserving Everett behavior.
if( processId == SystemProcessID || processId == IdleProcessID) {
// system process and idle process doesn't have any modules
throw new Win32Exception(HResults.EFail,SR.GetString(SR.EnumProcessModuleFailed));
}
SafeProcessHandle processHandle = SafeProcessHandle.InvalidHandle;
try {
processHandle = ProcessManager.OpenProcess(processId, NativeMethods.PROCESS_QUERY_INFORMATION | NativeMethods.PROCESS_VM_READ, true);
IntPtr[] moduleHandles = new IntPtr[64];
GCHandle moduleHandlesArrayHandle = new GCHandle();
int moduleCount = 0;
for (;;) {
bool enumResult = false;
try {
moduleHandlesArrayHandle = GCHandle.Alloc(moduleHandles, GCHandleType.Pinned);
enumResult = NativeMethods.EnumProcessModules(processHandle, moduleHandlesArrayHandle.AddrOfPinnedObject(), moduleHandles.Length * IntPtr.Size, ref moduleCount);
// The API we need to use to enumerate process modules differs on two factors:
// 1) If our process is running in WOW64.
// 2) The bitness of the process we wish to introspect.
//
// If we are not running in WOW64 or we ARE in WOW64 but want to inspect a 32 bit process
// we can call psapi!EnumProcessModules.
//
// If we are running in WOW64 and we want to inspect the modules of a 64 bit process then
// psapi!EnumProcessModules will return false with ERROR_PARTIAL_COPY (299). In this case we can't
// do the enumeration at all. So we'll detect this case and bail out.
//
// Also, EnumProcessModules is not a reliable method to get the modules for a process.
// If OS loader is touching module information, this method might fail and copy part of the data.
// This is no easy solution to this problem. The only reliable way to fix this is to
// suspend all the threads in target process. Of course we don't want to do this in Process class.
// So we just to try avoid the ---- by calling the same method 50 (an arbitary number) times.
//
if (!enumResult) {
bool sourceProcessIsWow64 = false;
bool targetProcessIsWow64 = false;
if (!ProcessManager.IsOSOlderThanXP) {
SafeProcessHandle hCurProcess = SafeProcessHandle.InvalidHandle;
try {
hCurProcess = ProcessManager.OpenProcess(NativeMethods.GetCurrentProcessId(), NativeMethods.PROCESS_QUERY_INFORMATION, true);
bool wow64Ret;
wow64Ret = SafeNativeMethods.IsWow64Process(hCurProcess, ref sourceProcessIsWow64);
if (!wow64Ret) {
throw new Win32Exception();
}
wow64Ret = SafeNativeMethods.IsWow64Process(processHandle, ref targetProcessIsWow64);
if (!wow64Ret) {
throw new Win32Exception();
}
if (sourceProcessIsWow64 && !targetProcessIsWow64) {
// Wow64 isn't going to allow this to happen, the best we can do is give a descriptive error to the user.
throw new Win32Exception(NativeMethods.ERROR_PARTIAL_COPY, SR.GetString(SR.EnumProcessModuleFailedDueToWow));
}
} finally {
if (hCurProcess != SafeProcessHandle.InvalidHandle) {
hCurProcess.Close();
}
}
}
// If the failure wasn't due to Wow64, try again.
for (int i = 0; i < 50; i++) {
enumResult = NativeMethods.EnumProcessModules(processHandle, moduleHandlesArrayHandle.AddrOfPinnedObject(), moduleHandles.Length * IntPtr.Size, ref moduleCount);
if (enumResult) {
break;
}
Thread.Sleep(1);
}
}
}
finally {
moduleHandlesArrayHandle.Free();
}
if (!enumResult) {
throw new Win32Exception();
}
moduleCount /= IntPtr.Size;
if (moduleCount <= moduleHandles.Length) break;
moduleHandles = new IntPtr[moduleHandles.Length * 2];
}
ArrayList moduleInfos = new ArrayList();
int ret;
for (int i = 0; i < moduleCount; i++) {
try
{
ModuleInfo moduleInfo = new ModuleInfo();
IntPtr moduleHandle = moduleHandles[i];
NativeMethods.NtModuleInfo ntModuleInfo = new NativeMethods.NtModuleInfo();
if (!NativeMethods.GetModuleInformation(processHandle, new HandleRef(null, moduleHandle), ntModuleInfo, Marshal.SizeOf(ntModuleInfo)))
throw new Win32Exception();
moduleInfo.sizeOfImage = ntModuleInfo.SizeOfImage;
moduleInfo.entryPoint = ntModuleInfo.EntryPoint;
moduleInfo.baseOfDll = ntModuleInfo.BaseOfDll;
StringBuilder baseName = new StringBuilder(1024);
ret = NativeMethods.GetModuleBaseName(processHandle, new HandleRef(null, moduleHandle), baseName, baseName.Capacity * 2);
if (ret == 0) throw new Win32Exception();
moduleInfo.baseName = baseName.ToString();
StringBuilder fileName = new StringBuilder(1024);
ret = NativeMethods.GetModuleFileNameEx(processHandle, new HandleRef(null, moduleHandle), fileName, fileName.Capacity * 2);
if (ret == 0) throw new Win32Exception();
moduleInfo.fileName = fileName.ToString();
// smss.exe is started before the win32 subsystem so it get this funny "\systemroot\.." path.
// We change this to the actual path by appending "smss.exe" to GetSystemDirectory()
if (string.Compare(moduleInfo.fileName, "\\SystemRoot\\System32\\smss.exe", StringComparison.OrdinalIgnoreCase) == 0) {
moduleInfo.fileName = Path.Combine(Environment.SystemDirectory, "smss.exe");
}
// Avoid returning Unicode-style long string paths. IO methods cannot handle them.
if (moduleInfo.fileName != null
&& moduleInfo.fileName.Length >= 4
&& moduleInfo.fileName.StartsWith(@"\\?\", StringComparison.Ordinal)) {
moduleInfo.fileName = moduleInfo.fileName.Substring(4);
}
moduleInfos.Add(moduleInfo);
}
catch (Win32Exception e)
{
if (e.NativeErrorCode == NativeMethods.ERROR_INVALID_HANDLE || e.NativeErrorCode == NativeMethods.ERROR_PARTIAL_COPY)
{
// It's possible that another thread casued this module to become
// unloaded (e.g FreeLibrary was called on the module). Ignore it and
// move on.
}
else
{
throw;
}
}
//
// If the user is only interested in the main module, break now.
// This avoid some waste of time. In addition, if the application unloads a DLL
// we will not get an exception.
//
if( firstModuleOnly) { break; }
}
ModuleInfo[] temp = new ModuleInfo[moduleInfos.Count];
moduleInfos.CopyTo(temp, 0);
return temp;
}
finally {
Debug.WriteLineIf(Process.processTracing.TraceVerbose, "Process - CloseHandle(process)");
if (!processHandle.IsInvalid ) {
processHandle.Close();
}
}
}
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
public static int GetProcessIdFromHandle(SafeProcessHandle processHandle) {
NativeMethods.NtProcessBasicInfo info = new NativeMethods.NtProcessBasicInfo();
int status = NativeMethods.NtQueryInformationProcess(processHandle, NativeMethods.NtQueryProcessBasicInfo, info, (int)Marshal.SizeOf(info), null);
if (status != 0) {
throw new InvalidOperationException(SR.GetString(SR.CantGetProcessId), new Win32Exception(status));
}
// We should change the signature of this function and ID property in process class.
return info.UniqueProcessId.ToInt32();
}
public static ProcessInfo[] GetProcessInfos(string machineName, bool isRemoteMachine) {
// We demand unmanaged code here because PerformanceCounterLib doesn't demand
// anything. This is the only place we do GetPerformanceCounterLib, and it isn't cached.
new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand();
PerformanceCounterLib library = null;
try {
library = PerformanceCounterLib.GetPerformanceCounterLib(machineName, new CultureInfo(0x009));
return GetProcessInfos(library);
}
catch(Exception e) {
if( isRemoteMachine) {
throw new InvalidOperationException(SR.GetString(SR.CouldntConnectToRemoteMachine), e);
}
else {
throw e;
}
}
// We don't want to call library.Close() here because that would cause us to unload all of the perflibs.
// On the next call to GetProcessInfos, we'd have to load them all up again, which is SLOW!
}
static ProcessInfo[] GetProcessInfos(PerformanceCounterLib library) {
ProcessInfo[] processInfos = new ProcessInfo[0] ;
byte[] dataPtr = null;
int retryCount = 5;
while (processInfos.Length == 0 && retryCount != 0) {
try {
dataPtr = library.GetPerformanceData(PerfCounterQueryString);
processInfos = GetProcessInfos(library, ProcessPerfCounterId, ThreadPerfCounterId, dataPtr);
}
catch (Exception e) {
throw new InvalidOperationException(SR.GetString(SR.CouldntGetProcessInfos), e);
}
--retryCount;
}
if (processInfos.Length == 0)
throw new InvalidOperationException(SR.GetString(SR.ProcessDisabled));
return processInfos;
}
static ProcessInfo[] GetProcessInfos(PerformanceCounterLib library, int processIndex, int threadIndex, byte[] data) {
Debug.WriteLineIf(Process.processTracing.TraceVerbose, "GetProcessInfos()");
Hashtable processInfos = new Hashtable();
ArrayList threadInfos = new ArrayList();
GCHandle dataHandle = new GCHandle();
try {
dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
IntPtr dataBlockPtr = dataHandle.AddrOfPinnedObject();
NativeMethods.PERF_DATA_BLOCK dataBlock = new NativeMethods.PERF_DATA_BLOCK();
Marshal.PtrToStructure(dataBlockPtr, dataBlock);
IntPtr typePtr = (IntPtr)((long)dataBlockPtr + dataBlock.HeaderLength);
NativeMethods.PERF_INSTANCE_DEFINITION instance = new NativeMethods.PERF_INSTANCE_DEFINITION();
NativeMethods.PERF_COUNTER_BLOCK counterBlock = new NativeMethods.PERF_COUNTER_BLOCK();
for (int i = 0; i < dataBlock.NumObjectTypes; i++) {
NativeMethods.PERF_OBJECT_TYPE type = new NativeMethods.PERF_OBJECT_TYPE();
Marshal.PtrToStructure(typePtr, type);
IntPtr instancePtr = (IntPtr)((long)typePtr + type.DefinitionLength);
IntPtr counterPtr = (IntPtr)((long)typePtr + type.HeaderLength);
ArrayList counterList = new ArrayList();
for (int j = 0; j < type.NumCounters; j++) {
NativeMethods.PERF_COUNTER_DEFINITION counter = new NativeMethods.PERF_COUNTER_DEFINITION();
Marshal.PtrToStructure(counterPtr, counter);
string counterName = library.GetCounterName(counter.CounterNameTitleIndex);
if (type.ObjectNameTitleIndex == processIndex)
counter.CounterNameTitlePtr = (int)GetValueId(counterName);
else if (type.ObjectNameTitleIndex == threadIndex)
counter.CounterNameTitlePtr = (int)GetValueId(counterName);
counterList.Add(counter);
counterPtr = (IntPtr)((long)counterPtr + counter.ByteLength);
}
NativeMethods.PERF_COUNTER_DEFINITION[] counters = new NativeMethods.PERF_COUNTER_DEFINITION[counterList.Count];
counterList.CopyTo(counters, 0);
for (int j = 0; j < type.NumInstances; j++) {
Marshal.PtrToStructure(instancePtr, instance);
IntPtr namePtr = (IntPtr)((long)instancePtr + instance.NameOffset);
string instanceName = Marshal.PtrToStringUni(namePtr);
if (instanceName.Equals("_Total")) continue;
IntPtr counterBlockPtr = (IntPtr)((long)instancePtr + instance.ByteLength);
Marshal.PtrToStructure(counterBlockPtr, counterBlock);
if (type.ObjectNameTitleIndex == processIndex) {
ProcessInfo processInfo = GetProcessInfo(type, (IntPtr)((long)instancePtr + instance.ByteLength), counters);
if (processInfo.processId == 0 && string.Compare(instanceName, "Idle", StringComparison.OrdinalIgnoreCase) != 0) {
// Sometimes we'll get a process structure that is not completely filled in.
// We can catch some of these by looking for non-"idle" processes that have id 0
// and ignoring those.
Debug.WriteLineIf(Process.processTracing.TraceVerbose, "GetProcessInfos() - found a non-idle process with id 0; ignoring.");
}
else {
if (processInfos[processInfo.processId] != null) {
// We've found two entries in the perfcounters that claim to be the
// same process. We throw an exception. Is this really going to be
// helpfull to the user? Should we just ignore?
Debug.WriteLineIf(Process.processTracing.TraceVerbose, "GetProcessInfos() - found a duplicate process id");
}
else {
// the performance counters keep a 15 character prefix of the exe name, and then delete the ".exe",
// if it's in the first 15. The problem is that sometimes that will leave us with part of ".exe"
// at the end. If instanceName ends in ".", ".e", or ".ex" we remove it.
string processName = instanceName;
if (processName.Length == 15) {
if (instanceName.EndsWith(".", StringComparison.Ordinal )) processName = instanceName.Substring(0, 14);
else if (instanceName.EndsWith(".e", StringComparison.Ordinal )) processName = instanceName.Substring(0, 13);
else if (instanceName.EndsWith(".ex", StringComparison.Ordinal)) processName = instanceName.Substring(0, 12);
}
processInfo.processName = processName;
processInfos.Add(processInfo.processId, processInfo);
}
}
}
else if (type.ObjectNameTitleIndex == threadIndex) {
ThreadInfo threadInfo = GetThreadInfo(type, (IntPtr)((long)instancePtr + instance.ByteLength), counters);
if (threadInfo.threadId != 0) threadInfos.Add(threadInfo);
}
instancePtr = (IntPtr)((long)instancePtr + instance.ByteLength + counterBlock.ByteLength);
}
typePtr = (IntPtr)((long)typePtr + type.TotalByteLength);
}
}
finally {
if (dataHandle.IsAllocated) dataHandle.Free();
}
for (int i = 0; i < threadInfos.Count; i++) {
ThreadInfo threadInfo = (ThreadInfo)threadInfos[i];
ProcessInfo processInfo = (ProcessInfo)processInfos[threadInfo.processId];
if (processInfo != null) {
processInfo.threadInfoList.Add(threadInfo);
}
}
ProcessInfo[] temp = new ProcessInfo[processInfos.Values.Count];
processInfos.Values.CopyTo(temp, 0);
return temp;
}
static ThreadInfo GetThreadInfo(NativeMethods.PERF_OBJECT_TYPE type, IntPtr instancePtr, NativeMethods.PERF_COUNTER_DEFINITION[] counters) {
ThreadInfo threadInfo = new ThreadInfo();
for (int i = 0; i < counters.Length; i++) {
NativeMethods.PERF_COUNTER_DEFINITION counter = counters[i];
long value = ReadCounterValue(counter.CounterType, (IntPtr)((long)instancePtr + counter.CounterOffset));
switch ((ValueId)counter.CounterNameTitlePtr) {
case ValueId.ProcessId:
threadInfo.processId = (int)value;
break;
case ValueId.ThreadId:
threadInfo.threadId = (int)value;
break;
case ValueId.BasePriority:
threadInfo.basePriority = (int)value;
break;
case ValueId.CurrentPriority:
threadInfo.currentPriority = (int)value;
break;
case ValueId.StartAddress:
threadInfo.startAddress = (IntPtr)value;
break;
case ValueId.ThreadState:
threadInfo.threadState = (ThreadState)value;
break;
case ValueId.ThreadWaitReason:
threadInfo.threadWaitReason = GetThreadWaitReason((int)value);
break;
}
}
return threadInfo;
}
internal static ThreadWaitReason GetThreadWaitReason(int value) {
switch (value) {
case 0:
case 7: return ThreadWaitReason.Executive;
case 1:
case 8: return ThreadWaitReason.FreePage;
case 2:
case 9: return ThreadWaitReason.PageIn;
case 3:
case 10: return ThreadWaitReason.SystemAllocation;
case 4:
case 11: return ThreadWaitReason.ExecutionDelay;
case 5:
case 12: return ThreadWaitReason.Suspended;
case 6:
case 13: return ThreadWaitReason.UserRequest;
case 14: return ThreadWaitReason.EventPairHigh;;
case 15: return ThreadWaitReason.EventPairLow;
case 16: return ThreadWaitReason.LpcReceive;
case 17: return ThreadWaitReason.LpcReply;
case 18: return ThreadWaitReason.VirtualMemory;
case 19: return ThreadWaitReason.PageOut;
default: return ThreadWaitReason.Unknown;
}
}
static ProcessInfo GetProcessInfo(NativeMethods.PERF_OBJECT_TYPE type, IntPtr instancePtr, NativeMethods.PERF_COUNTER_DEFINITION[] counters) {
ProcessInfo processInfo = new ProcessInfo();
for (int i = 0; i < counters.Length; i++) {
NativeMethods.PERF_COUNTER_DEFINITION counter = counters[i];
long value = ReadCounterValue(counter.CounterType, (IntPtr)((long)instancePtr + counter.CounterOffset));
switch ((ValueId)counter.CounterNameTitlePtr) {
case ValueId.ProcessId:
processInfo.processId = (int)value;
break;
case ValueId.HandleCount:
processInfo.handleCount = (int)value;
break;
case ValueId.PoolPagedBytes:
processInfo.poolPagedBytes = value;
break;
case ValueId.PoolNonpagedBytes:
processInfo.poolNonpagedBytes = value;
break;
case ValueId.VirtualBytes:
processInfo.virtualBytes = value;
break;
case ValueId.VirtualBytesPeak:
processInfo.virtualBytesPeak = value;
break;
case ValueId.WorkingSetPeak:
processInfo.workingSetPeak = value;
break;
case ValueId.WorkingSet:
processInfo.workingSet = value;
break;
case ValueId.PageFileBytesPeak:
processInfo.pageFileBytesPeak = value;
break;
case ValueId.PageFileBytes:
processInfo.pageFileBytes = value;
break;
case ValueId.PrivateBytes:
processInfo.privateBytes = value;
break;
case ValueId.BasePriority:
processInfo.basePriority = (int)value;
break;
}
}
return processInfo;
}
static ValueId GetValueId(string counterName) {
if (counterName != null) {
object id = valueIds[counterName];
if (id != null)
return(ValueId)id;
}
return ValueId.Unknown;
}
static long ReadCounterValue(int counterType, IntPtr dataPtr) {
if ((counterType & NativeMethods.NtPerfCounterSizeLarge) != 0)
return Marshal.ReadInt64(dataPtr);
else
return(long)Marshal.ReadInt32(dataPtr);
}
enum ValueId {
Unknown = -1,
HandleCount,
PoolPagedBytes,
PoolNonpagedBytes,
ElapsedTime,
VirtualBytesPeak,
VirtualBytes,
PrivateBytes,
PageFileBytes,
PageFileBytesPeak,
WorkingSetPeak,
WorkingSet,
ThreadId,
ProcessId,
BasePriority,
CurrentPriority,
UserTime,
PrivilegedTime,
StartAddress,
ThreadState,
ThreadWaitReason
}
}
internal static class NtProcessInfoHelper {
private static int GetNewBufferSize(int existingBufferSize, int requiredSize) {
if( requiredSize == 0) {
//
// On some old OS like win2000, requiredSize will not be set if the buffer
// passed to NtQuerySystemInformation is not enough.
//
int newSize = existingBufferSize * 2;
if ( newSize < existingBufferSize ) {
// In reality, we should never overflow.
// Adding the code here just in case it happens.
throw new OutOfMemoryException();
}
return newSize;
}
else {
// allocating a few more kilo bytes just in case there are some new process
// kicked in since new call to NtQuerySystemInformation
int newSize = requiredSize + 1024 * 10;
if ( newSize < requiredSize ) {
throw new OutOfMemoryException();
}
return newSize;
}
}
#pragma warning disable 169
public static ProcessInfo[] GetProcessInfos(Predicate<int> processIdFilter = null) {
int requiredSize = 0;
int status;
ProcessInfo[] processInfos;
GCHandle bufferHandle = new GCHandle();
// Start with the default buffer size.
int bufferSize = DefaultCachedBufferSize;
// Get the cached buffer.
long[] buffer = Interlocked.Exchange(ref CachedBuffer, null);
try {
// Retry until we get all the data
do {
if (buffer == null)
{
// Allocate buffer of longs since some platforms require the buffer to be 64-bit aligned.
buffer = new long[(bufferSize + 7) / 8];
}
else
{
// If we have cached buffer, set the size properly.
bufferSize = buffer.Length * sizeof(long);
}
bufferHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
status = NativeMethods.NtQuerySystemInformation(
NativeMethods.NtQuerySystemProcessInformation,
bufferHandle.AddrOfPinnedObject(),
bufferSize,
out requiredSize);
if ((uint)status == NativeMethods.STATUS_INFO_LENGTH_MISMATCH)
{
if (bufferHandle.IsAllocated) bufferHandle.Free();
buffer = null;
bufferSize = GetNewBufferSize(bufferSize, requiredSize);
}
} while ((uint)status == NativeMethods.STATUS_INFO_LENGTH_MISMATCH);
if (status < 0) { // see definition of NT_SUCCESS(Status) in SDK
throw new InvalidOperationException(SR.GetString(SR.CouldntGetProcessInfos), new Win32Exception(status));
}
// Parse the data block to get process information
processInfos = GetProcessInfos(bufferHandle.AddrOfPinnedObject(), processIdFilter);
}
finally {
// Cache the final buffer for use on the next call.
Interlocked.Exchange(ref CachedBuffer, buffer);
if (bufferHandle.IsAllocated) bufferHandle.Free();
}
return processInfos;
}
// Use a smaller buffer size on debug to ensure we hit the retry path.
#if DEBUG
private const int DefaultCachedBufferSize = 1024;
#else
private const int DefaultCachedBufferSize = 128 * 1024;
#endif
// Cache a single buffer for use in GetProcessInfos().
private static long[] CachedBuffer;
static ProcessInfo[] GetProcessInfos(IntPtr dataPtr, Predicate<int> processIdFilter) {
// 60 is a reasonable number for processes on a normal machine.
Hashtable processInfos = new Hashtable(60);
long totalOffset = 0;
while(true) {
IntPtr currentPtr = (IntPtr)((long)dataPtr + totalOffset);
SystemProcessInformation pi = new SystemProcessInformation();
Marshal.PtrToStructure(currentPtr, pi);
// Process ID shouldn't overflow. OS API GetCurrentProcessID returns DWORD.
int processInfoProcessId = pi.UniqueProcessId.ToInt32();
if (processIdFilter == null || processIdFilter(processInfoProcessId)) {
// get information for a process
ProcessInfo processInfo = new ProcessInfo();
processInfo.processId = processInfoProcessId;
processInfo.handleCount = (int)pi.HandleCount;
processInfo.sessionId = (int)pi.SessionId;
processInfo.poolPagedBytes = (long)pi.QuotaPagedPoolUsage;;
processInfo.poolNonpagedBytes = (long)pi.QuotaNonPagedPoolUsage;
processInfo.virtualBytes = (long)pi.VirtualSize;
processInfo.virtualBytesPeak = (long)pi.PeakVirtualSize;
processInfo.workingSetPeak = (long)pi.PeakWorkingSetSize;
processInfo.workingSet = (long)pi.WorkingSetSize;
processInfo.pageFileBytesPeak = (long)pi.PeakPagefileUsage;
processInfo.pageFileBytes = (long)pi.PagefileUsage;
processInfo.privateBytes = (long)pi.PrivatePageCount;
processInfo.basePriority = pi.BasePriority;
if( pi.NamePtr == IntPtr.Zero) {
if( processInfo.processId == NtProcessManager.SystemProcessID) {
processInfo.processName = "System";
}
else if( processInfo.processId == NtProcessManager.IdleProcessID) {
processInfo.processName = "Idle";
}
else {
// for normal process without name, using the process ID.
processInfo.processName = processInfo.processId.ToString(CultureInfo.InvariantCulture);
}
}
else {
string processName = GetProcessShortName(Marshal.PtrToStringUni(pi.NamePtr, pi.NameLength/sizeof(char)));
//
// On old operating system (NT4 and windows 2000), the process name might be truncated to 15
// characters. For example, aspnet_admin.exe will show up in performance counter as aspnet_admin.ex.
// Process class try to return a nicer name. We used to get the main module name for a process and
// use that as the process name. However normal user doesn't have access to module information,
// so normal user will see an exception when we try to get a truncated process name.
//
if (ProcessManager.IsOSOlderThanXP && (processName.Length == 15)) {
if (processName.EndsWith(".", StringComparison.OrdinalIgnoreCase)) {
processName = processName.Substring(0, 14);
}
else if (processName.EndsWith(".e", StringComparison.OrdinalIgnoreCase)) {
processName = processName.Substring(0, 13);
}
else if (processName.EndsWith(".ex", StringComparison.OrdinalIgnoreCase)) {
processName = processName.Substring(0, 12);
}
}
processInfo.processName = processName;
}
// get the threads for current process
processInfos[processInfo.processId] = processInfo;
currentPtr = (IntPtr)((long)currentPtr + Marshal.SizeOf(pi));
int i = 0;
while( i < pi.NumberOfThreads) {
SystemThreadInformation ti = new SystemThreadInformation();
Marshal.PtrToStructure(currentPtr, ti);
ThreadInfo threadInfo = new ThreadInfo();
threadInfo.processId = (int)ti.UniqueProcess;
threadInfo.threadId = (int)ti.UniqueThread;
threadInfo.basePriority = ti.BasePriority;
threadInfo.currentPriority = ti.Priority;
threadInfo.startAddress = ti.StartAddress;
threadInfo.threadState = (ThreadState)ti.ThreadState;
threadInfo.threadWaitReason = NtProcessManager.GetThreadWaitReason((int)ti.WaitReason);
processInfo.threadInfoList.Add(threadInfo);
currentPtr = (IntPtr)((long)currentPtr + Marshal.SizeOf(ti));
i++;
}
}
if (pi.NextEntryOffset == 0) {
break;
}
totalOffset += pi.NextEntryOffset;
}
ProcessInfo[] temp = new ProcessInfo[processInfos.Values.Count];
processInfos.Values.CopyTo(temp, 0);
return temp;
}
// This function generates the short form of process name.
//
// This is from GetProcessShortName in NT code base.
// Check base\screg\winreg\perfdlls\process\perfsprc.c for details.
internal static string GetProcessShortName(String name) {
if (String.IsNullOrEmpty(name)) {
Debug.WriteLineIf(Process.processTracing.TraceVerbose, "GetProcessInfos() - unexpected blank ProcessName");
return String.Empty;
}
int slash = -1;
int period = -1;
for (int i = 0; i < name.Length; i++) {
if (name[i] == '\\')
slash = i;
else if (name[i] == '.')
period = i;
}
if (period == -1)
period = name.Length - 1; // set to end of string
else {
// if a period was found, then see if the extension is
// .EXE, if so drop it, if not, then use end of string
// (i.e. include extension in name)
String extension = name.Substring(period);
if(String.Equals(".exe", extension, StringComparison.OrdinalIgnoreCase) )
period--; // point to character before period
else
period = name.Length - 1; // set to end of string
}
if (slash == -1)
slash = 0; // set to start of string
else
slash++; // point to character next to slash
// copy characters between period (or end of string) and
// slash (or start of string) to make image name
return name.Substring(slash, period - slash + 1);
}
// native struct defined in ntexapi.h
[StructLayout(LayoutKind.Sequential)]
internal class SystemProcessInformation {
internal uint NextEntryOffset;
internal uint NumberOfThreads;
long SpareLi1;
long SpareLi2;
long SpareLi3;
long CreateTime;
long UserTime;
long KernelTime;
internal ushort NameLength; // UNICODE_STRING
internal ushort MaximumNameLength;
internal IntPtr NamePtr; // This will point into the data block returned by NtQuerySystemInformation
internal int BasePriority;
internal IntPtr UniqueProcessId;
internal IntPtr InheritedFromUniqueProcessId;
internal uint HandleCount;
internal uint SessionId;
internal UIntPtr PageDirectoryBase;
internal UIntPtr PeakVirtualSize; // SIZE_T
internal UIntPtr VirtualSize;
internal uint PageFaultCount;
internal UIntPtr PeakWorkingSetSize;
internal UIntPtr WorkingSetSize;
internal UIntPtr QuotaPeakPagedPoolUsage;
internal UIntPtr QuotaPagedPoolUsage;
internal UIntPtr QuotaPeakNonPagedPoolUsage;
internal UIntPtr QuotaNonPagedPoolUsage;
internal UIntPtr PagefileUsage;
internal UIntPtr PeakPagefileUsage;
internal UIntPtr PrivatePageCount;
long ReadOperationCount;
long WriteOperationCount;
long OtherOperationCount;
long ReadTransferCount;
long WriteTransferCount;
long OtherTransferCount;
}
[StructLayout(LayoutKind.Sequential)]
internal class SystemThreadInformation {
long KernelTime;
long UserTime;
long CreateTime;
uint WaitTime;
internal IntPtr StartAddress;
internal IntPtr UniqueProcess;
internal IntPtr UniqueThread;
internal int Priority;
internal int BasePriority;
internal uint ContextSwitches;
internal uint ThreadState;
internal uint WaitReason;
}
#pragma warning restore 169
}
}
#endif // !FEATURE_PAL
|