Uptime

Description

This sample demonstrates how to determine when the computer it's running was last rebooted. There are really two strategies you can follow. The most straight forward, and certainly the most accurate, is to query the creation time of the winlogon.exe process. This process starts when Windows does, and that time can be found with the GetProcessTimes API. Sounds simple, right? Well, there are a few hoops you have to jump through, lemme tell ya. Probably easiest to take a look at the code directly.

The other method sounds easy, and it actually is. Unfortunately, it's not necessarily accurate. Windows writes its shutdown time to the registry every time it's properly shutdown. You can snatch that value like this:

Color-coded with vbMarkUp - try it today!
Public Function LastShutdown() As Date
   Dim b() As Byte
   Dim ft As FILETIME
   Const HKEY_LOCAL_MACHINE = &H80000002
   Const Key As String = "System\CurrentControlSet\Control\Windows"
   Const Value As String = "ShutdownTime"

   If RegGetBinaryValue(HKEY_LOCAL_MACHINE, Key, Value, b) Then
      If UBound(b) = 7 Then
         Call CopyMemory(ft, b(0), 8&)
         LastShutdown = FileTimeToDouble(ft, True)
      End If
   End If
End Function

Yeah, there are a couple of custom helper routines there. As you might imagine, RegGetBinaryValue grabs the bytes found at that registry location, and FileTimeToDouble converts a FILETIME structure to the standard format used by ClassicVB to store date/time values.

These two values, obtained with GetProcessTimes and from the Registry, may be presented or otherwise used like this:

Also included in the download is a console utility I wrote (using vbAdvance) that displays this information at the command prompt via standard output. You may find that useful for other scripting purposes.

Critical Update

On June 23, 2009, I discovered a critical bug in the MRegCalls.bas module. If you downloaded this module before that date, please redownload now. Or, at the least, modify the :

Color-coded with vbMarkUp - try it today!
Public Function RegDeleteValue(ByVal RootKey As Long, ByVal Key As String, 
                               ByVal Value As String) As Boolean
   Dim nRet As Long
   ' Just delete this single value.
   nRet = SHDeleteValue(RootKey, Key, Value)
   ' Return result of SHDeleteValue call.
   RegDeleteValue = (nRet = ERROR_SUCCESS)
End Function

Previously, this function erroneously called the SHDeleteKey API - a positively horrid cut/paste error. Worst still, perhaps, was the botched declare. That needs to look like this:

Private Declare Function SHDeleteValue Lib "shlwapi" Alias "SHDeleteValueA" _
   (ByVal hKey As Long, ByVal lpSubKey As String, ByVal lpValue As String) As Long

Please note, the problem with the original declare was that it used "SHDeleteKeyA" as the alias name for the function. I am so sorry for allowing this oversight to be published. Boy, am I sorry! I actually lost my HKEY_CURRENT_USER hive twice with this nonsense. If that happens to you, the best recovery path I found was to turn the machine off, then restart using the "Last Known Good" configuration. Not sure how many chances you have for that, and it doesn't restore quite everything. Guess that's why these registry articles always stress to completely backup the registry before making any changes! <sigh>

Published

This sample, or the one from which it originally derived, was published (or at least peripherally mentioned) in the following article(s):

APIs Usage

This sample uses the following API calls:

Module Library Function
CProcessTimes.cls advapi32


kernel32











psapi
AdjustTokenPrivileges
LookupPrivilegeValue
OpenProcessToken
CloseHandle
CreateToolhelp32Snapshot
FileTimeToLocalFileTime
FileTimeToSystemTime
GetCurrentProcess
GetProcessTimes
GetVersionEx
LocalFileTimeToFileTime
OpenProcess
Process32First
Process32Next
SystemTimeToFileTime
EnumProcesses
MDateFunctions.bas kernel32



FileTimeToLocalFileTime
FileTimeToSystemTime
LocalFileTimeToFileTime
RtlMoveMemory
SystemTimeToFileTime
MMain.bas kernel32 GetComputerName
MRegCalls.bas advapi32










kernel32
shlwapi
RegCloseKey
RegCreateKeyEx
RegDeleteKey
RegDeleteValue
RegEnumKeyEx
RegEnumValue
RegFlushKey
RegOpenKeyEx
RegQueryInfoKey
RegQueryValueEx
RegSetValueEx
GetTickCount
SHDeleteKey
SHDeleteValue

Don't see what you're looking for? Here's a complete API cross-reference.

Download

Download Uptime.zip   Please, enjoy and learn from this sample. Include its code within your own projects, if you wish. But, in order to insure only the most recent code is available to all, I ask that you don't share the sample by any form of mass distribution.

Download Uptime.zip, 36Kb, Last Updated: Monday, June 28, 2010

See Also

The following resources may also be of interest: