VB.NET 在 Windows下通过WIn32API获取CPU和内存的使用率


.net 要获取CPU和内存的使用率,一般是通过 PerformanceCounter 或者 WMI 查询得到,但是如果操作系统经常不正常断电或者别的什么原因,让系统的性能计数器抽风了,可能就会造成初始化 PerformanceCounter 对象出错。

性能计数器错误一般可以通过 lodctr /r 可以修复,但是时不时要这么搞一下,对用户总是太不友好了,所以能通过 Win32API 来获取也是一个不错的选项。

代码已封装到两个工具类 CpuUsageNt 和 MemUsage 里面了

''' 
''' Inherits the CPUUsage class and implements the Query method for Windows NT systems.
''' 
''' 
''' 

This class works on Windows NT4, Windows 2000, Windows XP, Windows .NET Server and higher.

''' Private NotInheritable Class CpuUsageNt ''' ''' Initializes a new CpuUsageNt instance. ''' ''' One of the system calls fails. 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 ''' ''' Determines the current average CPU load. ''' ''' An integer that holds the CPU load percentage. ''' One of the system calls fails. The CPU time can not be obtained. 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 ''' ''' NtQuerySystemInformation is an internal Windows function that retrieves various kinds of system information. ''' ''' One of the values enumerated in SYSTEM_INFORMATION_CLASS, indicating the kind of system information to be retrieved. ''' 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. ''' Length of the buffer pointed to by the SystemInformation parameter. ''' Optional pointer to a location where the function writes the actual size of the information requested. ''' Returns a success NTSTATUS if successful, and an NTSTATUS error code otherwise. "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 ''' Returns the number of processors in the system in a SYSTEM_BASIC_INFORMATION structure. Private Const SYSTEM_BASICINFORMATION As Integer = 0 ''' Returns an opaque SYSTEM_PERFORMANCE_INFORMATION structure. Private Const SYSTEM_PERFORMANCEINFORMATION As Integer = 2 ''' Returns an opaque SYSTEM_TIMEOFDAY_INFORMATION structure. Private Const SYSTEM_TIMEINFORMATION As Integer = 3 ''' The value returned by NtQuerySystemInformation is no error occurred. Private Const NO_ERROR As Integer = 0 ''' Holds the old idle time. Private _oldIdleTime As Long ''' Holds the old system time. Private _oldSystemTime As Long ''' Holds the number of processors in the system. Private _processorCount As Double End Class
CpuUsageNt
 1 Private NotInheritable Class MemUsage
 2     
 3     Private Structure MEMORY_INFO
 4         ''' 
 5         ''' 当前结构体大小
 6         ''' 
 7         Public dwLength As UInteger
 8         ''' 
 9         ''' 当前内存使用率
10         ''' 
11         Public dwMemoryLoad As UInteger
12         ''' 
13         ''' 总计物理内存大小
14         ''' 
15         Public dwTotalPhys As UInteger
16         ''' 
17         ''' 可用物理内存大小
18         ''' 
19         Public dwAvailPhys As UInteger
20         ''' 
21         ''' 总计交换文件大小
22         ''' 
23         Public dwTotalPageFile As UInteger
24         ''' 
25         ''' 可用交换文件大小
26         ''' 
27         Public dwAvailPageFile As UInteger
28         ''' 
29         ''' 总计虚拟内存大小
30         ''' 
31         Public dwTotalVirtual As UInteger
32         ''' 
33         ''' 可用虚拟内存大小
34         ''' 
35         Public dwAvailVirtual As UInteger
36     End Structure
37     "kernel32")>
38     Private Shared Sub GlobalMemoryStatus(ByRef meminfo As MEMORY_INFO)
39     End Sub
40 
41     Public Function Query() As Int32
42         Dim iRet As Int32 = 0
43         Try
44             Dim MemInfo As New MEMORY_INFO
45             GlobalMemoryStatus(MemInfo)
46             iRet = CInt(MemInfo.dwMemoryLoad)
47             Debug.Print("[DEBUG] GlobalMemoryStatus dwMemoryLoad={0}", iRet)
48         Catch ex As Exception
49             Debug.Print("[WARN ] GlobalMemoryStatus Err:{0}", ex.Message)
50         End Try
51         Return iRet
52     End Function
53 
54     ''' 
55     ''' 格式化容量大小
56     ''' 
57     ''' 容量(B)
58     ''' 已格式化的容量
59     Private Shared Function FormatSize(ByVal size As Double) As String
60         Dim d As Double = size
61         Dim i As Integer = 0
62         Do While (d > 1024) AndAlso (i < 5)
63             d /= 1024
64             i += 1
65         Loop
66         Dim unit() As String = {"B", "KB", "MB", "GB", "TB"}
67         Return (String.Format("{0} {1}", Math.Round(d, 2), unit(i)))
68     End Function
69 End Class
MemUsage

参考资料

1.C#获得Cpu使用率

2.c# 获取某一个进程的cpu和内存使用情况