Processor.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. using Microsoft.Win32;
  2. using System;
  3. using System.ComponentModel;
  4. using System.Runtime.InteropServices;
  5. namespace PaintDotNet.SystemLayer
  6. {
  7. /// <summary>
  8. /// Provides static methods and properties related to the CPU.
  9. /// </summary>
  10. public static class Processor
  11. {
  12. private static int logicalCpuCount;
  13. private static string cpuName;
  14. static Processor()
  15. {
  16. logicalCpuCount = ConcreteLogicalCpuCount;
  17. }
  18. private static ProcessorArchitecture Convert(ushort wProcessorArchitecture)
  19. {
  20. ProcessorArchitecture platform;
  21. switch (wProcessorArchitecture)
  22. {
  23. case NativeConstants.PROCESSOR_ARCHITECTURE_AMD64:
  24. platform = ProcessorArchitecture.X64;
  25. break;
  26. case NativeConstants.PROCESSOR_ARCHITECTURE_INTEL:
  27. platform = ProcessorArchitecture.X86;
  28. break;
  29. default:
  30. case NativeConstants.PROCESSOR_ARCHITECTURE_UNKNOWN:
  31. platform = ProcessorArchitecture.Unknown;
  32. break;
  33. }
  34. return platform;
  35. }
  36. /// <summary>
  37. /// Returns the processor architecture that the current process is using.
  38. /// </summary>
  39. /// <remarks>
  40. /// Note that if the current process is 32-bit, but the OS is 64-bit, this
  41. /// property will still return X86 and not X64.
  42. /// </remarks>
  43. public static ProcessorArchitecture Architecture
  44. {
  45. get
  46. {
  47. NativeStructs.SYSTEM_INFO sysInfo = new NativeStructs.SYSTEM_INFO();
  48. NativeMethods.GetSystemInfo(ref sysInfo);
  49. ProcessorArchitecture architecture = Convert(sysInfo.wProcessorArchitecture);
  50. return architecture;
  51. }
  52. }
  53. /// <summary>
  54. /// Returns the processor architecture of the installed operating system.
  55. /// </summary>
  56. /// <remarks>
  57. /// Note that this may differ from the Architecture property if, for instance,
  58. /// this is a 32-bit process on a 64-bit OS.
  59. /// </remarks>
  60. public static ProcessorArchitecture NativeArchitecture
  61. {
  62. get
  63. {
  64. NativeStructs.SYSTEM_INFO sysInfo = new NativeStructs.SYSTEM_INFO();
  65. NativeMethods.GetNativeSystemInfo(ref sysInfo);
  66. ProcessorArchitecture architecture = Convert(sysInfo.wProcessorArchitecture);
  67. return architecture;
  68. }
  69. }
  70. private static string GetCpuName()
  71. {
  72. Guid processorClassGuid = new Guid("{50127DC3-0F36-415E-A6CC-4CB3BE910B65}");
  73. IntPtr hDiSet = IntPtr.Zero;
  74. string cpuName = null;
  75. try
  76. {
  77. hDiSet = NativeMethods.SetupDiGetClassDevsW(ref processorClassGuid, null, IntPtr.Zero, NativeConstants.DIGCF_PRESENT);
  78. if (hDiSet == NativeConstants.INVALID_HANDLE_VALUE)
  79. {
  80. NativeMethods.ThrowOnWin32Error("SetupDiGetClassDevsW returned INVALID_HANDLE_VALUE");
  81. }
  82. bool bResult = false;
  83. uint memberIndex = 0;
  84. while (true)
  85. {
  86. NativeStructs.SP_DEVINFO_DATA spDevinfoData = new NativeStructs.SP_DEVINFO_DATA();
  87. spDevinfoData.cbSize = (uint)Marshal.SizeOf(typeof(NativeStructs.SP_DEVINFO_DATA));
  88. bResult = NativeMethods.SetupDiEnumDeviceInfo(hDiSet, memberIndex, ref spDevinfoData);
  89. if (!bResult)
  90. {
  91. int error = Marshal.GetLastWin32Error();
  92. if (error == NativeConstants.ERROR_NO_MORE_ITEMS)
  93. {
  94. break;
  95. }
  96. else
  97. {
  98. throw new Win32Exception("SetupDiEnumDeviceInfo returned false, GetLastError() = " + error.ToString());
  99. }
  100. }
  101. uint lengthReq = 0;
  102. bResult = NativeMethods.SetupDiGetDeviceInstanceIdW(hDiSet, ref spDevinfoData, IntPtr.Zero, 0, out lengthReq);
  103. if (bResult)
  104. {
  105. NativeMethods.ThrowOnWin32Error("SetupDiGetDeviceInstanceIdW(1) returned true");
  106. }
  107. if (lengthReq == 0)
  108. {
  109. NativeMethods.ThrowOnWin32Error("SetupDiGetDeviceInstanceIdW(1) returned false, but also 0 for lengthReq");
  110. }
  111. IntPtr str = IntPtr.Zero;
  112. string regPath = null;
  113. try
  114. {
  115. // Note: We cannot use Memory.Allocate() here because this property is
  116. // usually retrieved during app shutdown, during which the heap may not
  117. // be available.
  118. str = Marshal.AllocHGlobal(checked((int)(sizeof(char) * (1 + lengthReq))));
  119. bResult = NativeMethods.SetupDiGetDeviceInstanceIdW(hDiSet, ref spDevinfoData, str, lengthReq, out lengthReq);
  120. if (!bResult)
  121. {
  122. NativeMethods.ThrowOnWin32Error("SetupDiGetDeviceInstanceIdW(2) returned false");
  123. }
  124. regPath = Marshal.PtrToStringUni(str);
  125. }
  126. finally
  127. {
  128. if (str != IntPtr.Zero)
  129. {
  130. Marshal.FreeHGlobal(str);
  131. str = IntPtr.Zero;
  132. }
  133. }
  134. string keyName = @"SYSTEM\CurrentControlSet\Enum\" + regPath;
  135. using (RegistryKey procKey = Registry.LocalMachine.OpenSubKey(keyName, false))
  136. {
  137. const string friendlyName = "FriendlyName";
  138. if (procKey != null)
  139. {
  140. object valueObj = procKey.GetValue(friendlyName);
  141. string value = valueObj as string;
  142. if (value != null)
  143. {
  144. cpuName = value;
  145. }
  146. }
  147. }
  148. if (cpuName != null)
  149. {
  150. break;
  151. }
  152. ++memberIndex;
  153. }
  154. }
  155. finally
  156. {
  157. if (hDiSet != IntPtr.Zero)
  158. {
  159. NativeMethods.SetupDiDestroyDeviceInfoList(hDiSet);
  160. hDiSet = IntPtr.Zero;
  161. }
  162. }
  163. return cpuName;
  164. }
  165. /// <summary>
  166. /// Returns the name of the CPU that is installed. If more than 1 CPU is installed,
  167. /// then the name of the first one is retrieved.
  168. /// </summary>
  169. /// <remarks>
  170. /// This is the name that shows up in Windows Device Manager in the "Processors" node.
  171. /// Note to implementors: This is only ever used for diagnostics (e.g., crash log).
  172. /// </remarks>
  173. public static string CpuName
  174. {
  175. get
  176. {
  177. if (cpuName == null)
  178. {
  179. cpuName = GetCpuName();
  180. }
  181. return cpuName;
  182. }
  183. }
  184. /// <summary>
  185. /// Gets the number of logical or "virtual" processors installed in the computer.
  186. /// </summary>
  187. /// <remarks>
  188. /// This value may not return the actual number of processors installed in the system.
  189. /// It may be set to another number for testing and benchmarking purposes. It is
  190. /// recommended that you use this property instead of ConcreteLogicalCpuCount for the
  191. /// purposes of optimizing thread usage.
  192. /// The maximum value for this property is 32 when running as a 32-bit process, or
  193. /// 64 for a 64-bit process. Note that this implies the maximum is 32 for a 32-bit process
  194. /// even when running on a 64-bit system.
  195. /// </remarks>
  196. public static int LogicalCpuCount
  197. {
  198. get
  199. {
  200. return logicalCpuCount;
  201. }
  202. set
  203. {
  204. if (value < 1 || value > (IntPtr.Size * 8))
  205. {
  206. throw new ArgumentOutOfRangeException("value", value, "must be in the range [0, " + (IntPtr.Size * 8).ToString() + "]");
  207. }
  208. logicalCpuCount = value;
  209. }
  210. }
  211. /// <summary>
  212. /// Gets the number of logical or "virtual" processors installed in the computer.
  213. /// </summary>
  214. /// <remarks>
  215. /// This property will always return the actual number of logical processors installed
  216. /// in the system. Note that processors such as Intel Xeons and Pentium 4's with
  217. /// HyperThreading will result in values that are twice the number of physical processor
  218. /// packages that have been installed (i.e. 2 Xeons w/ HT => ConcreteLogicalCpuCount = 4).
  219. /// </remarks>
  220. public static int ConcreteLogicalCpuCount
  221. {
  222. get
  223. {
  224. return Environment.ProcessorCount;
  225. }
  226. }
  227. /// <summary>
  228. /// Gets the approximate speed of the processor, in megahurtz.
  229. /// </summary>
  230. /// <remarks>
  231. /// No accuracy is guaranteed, and precision is dependent on the operating system.
  232. /// If there is an error determining the CPU speed, then 0 will be returned.
  233. /// </remarks>
  234. public static int ApproximateSpeedMhz
  235. {
  236. get
  237. {
  238. const string keyName = @"HARDWARE\DESCRIPTION\System\CentralProcessor\0";
  239. const string valueName = @"~MHz";
  240. int mhz = 0;
  241. try
  242. {
  243. using (RegistryKey key = Registry.LocalMachine.OpenSubKey(keyName, false))
  244. {
  245. if (key != null)
  246. {
  247. object value = key.GetValue(valueName);
  248. mhz = (int)value;
  249. }
  250. }
  251. }
  252. catch (Exception)
  253. {
  254. mhz = 0;
  255. }
  256. return mhz;
  257. }
  258. }
  259. private static ProcessorFeature features = (ProcessorFeature)0;
  260. public static ProcessorFeature Features
  261. {
  262. get
  263. {
  264. if (features == (ProcessorFeature)0)
  265. {
  266. ProcessorFeature newFeatures = (ProcessorFeature)0;
  267. // DEP
  268. if (SafeNativeMethods.IsProcessorFeaturePresent(NativeConstants.PF_NX_ENABLED))
  269. {
  270. newFeatures |= ProcessorFeature.DEP;
  271. }
  272. // SSE
  273. if (SafeNativeMethods.IsProcessorFeaturePresent(NativeConstants.PF_XMMI_INSTRUCTIONS_AVAILABLE))
  274. {
  275. newFeatures |= ProcessorFeature.SSE;
  276. }
  277. // SSE2
  278. if (SafeNativeMethods.IsProcessorFeaturePresent(NativeConstants.PF_XMMI64_INSTRUCTIONS_AVAILABLE))
  279. {
  280. newFeatures |= ProcessorFeature.SSE2;
  281. }
  282. // SSE3
  283. if (SafeNativeMethods.IsProcessorFeaturePresent(NativeConstants.PF_SSE3_INSTRUCTIONS_AVAILABLE))
  284. {
  285. newFeatures |= ProcessorFeature.SSE3;
  286. }
  287. features = newFeatures;
  288. }
  289. return features;
  290. }
  291. }
  292. public static bool IsFeaturePresent(ProcessorFeature feature)
  293. {
  294. return ((Features & feature) == feature);
  295. }
  296. }
  297. }