.net 要获取CPU和内存的使用率,一般是通过 PerformanceCounter 或者 WMI 查询得到,但是如果操作系统经常不正常断电或者别的什么原因,让系统的性能计数器抽风了,可能就会造成初始化 PerformanceCounter 对象出错。
性能计数器错误一般可以通过 lodctr /r 可以修复,但是时不时要这么搞一下,对用户总是太不友好了,所以能通过 Win32API 来获取也是一个不错的选项。
代码已封装到两个工具类 CpuUsageNt 和 MemUsage 里面了
''' <summary> ''' Inherits the CPUUsage class and implements the Query method for Windows NT systems. ''' </summary> ''' <remarks> ''' <p>This class works on Windows NT4, Windows 2000, Windows XP, Windows .NET Server and higher.</p> ''' </remarks> Private NotInheritable Class CpuUsageNt ''' <summary> ''' Initializes a new CpuUsageNt instance. ''' </summary> ''' <exception cref="NotSupportedException">One of the system calls fails.</exception> Public Sub New() Dim timeInfo(31) As Byte ' SYSTEM_TIME_INFORMATION structure Dim perfInfo(311) As Byte ' SYSTEM_PERFORMANCE_INFORMATION structure Dim baseInfo(43) As Byte ' SYSTEM_BASIC_INFORMATION structure Dim ret As Integer If (Environment.OSVersion.Platform <> PlatformID.Win32NT) Then Throw New NotSupportedException() End If ' get new system time ret = NtQuerySystemInformation(SYSTEM_TIMEINFORMATION, timeInfo, timeInfo.Length, IntPtr.Zero) If ret <> NO_ERROR Then Throw New NotSupportedException() End If ' get new CPU's idle time ret = NtQuerySystemInformation(SYSTEM_PERFORMANCEINFORMATION, perfInfo, perfInfo.Length, IntPtr.Zero) If ret <> NO_ERROR Then Throw New NotSupportedException() End If ' get number of processors in the system ret = NtQuerySystemInformation(SYSTEM_BASICINFORMATION, baseInfo, baseInfo.Length, IntPtr.Zero) If ret <> NO_ERROR Then Throw New NotSupportedException() End If ' store new CPU's idle and system time and number of processors _oldIdleTime = BitConverter.ToInt64(perfInfo, 0) ' SYSTEM_PERFORMANCE_INFORMATION.liIdleTime _oldSystemTime = BitConverter.ToInt64(timeInfo, 8) ' SYSTEM_TIME_INFORMATION.liKeSystemTime _processorCount = baseInfo(40) End Sub ''' <summary> ''' Determines the current average CPU load. ''' </summary> ''' <returns>An integer that holds the CPU load percentage.</returns> ''' <exception cref="NotSupportedException">One of the system calls fails. The CPU time can not be obtained.</exception> Public Function Query() As Integer Dim timeInfo(31) As Byte ' SYSTEM_TIME_INFORMATION structure Dim perfInfo(311) As Byte ' SYSTEM_PERFORMANCE_INFORMATION structure ' get new system time Dim ret As Integer = NtQuerySystemInformation(SYSTEM_TIMEINFORMATION, timeInfo, timeInfo.Length, IntPtr.Zero) If ret <> NO_ERROR Then Throw New NotSupportedException() End If ' get new CPU's idle time ret = NtQuerySystemInformation(SYSTEM_PERFORMANCEINFORMATION, perfInfo, perfInfo.Length, IntPtr.Zero) If ret <> NO_ERROR Then Throw New NotSupportedException() End If ' CurrentValue = NewValue - OldValue Dim dbIdleTime As Double = BitConverter.ToInt64(perfInfo, 0) - _oldIdleTime Dim dbSystemTime As Double = BitConverter.ToInt64(timeInfo, 8) - _oldSystemTime ' CurrentCpuIdle = IdleTime / SystemTime If dbSystemTime <> 0 Then dbIdleTime = dbIdleTime / dbSystemTime End If ' CurrentCpuUsage% = 100 - (CurrentCpuIdle * 100) / NumberOfProcessors dbIdleTime = 100.0 - dbIdleTime * 100.0 / _processorCount + 0.5 ' store new CPU's idle and system time _oldIdleTime = BitConverter.ToInt64(perfInfo, 0) ' SYSTEM_PERFORMANCE_INFORMATION.liIdleTime _oldSystemTime = BitConverter.ToInt64(timeInfo, 8) ' SYSTEM_TIME_INFORMATION.liKeSystemTime Return CInt(Fix(dbIdleTime)) End Function ''' <summary> ''' NtQuerySystemInformation is an internal Windows function that retrieves various kinds of system information. ''' </summary> ''' <param name="dwInfoType">One of the values enumerated in SYSTEM_INFORMATION_CLASS, indicating the kind of system information to be retrieved.</param> ''' <param name="lpStructure">Points to a buffer where the requested information is to be returned. The size and structure of this information varies depending on the value of the SystemInformationClass parameter.</param> ''' <param name="dwSize">Length of the buffer pointed to by the SystemInformation parameter.</param> ''' <param name="returnLength">Optional pointer to a location where the function writes the actual size of the information requested.</param> ''' <returns>Returns a success NTSTATUS if successful, and an NTSTATUS error code otherwise.</returns> <DllImport("ntdll", EntryPoint:="NtQuerySystemInformation")> Private Shared Function NtQuerySystemInformation(ByVal dwInfoType As Integer, ByVal lpStructure() As Byte, ByVal dwSize As Integer, ByVal returnLength As IntPtr) As Integer End Function ''' <summary>Returns the number of processors in the system in a SYSTEM_BASIC_INFORMATION structure.</summary> Private Const SYSTEM_BASICINFORMATION As Integer = 0 ''' <summary>Returns an opaque SYSTEM_PERFORMANCE_INFORMATION structure.</summary> Private Const SYSTEM_PERFORMANCEINFORMATION As Integer = 2 ''' <summary>Returns an opaque SYSTEM_TIMEOFDAY_INFORMATION structure.</summary> Private Const SYSTEM_TIMEINFORMATION As Integer = 3 ''' <summary>The value returned by NtQuerySystemInformation is no error occurred.</summary> Private Const NO_ERROR As Integer = 0 ''' <summary>Holds the old idle time.</summary> Private _oldIdleTime As Long ''' <summary>Holds the old system time.</summary> Private _oldSystemTime As Long ''' <summary>Holds the number of processors in the system.</summary> Private _processorCount As Double End Class