VB Tip: obter uso de memória RAM e de CPU
Autor: Diego Silva | Publicado: 2011-08-21T21:21:00-03:00

Olá.
Essa semana, pelos comentários, perguntaram como acessar o uso de memória RAM e de CPU no Visual Basic 6, uma vez que o MultiSystem Sidebar consegue tal feito. Ensinarei aqui o código necessário para acessar tais informações.

Primeiramente se deve saber de uma coisa: o funcionamento ou não do código dependerá do sistema operacional utilizado. Pelo menos aqui no Seven funciona, no Vista também funciona (já testei) e no XP, idem (foi lá onde desenvolvi o aplicativo). Sendo assim, o código deverá não funcionar em sistemas operacionais antigos como WinME ou Win98. Mas quem ainda usa esses sistemas operacionais hoje em dia?? Enfim.
Irei dividir em duas partes: a primeira tratará do uso de RAM e o outro tratará do uso de CPU. 
Uso de RAM
Iremos precisar da API GlobalMemoryStatus da biblioteca kernel32 (onde a maioria das APIs são para acesso à seção de hardware. Beep é um exemplo.) cujo único parâmetro é uma referência do tipo MEMORYSTATUS.
Antes de começarmos, crie um novo projeto Standard EXE (pode ser também uma DLL). Adicione ao projeto um módulo e uma classe. Chamaremos o módulo de mApi (mas pode-se colocar qualquer nome no módulo;a classe trataremos depois, portanto, não mexa nela).
Feito isso, adicione o seguinte código ao módulo:

Public Type MEMORYSTATUS
       dwLength As Long
       dwMemoryLoad As Long
       dwTotalPhys As Long
       dwAvailPhys As Long
       dwTotalPageFile As Long
       dwAvailPageFile As Long
       dwTotalVirtual As Long
       dwAvailVirtual As Long
End Type
Public Declare Sub GlobalMemoryStatus Lib "kernel32" (lpBuffer As MEMORYSTATUS)

Feita a declaração da API e do tipo necessários para a obtenção das informações desejadas, iremos criar uma função que retornará o valor de utilização da memória RAM. 

Adicione a seguinte função abaixo das declarações do módulo:

Public Function UsoDeRAM() As String 'Aqui pode ser qualquer nome que desejar.
Dim Mem As MEMORYSTATUS
Mem.dwLength = Len(Mem)
GlobalMemoryStatus Mem
UsoDeRAM=CStr(Mem.dwMemoryLoad) 'Se alterar o nome da função, altere aqui também!
End Function

Feito isso, você pode usar a função UsoDeRAM a qualquer momento, seja na atribuição à propriedade Caption de uma label ou à uma função Print de algum container.

Uso de CPU
A obtenção do uso de CPU requer uma classe. Utilizaremos a classe que criamos anteriormente. Nomeie-a de cCpu.

Nela, insira o seguinte código:

Option Explicit
Private Const SYSTEM_BASICINFORMATION = 0&
Private Const SYSTEM_PERFORMANCEINFORMATION = 2&
Private Const SYSTEM_TIMEINFORMATION = 3&
Private Const NO_ERROR = 0
Private Type LARGE_INTEGER
    dwLow As Long
    dwHigh As Long
End Type
Private Type SYSTEM_BASIC_INFORMATION
    dwUnknown1 As Long
    uKeMaximumIncrement As Long
    uPageSize As Long
    uMmNumberOfPhysicalPages As Long
    uMmLowestPhysicalPage As Long
    uMmHighestPhysicalPage As Long
    uAllocationGranularity As Long
    pLowestUserAddress As Long
    pMmHighestUserAddress As Long
    uKeActiveProcessors As Long
    bKeNumberProcessors As Byte
    bUnknown2 As Byte
    wUnknown3 As Integer
End Type
Private Type SYSTEM_PERFORMANCE_INFORMATION
    liIdleTime As LARGE_INTEGER
    dwSpare(0 To 75) As Long
End Type
Private Type SYSTEM_TIME_INFORMATION
    liKeBootTime As LARGE_INTEGER
    liKeSystemTime As LARGE_INTEGER
    liExpTimeZoneBias  As LARGE_INTEGER
    uCurrentTimeZoneId As Long
    dwReserved As Long
End Type
Private Declare Function NtQuerySystemInformation Lib "ntdll" (ByVal dwInfoType As Long, ByVal lpStructure As Long, ByVal dwSize As Long, ByVal dwReserved As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDst As Any, pSrc As Any, ByVal ByteLen As Long)
Private liOldIdleTime As LARGE_INTEGER
Private liOldSystemTime As LARGE_INTEGER
Public Sub Initialize()
    Dim SysTimeInfo As SYSTEM_TIME_INFORMATION
    Dim SysPerfInfo As SYSTEM_PERFORMANCE_INFORMATION
    Dim Ret As Long
    Ret = NtQuerySystemInformation(SYSTEM_TIMEINFORMATION, VarPtr(SysTimeInfo), LenB(SysTimeInfo), 0&)
    If Ret <> NO_ERROR Then
        Debug.Print "Error while initializing the system's time!", vbCritical
        Exit Sub
    End If
    Ret = NtQuerySystemInformation(SYSTEM_PERFORMANCEINFORMATION, VarPtr(SysPerfInfo), LenB(SysPerfInfo), ByVal 0&)
    If Ret <> NO_ERROR Then
        Debug.Print "Error while initializing the CPU's idle time!", vbCritical
        Exit Sub
    End If
    liOldIdleTime = SysPerfInfo.liIdleTime
    liOldSystemTime = SysTimeInfo.liKeSystemTime
End Sub
Public Function Query() As Long
    Dim SysBaseInfo As SYSTEM_BASIC_INFORMATION
    Dim SysPerfInfo As SYSTEM_PERFORMANCE_INFORMATION
    Dim SysTimeInfo As SYSTEM_TIME_INFORMATION
    Dim dbIdleTime As Currency
    Dim dbSystemTime As Currency
    Dim Ret As Long
    Query = -1
    Ret = NtQuerySystemInformation(SYSTEM_BASICINFORMATION, VarPtr(SysBaseInfo), LenB(SysBaseInfo), 0&)
    If Ret <> NO_ERROR Then
        Debug.Print "Error while retrieving the number of processors!", vbCritical
        Exit Function
    End If
    Ret = NtQuerySystemInformation(SYSTEM_TIMEINFORMATION, VarPtr(SysTimeInfo), LenB(SysTimeInfo), 0&)
    If Ret <> NO_ERROR Then
        Debug.Print "Error while retrieving the system's time!", vbCritical
        Exit Function
    End If
    Ret = NtQuerySystemInformation(SYSTEM_PERFORMANCEINFORMATION, VarPtr(SysPerfInfo), LenB(SysPerfInfo), ByVal 0&)
    If Ret <> NO_ERROR Then
        Debug.Print "Error while retrieving the CPU's idle time!", vbCritical
        Exit Function
    End If
    dbIdleTime = LI2Currency(SysPerfInfo.liIdleTime) - LI2Currency(liOldIdleTime)
    dbSystemTime = LI2Currency(SysTimeInfo.liKeSystemTime) - LI2Currency(liOldSystemTime)
    If dbSystemTime <> 0 Then dbIdleTime = dbIdleTime / dbSystemTime
    dbIdleTime = 100 - dbIdleTime * 100 / SysBaseInfo.bKeNumberProcessors + 0.5
    Query = Int(dbIdleTime)
    liOldIdleTime = SysPerfInfo.liIdleTime
    liOldSystemTime = SysTimeInfo.liKeSystemTime
End Function
Private Function LI2Currency(liInput As LARGE_INTEGER) As Currency
    CopyMemory LI2Currency, liInput, LenB(liInput)
End Function
Public Sub Terminate()
'Nada a fazer.
End Sub

Sim, o código é realmente extenso. Portanto, explicarei somente o necessário. No módulo que criamos, insira, abaixo da declaração "GlobalMemoryStatus", o seguinte código: 

Dim cpusage as cCpu

Sub InitCPU()
Set cpusage = new cCpu 'Cria uma nova instância de cCpu
End Sub

Sub EndCPU()
Set cpusage = Nothing ' Remove a instância de cCpu da memória
End Sub

Function GetCPU() As String 
GetCPU = CStr(Abs(cpusage.Query)) 'retorna o valor de uso da cpu
End Function 


A função Query retorna o valor de uso da cpu através da classe e de suas APIs internas. 

Se quiser, pode baixar o exemplo pronto através do link https://skydrive.live.com/?cid=B278D5E7A71B5DCA&sc=documents#!/?cid=b278d5e7a71b5dca&sc=documents&nl=1&uc=1&id=B278D5E7A71B5DCA!152!cid=B278D5E7A71B5DCA&id=B278D5E7A71B5DCA!152 (pasta do SkyDrive).

É isso pessoal.
Até o próximo artigo!