Retrieving system information using Visual Basic

Need to get information about the system your application is running on? As Lamont Adams demonstrates, Windows API functions enable you to retrieve info like the screen resolution and the user's name. Our downloadable source code demos the API calls.

When programming, it’s often necessary to know certain things about the system on which your application is running. For instance, you may need to determine which version of Windows is installed or find out the current screen resolution. You can use the Windows API to easily obtain information like this.

In this article, I’ll introduce you to a few helpful API functions you can use to retrieve the following information:
  • Computer name
  • User’s login ID
  • Windows version in text (Windows 2000 SP1) and numeric (5.0.2195) format
  • Current screen resolution in pixels
  • Elapsed time since the last reboot
  • Whether or not the user requires visual feedback for sounds
  • How the machine started (Normal or Safe Mode)
  • Path to the Windows and System folders
  • Number of mouse buttons, whether it has a wheel, and its orientation (left- or right-handed)

Danger, Will Robinson!
Because most Windows API functions are written in C or C++, the types they use do not always exactly match their VB counterparts internally. Strings are a good example. Because of this, passing a variable of the incorrect type or of the correct type in an incorrect manner will usually result in a one-way ticket to crash city for your application (or VB if your app is running in the IDE) and sometimes for Windows as well. For this reason, it’s important to use the correct declarations provided by the API Text Viewer utility and save your work often when dealing with API functions!

What’s your name?
Obtaining the user and computer name is simple with the use of the GetComputerName() and GetUserName() API functions. Their declarations are as follows:
Private Declare Function GetComputerName _
Lib "kernel32" Alias "GetComputerNameA" _
(ByVal lpBuffer As String, _
nSize As Long) As Long
Private Declare Function GetUserName _
Lib "advapi32.dll" Alias "GetUserNameA" _
(ByVal lpBuffer As String, _
nSize As Long) As Long

The Windows and System folder paths are just as easy to retrieve using the GetWindowsDirectory() and GetSystemDirectory() API functions. These work identically to the GetComputerName() function and are declared as follows:
Private Declare Function GetWindowsDirectory _
Lib "kernel32" Alias "GetWindowsDirectoryA" _
(ByVal lpBuffer As String, _
ByVal nSize As Long) As Long
Private Declare Function GetSystemDirectory _
Lib "kernel32" Alias "GetSystemDirectoryA" _
(ByVal lpBuffer As String, _
ByVal nSize As Long) As Long

Like most API functions, these return values of type Long, with a value of zero typically indicating success. The computer, user, and directory names are actually returned through the functions’ arguments. The lpBuffer input-output argument represents a fixed-length, null-terminated string, while the nSize input argument is the maximum number of characters the string may contain, including the terminating null. I specified 100 characters in our examples since this is usually more than sufficient. Remember that lpBuffer must be initialized to the proper length via VB’s String() function or by specifying a fixed size in lpBuffer’s Dim statement, and this length should be passed to the function as the nSize argument. After the function call, the null marking the end of lpBuffer must be removed before any spaces can be trimmed off. I do this in the example via a helper function I created named szToStr().

The metric system
The multipurpose GetSystemMetrics() function can retrieve a variety of information about the system and determine whether certain features are installed. Our example uses GetSystemMetrics() to determine the screen resolution, mouse information, visual feedback, and startup mode. Here’s the declaration for GetSystemMetrics():
Private Declare Function GetSystemMetrics Lib "user32" _
(ByVal nIndex As Long) As Long

The input argument nIndex determines what information the function returns. The allowable values for nIndex are defined by a set of constants named with an SM_ prefix, for example, SM_CMOUSEBUTTONS returns the number of buttons on the attached mouse. Unfortunately, only a relative few of these constants are defined by Visual Studio’s API Text Viewer. If you are fortunate enough to have Visual C++ installed, you can find the values of the missing system metrics constants (as well as many others) by searching for them in the Winuser.h header file located in the VC98\include folder of your Visual Studio folder tree.

The GetTickCount() function returns the number of milliseconds that have elapsed since the machine was started. An obvious use for this function is to calculate the elapsed time in hours, minutes, and seconds since Windows was last rebooted, as I did in our example. By calling this function repeatedly and comparing the two values, it is also possible to calculate the elapsed time between calls.

Why would you use this method instead of the built in VB function Timer(), which returns the number of milliseconds elapsed since midnight? Code that utilizes Timer() must determine whether the clock has passed midnight since the last call and handle that special case accordingly, while code using GetTickCount() is immune from this consideration. GetTickCount() has a simple declaration:
Private Declare Function GetTickCount _
Lib "kernel32" () As Long

What version is that?
Determining the Windows version is not difficult using GetVersionEx(), as long as you understand the OSVERSIONINFO structure that the function accepts as an argument. OSVERSIONINFO is defined by the API Text Viewer and contains the following six members:
  • dwOSVersionInfoSize is the size of the structure in bytes. Currently, this is 148, but it could change, so it is safer to use the VB len() function to determine the size than to hard-code it. Make sure this member is set to the correct value before calling the function; otherwise, welcome to crash city, population you.
  • dwMajorVersion, dwMinorVersion, and dwBuildNumber represent the version number of Windows in Major.Minor.Build format (e.g., 5.0.2195). Per Microsoft, Windows 95, 98, Me, and NT4 are all version 4.x.x, while Windows 2000 and XP(Whistler) are version 5.x.x. The minor version number determines the edition. For example, Windows Me is 5.90.x.
  • dwPlatformId determines the kernel type. This will likely be either VER_PLATFORM_WIN32_WINDOWS, or VER_PLATFORM_WIN32_NT. You’ll need to examine this member to distinguish between Windows 95 and NT4, since these both report identical dwMajorVersion and dwMinorVersion numbers: 4.0.
  • szCSDVersion contains information about installed service packs in null-terminated, 128 character string format.

Here is the declaration for GetVersionEx():
Private Declare Function GetVersionEx _
Lib "kernel32" Alias "GetVersionExA" _
(lpVersionInformation As OSVERSIONINFO) _
As Long

That’s all for now, but I’ve just scratched the surface. For more information, I recommend picking up a copy of the excellent reference Dan Appleman's Visual Basic Programmer's Guide to the Win32 API. Editions are available for all versions of VB through VB6. Happy coding.

Editor's Picks