PageRenderTime 62ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 1ms

/mcs/class/referencesource/System/services/monitoring/system/diagnosticts/ProcessManager.cs

https://github.com/pruiz/mono
C# | 1007 lines | 888 code | 66 blank | 53 comment | 106 complexity | 64f5a0d8739081402c5cca8c8dd8b0bd MD5 | raw file
Possible License(s): LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  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;
  21. /// <devdoc>
  22. /// This class finds the main window of a process. It needs to be
  23. /// class because we need to store state while searching the set
  24. /// of windows.
  25. /// </devdoc>
  26. /// <internalonly/>
  27. internal class MainWindowFinder {
  28. IntPtr bestHandle;
  29. int processId;
  30. [ResourceExposure(ResourceScope.Process)]
  31. [ResourceConsumption(ResourceScope.Process)]
  32. public IntPtr FindMainWindow(int processId) {
  33. bestHandle = (IntPtr)0;
  34. this.processId = processId;
  35. NativeMethods.EnumThreadWindowsCallback callback = new NativeMethods.EnumThreadWindowsCallback(this.EnumWindowsCallback);
  36. NativeMethods.EnumWindows(callback, IntPtr.Zero);
  37. GC.KeepAlive(callback);
  38. return bestHandle;
  39. }
  40. [ResourceExposure(ResourceScope.Process)]
  41. [ResourceConsumption(ResourceScope.Process)]
  42. bool IsMainWindow(IntPtr handle) {
  43. if (NativeMethods.GetWindow(new HandleRef(this, handle), NativeMethods.GW_OWNER) != (IntPtr)0 || !NativeMethods.IsWindowVisible(new HandleRef(this, handle)))
  44. return false;
  45. // Microsoft: should we use no window title to mean not a main window? (task man does)
  46. /*
  47. int length = NativeMethods.GetWindowTextLength(handle) * 2;
  48. StringBuilder builder = new StringBuilder(length);
  49. if (NativeMethods.GetWindowText(handle, builder, builder.Capacity) == 0)
  50. return false;
  51. if (builder.ToString() == string.Empty)
  52. return false;
  53. */
  54. return true;
  55. }
  56. [ResourceExposure(ResourceScope.Machine)]
  57. [ResourceConsumption(ResourceScope.Machine)]
  58. bool EnumWindowsCallback(IntPtr handle, IntPtr extraParameter) {
  59. int processId;
  60. NativeMethods.GetWindowThreadProcessId(new HandleRef(this, handle), out processId);
  61. if (processId == this.processId) {
  62. if (IsMainWindow(handle)) {
  63. bestHandle = handle;
  64. return false;
  65. }
  66. }
  67. return true;
  68. }
  69. }
  70. /// <devdoc>
  71. /// This static class is a platform independent Api for querying information
  72. /// about processes, threads and modules. It delegates to the platform
  73. /// specific classes WinProcessManager for Win9x and NtProcessManager
  74. /// for WinNt.
  75. /// </devdoc>
  76. /// <internalonly/>
  77. internal static class ProcessManager {
  78. [ResourceExposure(ResourceScope.Process)]
  79. [ResourceConsumption(ResourceScope.Process)]
  80. static ProcessManager() {
  81. // In order to query information (OpenProcess) on some protected processes
  82. // like csrss, we need SeDebugPrivilege privilege.
  83. // After removing the depenecy on Performance Counter, we don't have a chance
  84. // to run the code in CLR performance counter to ask for this privilege.
  85. // So we will try to get the privilege here.
  86. // We could fail if the user account doesn't have right to do this, but that's fair.
  87. NativeMethods.LUID luid = new NativeMethods.LUID();
  88. if (!NativeMethods.LookupPrivilegeValue(null, "SeDebugPrivilege", out luid)) {
  89. return;
  90. }
  91. IntPtr tokenHandle = IntPtr.Zero;
  92. try {
  93. if( !NativeMethods.OpenProcessToken(
  94. new HandleRef(null, NativeMethods.GetCurrentProcess()),
  95. (int)TokenAccessLevels.AdjustPrivileges,
  96. out tokenHandle)) {
  97. return;
  98. }
  99. NativeMethods.TokenPrivileges tp = new NativeMethods.TokenPrivileges();
  100. tp.PrivilegeCount = 1;
  101. tp.Luid = luid;
  102. tp.Attributes = NativeMethods.SE_PRIVILEGE_ENABLED;
  103. // AdjustTokenPrivileges can return true even if it didn't succeed (when ERROR_NOT_ALL_ASSIGNED is returned).
  104. NativeMethods.AdjustTokenPrivileges(new HandleRef(null,tokenHandle), false, tp, 0, IntPtr.Zero, IntPtr.Zero);
  105. }
  106. finally {
  107. if( tokenHandle != IntPtr.Zero) {
  108. SafeNativeMethods.CloseHandle(tokenHandle);
  109. }
  110. }
  111. }
  112. public static bool IsNt {
  113. get {
  114. return Environment.OSVersion.Platform == PlatformID.Win32NT;
  115. }
  116. }
  117. public static bool IsOSOlderThanXP {
  118. get {
  119. return Environment.OSVersion.Version.Major < 5 ||
  120. (Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor == 0);
  121. }
  122. }
  123. public static ProcessInfo[] GetProcessInfos(string machineName) {
  124. bool isRemoteMachine = IsRemoteMachine(machineName);
  125. if (IsNt) {
  126. // Do not use performance counter for local machine with Win2000 and above
  127. if( !isRemoteMachine &&
  128. (Environment.OSVersion.Version.Major >= 5 )) {
  129. return NtProcessInfoHelper.GetProcessInfos();
  130. }
  131. return NtProcessManager.GetProcessInfos(machineName, isRemoteMachine);
  132. }
  133. else {
  134. if (isRemoteMachine)
  135. throw new PlatformNotSupportedException(SR.GetString(SR.WinNTRequiredForRemote));
  136. return WinProcessManager.GetProcessInfos();
  137. }
  138. }
  139. [ResourceExposure(ResourceScope.Machine)]
  140. [ResourceConsumption(ResourceScope.Machine)]
  141. public static int[] GetProcessIds() {
  142. if (IsNt)
  143. return NtProcessManager.GetProcessIds();
  144. else {
  145. return WinProcessManager.GetProcessIds();
  146. }
  147. }
  148. [ResourceExposure(ResourceScope.Machine)]
  149. [ResourceConsumption(ResourceScope.Machine)]
  150. public static int[] GetProcessIds(string machineName) {
  151. if (IsRemoteMachine(machineName)) {
  152. if (IsNt) {
  153. return NtProcessManager.GetProcessIds(machineName, true);
  154. }
  155. else {
  156. throw new PlatformNotSupportedException(SR.GetString(SR.WinNTRequiredForRemote));
  157. }
  158. }
  159. else {
  160. return GetProcessIds();
  161. }
  162. }
  163. [ResourceExposure(ResourceScope.None)]
  164. [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
  165. public static bool IsProcessRunning(int processId, string machineName) {
  166. return IsProcessRunning(processId, GetProcessIds(machineName));
  167. }
  168. [ResourceExposure(ResourceScope.None)]
  169. [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
  170. public static bool IsProcessRunning(int processId) {
  171. return IsProcessRunning(processId, GetProcessIds());
  172. }
  173. static bool IsProcessRunning(int processId, int[] processIds) {
  174. for (int i = 0; i < processIds.Length; i++)
  175. if (processIds[i] == processId)
  176. return true;
  177. return false;
  178. }
  179. [ResourceExposure(ResourceScope.Machine)]
  180. [ResourceConsumption(ResourceScope.Machine)]
  181. public static int GetProcessIdFromHandle(SafeProcessHandle processHandle) {
  182. if (IsNt)
  183. return NtProcessManager.GetProcessIdFromHandle(processHandle);
  184. else
  185. throw new PlatformNotSupportedException(SR.GetString(SR.WinNTRequired));
  186. }
  187. [ResourceExposure(ResourceScope.Machine)]
  188. [ResourceConsumption(ResourceScope.Machine)]
  189. public static IntPtr GetMainWindowHandle(int processId) {
  190. MainWindowFinder finder = new MainWindowFinder();
  191. return finder.FindMainWindow(processId);
  192. }
  193. [ResourceExposure(ResourceScope.Process)]
  194. [ResourceConsumption(ResourceScope.Process)]
  195. public static ModuleInfo[] GetModuleInfos(int processId) {
  196. if (IsNt)
  197. return NtProcessManager.GetModuleInfos(processId);
  198. else
  199. return WinProcessManager.GetModuleInfos(processId);
  200. }
  201. [ResourceExposure(ResourceScope.Machine)]
  202. [ResourceConsumption(ResourceScope.Machine)]
  203. public static SafeProcessHandle OpenProcess(int processId, int access, bool throwIfExited) {
  204. SafeProcessHandle processHandle = NativeMethods.OpenProcess(access, false, processId);
  205. int result = Marshal.GetLastWin32Error();
  206. if (!processHandle.IsInvalid) {
  207. return processHandle;
  208. }
  209. if (processId == 0) {
  210. throw new Win32Exception(5);
  211. }
  212. // If the handle is invalid because the process has exited, only throw an exception if throwIfExited is true.
  213. if (!IsProcessRunning(processId)) {
  214. if (throwIfExited) {
  215. throw new InvalidOperationException(SR.GetString(SR.ProcessHasExited, processId.ToString(CultureInfo.CurrentCulture)));
  216. }
  217. else {
  218. return SafeProcessHandle.InvalidHandle;
  219. }
  220. }
  221. throw new Win32Exception(result);
  222. }
  223. [ResourceExposure(ResourceScope.Process)]
  224. [ResourceConsumption(ResourceScope.Process)]
  225. public static SafeThreadHandle OpenThread(int threadId, int access) {
  226. try {
  227. SafeThreadHandle threadHandle = NativeMethods.OpenThread(access, false, threadId);
  228. int result = Marshal.GetLastWin32Error();
  229. if (threadHandle.IsInvalid) {
  230. if (result == NativeMethods.ERROR_INVALID_PARAMETER)
  231. throw new InvalidOperationException(SR.GetString(SR.ThreadExited, threadId.ToString(CultureInfo.CurrentCulture)));
  232. throw new Win32Exception(result);
  233. }
  234. return threadHandle;
  235. }
  236. catch (EntryPointNotFoundException x) {
  237. throw new PlatformNotSupportedException(SR.GetString(SR.Win2000Required), x);
  238. }
  239. }
  240. public static bool IsRemoteMachine(string machineName) {
  241. if (machineName == null)
  242. throw new ArgumentNullException("machineName");
  243. if (machineName.Length == 0)
  244. throw new ArgumentException(SR.GetString(SR.InvalidParameter, "machineName", machineName));
  245. string baseName;
  246. if (machineName.StartsWith("\\", StringComparison.Ordinal))
  247. baseName = machineName.Substring(2);
  248. else
  249. baseName = machineName;
  250. if (baseName.Equals(".")) return false;
  251. StringBuilder sb = new StringBuilder(256);
  252. SafeNativeMethods.GetComputerName(sb, new int[] {sb.Capacity});
  253. string computerName = sb.ToString();
  254. if (String.Compare(computerName, baseName, StringComparison.OrdinalIgnoreCase) == 0) return false;
  255. return true;
  256. }
  257. }
  258. /// <devdoc>
  259. /// This static class provides the process api for the Win9x platform.
  260. /// We use the toolhelp32 api to query process, thread and module information.
  261. /// </devdoc>
  262. /// <internalonly/>
  263. internal static class WinProcessManager {
  264. // This is expensive. We should specialize getprocessinfos and only get
  265. // the ids instead of getting all the info and then copying the ids out.
  266. public static int[] GetProcessIds() {
  267. ProcessInfo[] infos = GetProcessInfos();
  268. int[] ids = new int[infos.Length];
  269. for (int i = 0; i < infos.Length; i++) {
  270. ids[i] = infos[i].processId;
  271. }
  272. return ids;
  273. }
  274. [ResourceExposure(ResourceScope.None)]
  275. [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
  276. public static ProcessInfo[] GetProcessInfos() {
  277. IntPtr handle = (IntPtr)(-1);
  278. GCHandle bufferHandle = new GCHandle();
  279. ArrayList threadInfos = new ArrayList();
  280. Hashtable processInfos = new Hashtable();
  281. try {
  282. handle = NativeMethods.CreateToolhelp32Snapshot(NativeMethods.TH32CS_SNAPPROCESS | NativeMethods.TH32CS_SNAPTHREAD, 0);
  283. if (handle == (IntPtr)(-1)) throw new Win32Exception();
  284. int entrySize = (int)Marshal.SizeOf(typeof(NativeMethods.WinProcessEntry));
  285. int bufferSize = entrySize + NativeMethods.WinProcessEntry.sizeofFileName;
  286. int[] buffer = new int[bufferSize / 4];
  287. bufferHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
  288. IntPtr bufferPtr = bufferHandle.AddrOfPinnedObject();
  289. Marshal.WriteInt32(bufferPtr, bufferSize);
  290. HandleRef handleRef = new HandleRef(null, handle);
  291. if (NativeMethods.Process32First(handleRef, bufferPtr)) {
  292. do {
  293. NativeMethods.WinProcessEntry process = new NativeMethods.WinProcessEntry();
  294. Marshal.PtrToStructure(bufferPtr, process);
  295. ProcessInfo processInfo = new ProcessInfo();
  296. String name = Marshal.PtrToStringAnsi((IntPtr)((long)bufferPtr + entrySize));
  297. processInfo.processName = Path.ChangeExtension(Path.GetFileName(name), null);
  298. processInfo.handleCount = process.cntUsage;
  299. processInfo.processId = process.th32ProcessID;
  300. processInfo.basePriority = process.pcPriClassBase;
  301. processInfo.mainModuleId = process.th32ModuleID;
  302. processInfos.Add(processInfo.processId, processInfo);
  303. Marshal.WriteInt32(bufferPtr, bufferSize);
  304. }
  305. while (NativeMethods.Process32Next(handleRef, bufferPtr));
  306. }
  307. NativeMethods.WinThreadEntry thread = new NativeMethods.WinThreadEntry();
  308. thread.dwSize = Marshal.SizeOf(thread);
  309. if (NativeMethods.Thread32First(handleRef, thread)) {
  310. do {
  311. ThreadInfo threadInfo = new ThreadInfo();
  312. threadInfo.threadId = thread.th32ThreadID;
  313. threadInfo.processId = thread.th32OwnerProcessID;
  314. threadInfo.basePriority = thread.tpBasePri;
  315. threadInfo.currentPriority = thread.tpBasePri + thread.tpDeltaPri;
  316. threadInfos.Add(threadInfo);
  317. }
  318. while (NativeMethods.Thread32Next(handleRef, thread));
  319. }
  320. for (int i = 0; i < threadInfos.Count; i++) {
  321. ThreadInfo threadInfo = (ThreadInfo)threadInfos[i];
  322. ProcessInfo processInfo = (ProcessInfo)processInfos[threadInfo.processId];
  323. if (processInfo != null)
  324. processInfo.threadInfoList.Add(threadInfo);
  325. //else
  326. // throw new InvalidOperationException(SR.GetString(SR.ProcessNotFound, threadInfo.threadId.ToString(), threadInfo.processId.ToString()));
  327. }
  328. }
  329. finally {
  330. if (bufferHandle.IsAllocated) bufferHandle.Free();
  331. Debug.WriteLineIf(Process.processTracing.TraceVerbose, "Process - CloseHandle(toolhelp32 snapshot handle)");
  332. if (handle != (IntPtr)(-1)) SafeNativeMethods.CloseHandle(handle);
  333. }
  334. ProcessInfo[] temp = new ProcessInfo[processInfos.Values.Count];
  335. processInfos.Values.CopyTo(temp, 0);
  336. return temp;
  337. }
  338. [ResourceExposure(ResourceScope.Process)]
  339. [ResourceConsumption(ResourceScope.Process)]
  340. public static ModuleInfo[] GetModuleInfos(int processId) {
  341. IntPtr handle = (IntPtr)(-1);
  342. GCHandle bufferHandle = new GCHandle();
  343. ArrayList moduleInfos = new ArrayList();
  344. try {
  345. handle = NativeMethods.CreateToolhelp32Snapshot(NativeMethods.TH32CS_SNAPMODULE, processId);
  346. if (handle == (IntPtr)(-1)) throw new Win32Exception();
  347. int entrySize = Marshal.SizeOf(typeof(NativeMethods.WinModuleEntry));
  348. int bufferSize = entrySize + NativeMethods.WinModuleEntry.sizeofFileName + NativeMethods.WinModuleEntry.sizeofModuleName;
  349. int[] buffer = new int[bufferSize / 4];
  350. bufferHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
  351. IntPtr bufferPtr = bufferHandle.AddrOfPinnedObject();
  352. Marshal.WriteInt32(bufferPtr, bufferSize);
  353. HandleRef handleRef = new HandleRef(null, handle);
  354. if (NativeMethods.Module32First(handleRef, bufferPtr)) {
  355. do {
  356. NativeMethods.WinModuleEntry module = new NativeMethods.WinModuleEntry();
  357. Marshal.PtrToStructure(bufferPtr, module);
  358. ModuleInfo moduleInfo = new ModuleInfo();
  359. moduleInfo.baseName = Marshal.PtrToStringAnsi((IntPtr)((long)bufferPtr + entrySize));
  360. moduleInfo.fileName = Marshal.PtrToStringAnsi((IntPtr)((long)bufferPtr + entrySize + NativeMethods.WinModuleEntry.sizeofModuleName));
  361. moduleInfo.baseOfDll = module.modBaseAddr;
  362. moduleInfo.sizeOfImage = module.modBaseSize;
  363. moduleInfo.Id = module.th32ModuleID;
  364. moduleInfos.Add(moduleInfo);
  365. Marshal.WriteInt32(bufferPtr, bufferSize);
  366. }
  367. while (NativeMethods.Module32Next(handleRef, bufferPtr));
  368. }
  369. }
  370. finally {
  371. if (bufferHandle.IsAllocated) bufferHandle.Free();
  372. Debug.WriteLineIf(Process.processTracing.TraceVerbose, "Process - CloseHandle(toolhelp32 snapshot handle)");
  373. if (handle != (IntPtr)(-1)) SafeNativeMethods.CloseHandle(handle);
  374. }
  375. ModuleInfo[] temp = new ModuleInfo[moduleInfos.Count];
  376. moduleInfos.CopyTo(temp, 0);
  377. return temp;
  378. }
  379. }
  380. /// <devdoc>
  381. /// This static class provides the process api for the WinNt platform.
  382. /// We use the performance counter api to query process and thread
  383. /// information. Module information is obtained using PSAPI.
  384. /// </devdoc>
  385. /// <internalonly/>
  386. internal static class NtProcessManager {
  387. private const int ProcessPerfCounterId = 230;
  388. private const int ThreadPerfCounterId = 232;
  389. private const string PerfCounterQueryString = "230 232";
  390. internal const int IdleProcessID = 0;
  391. static Hashtable valueIds;
  392. static NtProcessManager() {
  393. valueIds = new Hashtable();
  394. valueIds.Add("Handle Count", ValueId.HandleCount);
  395. valueIds.Add("Pool Paged Bytes", ValueId.PoolPagedBytes);
  396. valueIds.Add("Pool Nonpaged Bytes", ValueId.PoolNonpagedBytes);
  397. valueIds.Add("Elapsed Time", ValueId.ElapsedTime);
  398. valueIds.Add("Virtual Bytes Peak", ValueId.VirtualBytesPeak);
  399. valueIds.Add("Virtual Bytes", ValueId.VirtualBytes);
  400. valueIds.Add("Private Bytes", ValueId.PrivateBytes);
  401. valueIds.Add("Page File Bytes", ValueId.PageFileBytes);
  402. valueIds.Add("Page File Bytes Peak", ValueId.PageFileBytesPeak);
  403. valueIds.Add("Working Set Peak", ValueId.WorkingSetPeak);
  404. valueIds.Add("Working Set", ValueId.WorkingSet);
  405. valueIds.Add("ID Thread", ValueId.ThreadId);
  406. valueIds.Add("ID Process", ValueId.ProcessId);
  407. valueIds.Add("Priority Base", ValueId.BasePriority);
  408. valueIds.Add("Priority Current", ValueId.CurrentPriority);
  409. valueIds.Add("% User Time", ValueId.UserTime);
  410. valueIds.Add("% Privileged Time", ValueId.PrivilegedTime);
  411. valueIds.Add("Start Address", ValueId.StartAddress);
  412. valueIds.Add("Thread State", ValueId.ThreadState);
  413. valueIds.Add("Thread Wait Reason", ValueId.ThreadWaitReason);
  414. }
  415. internal static int SystemProcessID {
  416. get {
  417. const int systemProcessIDOnXP = 4;
  418. const int systemProcessIDOn2K = 8;
  419. if( ProcessManager.IsOSOlderThanXP) {
  420. return systemProcessIDOn2K;
  421. }
  422. else {
  423. return systemProcessIDOnXP;
  424. }
  425. }
  426. }
  427. [ResourceExposure(ResourceScope.Machine)]
  428. [ResourceConsumption(ResourceScope.Machine)]
  429. public static int[] GetProcessIds(string machineName, bool isRemoteMachine) {
  430. ProcessInfo[] infos = GetProcessInfos(machineName, isRemoteMachine);
  431. int[] ids = new int[infos.Length];
  432. for (int i = 0; i < infos.Length; i++)
  433. ids[i] = infos[i].processId;
  434. return ids;
  435. }
  436. [ResourceExposure(ResourceScope.Machine)]
  437. [ResourceConsumption(ResourceScope.Machine)]
  438. public static int[] GetProcessIds() {
  439. int[] processIds = new int[256];
  440. int size;
  441. for (;;) {
  442. if (!NativeMethods.EnumProcesses(processIds, processIds.Length * 4, out size))
  443. throw new Win32Exception();
  444. if (size == processIds.Length * 4) {
  445. processIds = new int[processIds.Length * 2];
  446. continue;
  447. }
  448. break;
  449. }
  450. int[] ids = new int[size / 4];
  451. Array.Copy(processIds, ids, ids.Length);
  452. return ids;
  453. }
  454. [ResourceExposure(ResourceScope.Process)]
  455. [ResourceConsumption(ResourceScope.Process)]
  456. public static ModuleInfo[] GetModuleInfos(int processId) {
  457. return GetModuleInfos(processId, false);
  458. }
  459. [ResourceExposure(ResourceScope.Process)]
  460. [ResourceConsumption(ResourceScope.Process)]
  461. public static ModuleInfo GetFirstModuleInfo(int processId) {
  462. ModuleInfo[] moduleInfos = GetModuleInfos(processId, true);
  463. if( moduleInfos.Length == 0) {
  464. return null;
  465. }
  466. else {
  467. return moduleInfos[0];
  468. }
  469. }
  470. [ResourceExposure(ResourceScope.None)]
  471. [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
  472. private static ModuleInfo[] GetModuleInfos(int processId, bool firstModuleOnly) {
  473. Contract.Ensures(Contract.Result<ModuleInfo[]>().Length >= 1);
  474. // preserving Everett behavior.
  475. if( processId == SystemProcessID || processId == IdleProcessID) {
  476. // system process and idle process doesn't have any modules
  477. throw new Win32Exception(HResults.EFail,SR.GetString(SR.EnumProcessModuleFailed));
  478. }
  479. SafeProcessHandle processHandle = SafeProcessHandle.InvalidHandle;
  480. try {
  481. processHandle = ProcessManager.OpenProcess(processId, NativeMethods.PROCESS_QUERY_INFORMATION | NativeMethods.PROCESS_VM_READ, true);
  482. IntPtr[] moduleHandles = new IntPtr[64];
  483. GCHandle moduleHandlesArrayHandle = new GCHandle();
  484. int moduleCount = 0;
  485. for (;;) {
  486. bool enumResult = false;
  487. try {
  488. moduleHandlesArrayHandle = GCHandle.Alloc(moduleHandles, GCHandleType.Pinned);
  489. enumResult = NativeMethods.EnumProcessModules(processHandle, moduleHandlesArrayHandle.AddrOfPinnedObject(), moduleHandles.Length * IntPtr.Size, ref moduleCount);
  490. // The API we need to use to enumerate process modules differs on two factors:
  491. // 1) If our process is running in WOW64.
  492. // 2) The bitness of the process we wish to introspect.
  493. //
  494. // If we are not running in WOW64 or we ARE in WOW64 but want to inspect a 32 bit process
  495. // we can call psapi!EnumProcessModules.
  496. //
  497. // If we are running in WOW64 and we want to inspect the modules of a 64 bit process then
  498. // psapi!EnumProcessModules will return false with ERROR_PARTIAL_COPY (299). In this case we can't
  499. // do the enumeration at all. So we'll detect this case and bail out.
  500. //
  501. // Also, EnumProcessModules is not a reliable method to get the modules for a process.
  502. // If OS loader is touching module information, this method might fail and copy part of the data.
  503. // This is no easy solution to this problem. The only reliable way to fix this is to
  504. // suspend all the threads in target process. Of course we don't want to do this in Process class.
  505. // So we just to try avoid the ---- by calling the same method 50 (an arbitary number) times.
  506. //
  507. if (!enumResult) {
  508. bool sourceProcessIsWow64 = false;
  509. bool targetProcessIsWow64 = false;
  510. if (!ProcessManager.IsOSOlderThanXP) {
  511. SafeProcessHandle hCurProcess = SafeProcessHandle.InvalidHandle;
  512. try {
  513. hCurProcess = ProcessManager.OpenProcess(NativeMethods.GetCurrentProcessId(), NativeMethods.PROCESS_QUERY_INFORMATION, true);
  514. bool wow64Ret;
  515. wow64Ret = SafeNativeMethods.IsWow64Process(hCurProcess, ref sourceProcessIsWow64);
  516. if (!wow64Ret) {
  517. throw new Win32Exception();
  518. }
  519. wow64Ret = SafeNativeMethods.IsWow64Process(processHandle, ref targetProcessIsWow64);
  520. if (!wow64Ret) {
  521. throw new Win32Exception();
  522. }
  523. if (sourceProcessIsWow64 && !targetProcessIsWow64) {
  524. // Wow64 isn't going to allow this to happen, the best we can do is give a descriptive error to the user.
  525. throw new Win32Exception(NativeMethods.ERROR_PARTIAL_COPY, SR.GetString(SR.EnumProcessModuleFailedDueToWow));
  526. }
  527. } finally {
  528. if (hCurProcess != SafeProcessHandle.InvalidHandle) {
  529. hCurProcess.Close();
  530. }
  531. }
  532. }
  533. // If the failure wasn't due to Wow64, try again.
  534. for (int i = 0; i < 50; i++) {
  535. enumResult = NativeMethods.EnumProcessModules(processHandle, moduleHandlesArrayHandle.AddrOfPinnedObject(), moduleHandles.Length * IntPtr.Size, ref moduleCount);
  536. if (enumResult) {
  537. break;
  538. }
  539. Thread.Sleep(1);
  540. }
  541. }
  542. }
  543. finally {
  544. moduleHandlesArrayHandle.Free();
  545. }
  546. if (!enumResult) {
  547. throw new Win32Exception();
  548. }
  549. moduleCount /= IntPtr.Size;
  550. if (moduleCount <= moduleHandles.Length) break;
  551. moduleHandles = new IntPtr[moduleHandles.Length * 2];
  552. }
  553. ArrayList moduleInfos = new ArrayList();
  554. int ret;
  555. for (int i = 0; i < moduleCount; i++) {
  556. try
  557. {
  558. ModuleInfo moduleInfo = new ModuleInfo();
  559. IntPtr moduleHandle = moduleHandles[i];
  560. NativeMethods.NtModuleInfo ntModuleInfo = new NativeMethods.NtModuleInfo();
  561. if (!NativeMethods.GetModuleInformation(processHandle, new HandleRef(null, moduleHandle), ntModuleInfo, Marshal.SizeOf(ntModuleInfo)))
  562. throw new Win32Exception();
  563. moduleInfo.sizeOfImage = ntModuleInfo.SizeOfImage;
  564. moduleInfo.entryPoint = ntModuleInfo.EntryPoint;
  565. moduleInfo.baseOfDll = ntModuleInfo.BaseOfDll;
  566. StringBuilder baseName = new StringBuilder(1024);
  567. ret = NativeMethods.GetModuleBaseName(processHandle, new HandleRef(null, moduleHandle), baseName, baseName.Capacity * 2);
  568. if (ret == 0) throw new Win32Exception();
  569. moduleInfo.baseName = baseName.ToString();
  570. StringBuilder fileName = new StringBuilder(1024);
  571. ret = NativeMethods.GetModuleFileNameEx(processHandle, new HandleRef(null, moduleHandle), fileName, fileName.Capacity * 2);
  572. if (ret == 0) throw new Win32Exception();
  573. moduleInfo.fileName = fileName.ToString();
  574. // smss.exe is started before the win32 subsystem so it get this funny "\systemroot\.." path.
  575. // We change this to the actual path by appending "smss.exe" to GetSystemDirectory()
  576. if (string.Compare(moduleInfo.fileName, "\\SystemRoot\\System32\\smss.exe", StringComparison.OrdinalIgnoreCase) == 0) {
  577. moduleInfo.fileName = Path.Combine(Environment.SystemDirectory, "smss.exe");
  578. }
  579. // Avoid returning Unicode-style long string paths. IO methods cannot handle them.
  580. if (moduleInfo.fileName != null
  581. && moduleInfo.fileName.Length >= 4
  582. && moduleInfo.fileName.StartsWith(@"\\?\", StringComparison.Ordinal)) {
  583. moduleInfo.fileName = moduleInfo.fileName.Substring(4);
  584. }
  585. moduleInfos.Add(moduleInfo);
  586. }
  587. catch (Win32Exception e)
  588. {
  589. if (e.NativeErrorCode == NativeMethods.ERROR_INVALID_HANDLE || e.NativeErrorCode == NativeMethods.ERROR_PARTIAL_COPY)
  590. {
  591. // It's possible that another thread casued this module to become
  592. // unloaded (e.g FreeLibrary was called on the module). Ignore it and
  593. // move on.
  594. }
  595. else
  596. {
  597. throw;
  598. }
  599. }
  600. //
  601. // If the user is only interested in the main module, break now.
  602. // This avoid some waste of time. In addition, if the application unloads a DLL
  603. // we will not get an exception.
  604. //
  605. if( firstModuleOnly) { break; }
  606. }
  607. ModuleInfo[] temp = new ModuleInfo[moduleInfos.Count];
  608. moduleInfos.CopyTo(temp, 0);
  609. return temp;
  610. }
  611. finally {
  612. Debug.WriteLineIf(Process.processTracing.TraceVerbose, "Process - CloseHandle(process)");
  613. if (!processHandle.IsInvalid ) {
  614. processHandle.Close();
  615. }
  616. }
  617. }
  618. [ResourceExposure(ResourceScope.Machine)]
  619. [ResourceConsumption(ResourceScope.Machine)]
  620. public static int GetProcessIdFromHandle(SafeProcessHandle processHandle) {
  621. NativeMethods.NtProcessBasicInfo info = new NativeMethods.NtProcessBasicInfo();
  622. int status = NativeMethods.NtQueryInformationProcess(processHandle, NativeMethods.NtQueryProcessBasicInfo, info, (int)Marshal.SizeOf(info), null);
  623. if (status != 0) {
  624. throw new InvalidOperationException(SR.GetString(SR.CantGetProcessId), new Win32Exception(status));
  625. }
  626. // We should change the signature of this function and ID property in process class.
  627. return info.UniqueProcessId.ToInt32();
  628. }
  629. public static ProcessInfo[] GetProcessInfos(string machineName, bool isRemoteMachine) {
  630. // We demand unmanaged code here because PerformanceCounterLib doesn't demand
  631. // anything. This is the only place we do GetPerformanceCounterLib, and it isn't cached.
  632. new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand();
  633. PerformanceCounterLib library = null;
  634. try {
  635. library = PerformanceCounterLib.GetPerformanceCounterLib(machineName, new CultureInfo(0x009));
  636. return GetProcessInfos(library);
  637. }
  638. catch(Exception e) {
  639. if( isRemoteMachine) {
  640. throw new InvalidOperationException(SR.GetString(SR.CouldntConnectToRemoteMachine), e);
  641. }
  642. else {
  643. throw e;
  644. }
  645. }
  646. // We don't want to call library.Close() here because that would cause us to unload all of the perflibs.
  647. // On the next call to GetProcessInfos, we'd have to load them all up again, which is SLOW!
  648. }
  649. static ProcessInfo[] GetProcessInfos(PerformanceCounterLib library) {
  650. ProcessInfo[] processInfos = new ProcessInfo[0] ;
  651. byte[] dataPtr = null;
  652. int retryCount = 5;
  653. while (processInfos.Length == 0 && retryCount != 0) {
  654. try {
  655. dataPtr = library.GetPerformanceData(PerfCounterQueryString);
  656. processInfos = GetProcessInfos(library, ProcessPerfCounterId, ThreadPerfCounterId, dataPtr);
  657. }
  658. catch (Exception e) {
  659. throw new InvalidOperationException(SR.GetString(SR.CouldntGetProcessInfos), e);
  660. }
  661. --retryCount;
  662. }
  663. if (processInfos.Length == 0)
  664. throw new InvalidOperationException(SR.GetString(SR.ProcessDisabled));
  665. return processInfos;
  666. }
  667. static ProcessInfo[] GetProcessInfos(PerformanceCounterLib library, int processIndex, int threadIndex, byte[] data) {
  668. Debug.WriteLineIf(Process.processTracing.TraceVerbose, "GetProcessInfos()");
  669. Hashtable processInfos = new Hashtable();
  670. ArrayList threadInfos = new ArrayList();
  671. GCHandle dataHandle = new GCHandle();
  672. try {
  673. dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
  674. IntPtr dataBlockPtr = dataHandle.AddrOfPinnedObject();
  675. NativeMethods.PERF_DATA_BLOCK dataBlock = new NativeMethods.PERF_DATA_BLOCK();
  676. Marshal.PtrToStructure(dataBlockPtr, dataBlock);
  677. IntPtr typePtr = (IntPtr)((long)dataBlockPtr + dataBlock.HeaderLength);
  678. NativeMethods.PERF_INSTANCE_DEFINITION instance = new NativeMethods.PERF_INSTANCE_DEFINITION();
  679. NativeMethods.PERF_COUNTER_BLOCK counterBlock = new NativeMethods.PERF_COUNTER_BLOCK();
  680. for (int i = 0; i < dataBlock.NumObjectTypes; i++) {
  681. NativeMethods.PERF_OBJECT_TYPE type = new NativeMethods.PERF_OBJECT_TYPE();
  682. Marshal.PtrToStructure(typePtr, type);
  683. IntPtr instancePtr = (IntPtr)((long)typePtr + type.DefinitionLength);
  684. IntPtr counterPtr = (IntPtr)((long)typePtr + type.HeaderLength);
  685. ArrayList counterList = new ArrayList();
  686. for (int j = 0; j < type.NumCounters; j++) {
  687. NativeMethods.PERF_COUNTER_DEFINITION counter = new NativeMethods.PERF_COUNTER_DEFINITION();
  688. Marshal.PtrToStructure(counterPtr, counter);
  689. string counterName = library.GetCounterName(counter.CounterNameTitleIndex);
  690. if (type.ObjectNameTitleIndex == processIndex)
  691. counter.CounterNameTitlePtr = (int)GetValueId(counterName);
  692. else if (type.ObjectNameTitleIndex == threadIndex)
  693. counter.CounterNameTitlePtr = (int)GetValueId(counterName);
  694. counterList.Add(counter);
  695. counterPtr = (IntPtr)((long)counterPtr + counter.ByteLength);
  696. }
  697. NativeMethods.PERF_COUNTER_DEFINITION[] counters = new NativeMethods.PERF_COUNTER_DEFINITION[counterList.Count];
  698. counterList.CopyTo(counters, 0);
  699. for (int j = 0; j < type.NumInstances; j++) {
  700. Marshal.PtrToStructure(instancePtr, instance);
  701. IntPtr namePtr = (IntPtr)((long)instancePtr + instance.NameOffset);
  702. string instanceName = Marshal.PtrToStringUni(namePtr);
  703. if (instanceName.Equals("_Total")) continue;
  704. IntPtr counterBlockPtr = (IntPtr)((long)instancePtr + instance.ByteLength);
  705. Marshal.PtrToStructure(counterBlockPtr, counterBlock);
  706. if (type.ObjectNameTitleIndex == processIndex) {
  707. ProcessInfo processInfo = GetProcessInfo(type, (IntPtr)((long)instancePtr + instance.ByteLength), counters);
  708. if (processInfo.processId == 0 && string.Compare(instanceName, "Idle", StringComparison.OrdinalIgnoreCase) != 0) {
  709. // Sometimes we'll get a process structure that is not completely filled in.
  710. // We can catch some of these by looking for non-"idle" processes that have id 0
  711. // and ignoring those.
  712. Debug.WriteLineIf(Process.processTracing.TraceVerbose, "GetProcessInfos() - found a non-idle process with id 0; ignoring.");
  713. }
  714. else {
  715. if (processInfos[processInfo.processId] != null) {
  716. // We've found two entries in the perfcounters that claim to be the
  717. // same process. We throw an exception. Is this really going to be
  718. // helpfull to the user? Should we just ignore?
  719. Debug.WriteLineIf(Process.processTracing.TraceVerbose, "GetProcessInfos() - found a duplicate process id");
  720. }
  721. else {
  722. // the performance counters keep a 15 character prefix of the exe name, and then delete the ".exe",
  723. // if it's in the first 15. The problem is that sometimes that will leave us with part of ".exe"
  724. // at the end. If instanceName ends in ".", ".e", or ".ex" we remove it.
  725. string processName = instanceName;
  726. if (processName.Length == 15) {
  727. if (instanceName.EndsWith(".", StringComparison.Ordinal )) processName = instanceName.Substring(0, 14);
  728. else if (instanceName.EndsWith(".e", StringComparison.Ordinal )) processName = instanceName.Substring(0, 13);
  729. else if (instanceName.EndsWith(".ex", StringComparison.Ordinal)) processName = instanceName.Substring(0, 12);
  730. }
  731. processInfo.processName = processName;
  732. processInfos.Add(processInfo.processId, processInfo);
  733. }
  734. }
  735. }
  736. else if (type.ObjectNameTitleIndex == threadIndex) {
  737. ThreadInfo threadInfo = GetThreadInfo(type, (IntPtr)((long)instancePtr + instance.ByteLength), counters);
  738. if (threadInfo.threadId != 0) threadInfos.Add(threadInfo);
  739. }
  740. instancePtr = (IntPtr)((long)instancePtr + instance.ByteLength + counterBlock.ByteLength);
  741. }
  742. typePtr = (IntPtr)((long)typePtr + type.TotalByteLength);
  743. }
  744. }
  745. finally {
  746. if (dataHandle.IsAllocated) dataHandle.Free();
  747. }
  748. for (int i = 0; i < threadInfos.Count; i++) {
  749. ThreadInfo threadInfo = (ThreadInfo)threadInfos[i];
  750. ProcessInfo processInfo = (ProcessInfo)processInfos[threadInfo.processId];
  751. if (processInfo != null) {
  752. processInfo.threadInfoList.Add(threadInfo);
  753. }
  754. }
  755. ProcessInfo[] temp = new ProcessInfo[processInfos.Values.Count];
  756. processInfos.Values.CopyTo(temp, 0);
  757. return temp;
  758. }
  759. static ThreadInfo GetThreadInfo(NativeMethods.PERF_OBJECT_TYPE type, IntPtr instancePtr, NativeMethods.PERF_COUNTER_DEFINITION[] counters) {
  760. ThreadInfo threadInfo = new ThreadInfo();
  761. for (int i = 0; i < counters.Length; i++) {
  762. NativeMethods.PERF_COUNTER_DEFINITION counter = counters[i];
  763. long value = ReadCounterValue(counter.CounterType, (IntPtr)((long)instancePtr + counter.CounterOffset));
  764. switch ((ValueId)counter.CounterNameTitlePtr) {
  765. case ValueId.ProcessId:
  766. threadInfo.processId = (int)value;
  767. break;
  768. case ValueId.ThreadId:
  769. threadInfo.threadId = (int)value;
  770. break;
  771. case ValueId.BasePriority:
  772. threadInfo.basePriority = (int)value;
  773. break;
  774. case ValueId.CurrentPriority:
  775. threadInfo.currentPriority = (int)value;
  776. break;
  777. case ValueId.StartAddress:
  778. threadInfo.startAddress = (IntPtr)value;
  779. break;
  780. case ValueId.ThreadState:
  781. threadInfo.threadState = (ThreadState)value;
  782. break;
  783. case ValueId.ThreadWaitReason:
  784. threadInfo.threadWaitReason = GetThreadWaitReason((int)value);
  785. break;
  786. }
  787. }
  788. return threadInfo;
  789. }
  790. internal static ThreadWaitReason GetThreadWaitReason(int value) {
  791. switch (value) {
  792. case 0:
  793. case 7: return ThreadWaitReason.Executive;
  794. case 1:
  795. case 8: return ThreadWaitReason.FreePage;
  796. case 2:
  797. case 9: return ThreadWaitReason.PageIn;
  798. case 3:
  799. case 10: return ThreadWaitReason.SystemAllocation;
  800. case 4:
  801. case 11: return ThreadWaitReason.ExecutionDelay;
  802. case 5:
  803. case 12: return ThreadWaitReason.Suspended;
  804. case 6:
  805. case 13: return ThreadWaitReason.UserRequest;
  806. case 14: return ThreadWaitReason.EventPairHigh;;
  807. case 15: return ThreadWaitReason.EventPairLow;
  808. case 16: return ThreadWaitReason.LpcReceive;
  809. case 17: return ThreadWaitReason.LpcReply;
  810. case 18: return ThreadWaitReason.VirtualMemory;
  811. case 19: return ThreadWaitReason.PageOut;
  812. default: return ThreadWaitReason.Unknown;
  813. }
  814. }
  815. static ProcessInfo GetProcessInfo(NativeMethods.PERF_OBJECT_TYPE type, IntPtr instancePtr, NativeMethods.PERF_COUNTER_DEFINITION[] counters) {
  816. ProcessInfo processInfo = new ProcessInfo();
  817. for (int i = 0; i < counters.Length; i++) {
  818. NativeMethods.PERF_COUNTER_DEFINITION counter = counters[i];
  819. long value = ReadCounterValue(counter.CounterType, (IntPtr)((long)instancePtr + counter.CounterOffset));
  820. switch ((ValueId)counter.CounterNameTitlePtr) {
  821. case ValueId.ProcessId:
  822. processInfo.processId = (int)value;
  823. break;
  824. case ValueId.HandleCount:
  825. processInfo.handleCount = (int)value;
  826. break;
  827. case ValueId.PoolPagedBytes:
  828. processInfo.poolPagedBytes = value;
  829. break;
  830. case ValueId.PoolNonpagedBytes:
  831. processInfo.poolNonpagedBytes = value;
  832. break;
  833. case ValueId.VirtualBytes:
  834. processInfo.virtualBytes = value;
  835. break;
  836. case ValueId.VirtualBytesPeak:
  837. processInfo.virtualBytesPeak = value;
  838. break;
  839. case ValueId.WorkingSetPeak:
  840. processInfo.workingSetPeak = value;
  841. break;
  842. case ValueId.WorkingSet:
  843. processInfo.workingSet = value;
  844. break;
  845. case ValueId.PageFileBytesPeak:
  846. processInfo.pageFileBytesPeak = value;
  847. break;
  848. case ValueId.PageFileBytes:
  849. processInfo.pageFileBytes = value;
  850. break;
  851. case ValueId.PrivateBytes:
  852. processInfo.privateBytes = value;
  853. break;
  854. case ValueId.BasePriority:
  855. processInfo.basePriority = (int)value;
  856. break;
  857. }
  858. }
  859. return processInfo;
  860. }
  861. static ValueId GetValueId(string counterName) {
  862. if (counterName != null) {
  863. object id = valueIds[counterName];
  864. if (id != null)
  865. return(ValueId)id;
  866. }
  867. return ValueId.Unknown;
  868. }
  869. static long ReadCounterValue(int counterType, IntPtr dataPtr) {
  870. if ((counterType & NativeMethods.NtPerfCounterSizeLarge) != 0)
  871. return Marshal.ReadInt64(dataPtr);
  872. else
  873. return(long)Marshal.ReadInt32(dataPtr);
  874. }
  875. enum ValueId {
  876. Unknown = -1,
  877. HandleCount,
  878. PoolPagedBytes,
  879. PoolNonpagedBytes,
  880. ElapsedTime,
  881. VirtualBytesPeak,
  882. VirtualBytes,
  883. PrivateBytes,
  884. PageFileBytes,
  885. PageFileBytesPeak,
  886. WorkingSetPeak,
  887. WorkingSet,
  888. ThreadId,
  889. ProcessId,
  890. BasePriority,
  891. CurrentPriority,
  892. UserTime,
  893. PrivilegedTime,
  894. StartAddress,
  895. ThreadState,
  896. ThreadWaitReason
  897. }
  898. }
  899. internal static c