|
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:
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 FunctionYeah, 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 :
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 FunctionPreviously, 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 LongPlease 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>
This sample, or the one from which it originally derived, was published (or at least peripherally mentioned) in the following article(s):
- Mining the Registry for Structures, Classic VB Corner, VSM Online, April 2009
- Determining Process Times, Classic VB Corner, VSM Online, May 2009
- Creating Admin Tools in a Least Privileged World, Classic VB Corner, VSM Online, July 2010
This sample uses the following API calls:
Module Library Function CProcessTimes.cls advapi32
kernel32
psapiAdjustTokenPrivileges
LookupPrivilegeValue
OpenProcessToken
CloseHandle
CreateToolhelp32Snapshot
FileTimeToLocalFileTime
FileTimeToSystemTime
GetCurrentProcess
GetProcessTimes
GetVersionEx
LocalFileTimeToFileTime
OpenProcess
Process32First
Process32Next
SystemTimeToFileTime
EnumProcessesMDateFunctions.bas kernel32 FileTimeToLocalFileTime
FileTimeToSystemTime
LocalFileTimeToFileTime
RtlMoveMemory
SystemTimeToFileTimeMMain.bas kernel32 GetComputerName MRegCalls.bas advapi32
kernel32
shlwapiRegCloseKey
RegCreateKeyEx
RegDeleteKey
RegDeleteValue
RegEnumKeyEx
RegEnumValue
RegFlushKey
RegOpenKeyEx
RegQueryInfoKey
RegQueryValueEx
RegSetValueEx
GetTickCount
SHDeleteKey
SHDeleteValueDon't see what you're looking for? Here's a complete API cross-reference.
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
The following resources may also be of interest: