Functions That Require Data Structures
Several API functions used in this chapter require you to send them a user-defined type, and they supply values to fill the elements of the structure. Depending on the circumstances, the wrapper class may call the function in either of two ways, in terms of information retrieval:
It may call the function once, in the Initialize event of the class. If the information is relatively static, this makes sense. There's no point in calling the function each time you need to retrieve information from the function.
- It may set up the function call in the Initialize event of the class but call the function each time you request information from the class. This technique is useful for situations in which the data changes rapidly; the MemoryStatus class uses this technique because memory information is so volatile.
All the API functions in this chapter that pass information in this manner provide information that's read-only. Therefore, there are no issues involved in saving information back to the API.
For example, the GetVersionEx API call requires you to supply it a data structure of type OSVERSIONINFO. Listing 9.4 shows the necessary declarations, and the class Initialize event procedure, from the SystemInfo class (SYSTEMINFO.CLS). The event procedure first fills in the dwOSVersionInfoSize element of the structure with the length of the structure itself (many API calls require this step), and then it passes the structure to the GetVersionEx function. This function fills in the various members of the OSVI variable, and other properties of the class use these members in order to supply their information. For example, the OSMajorVersion property, also shown in Listing 9.4, uses the dwMajorVersion member of the OSVERSIONINFO structure to do its work.
Listing 9.4: Use the GetVersionEx API Function (Code Gathered from the SystemInfo Class Module)
Private Type OSVERSIONINFO dwOSVersionInfoSize As Long dwMajorVersion As Long dwMinorVersion As Long dwBuildNumber As Long dwPlatformId As Long szCSDVersion As String * 128 End Type Private Declare Function GetVersionEx Lib "kernel32" _ Alias "GetVersionExA" (OSVI As OSVERSIONINFO) _ As Long Private OSVI As OSVERSIONINFO Private Sub Class_Initialize() ' Fill in the OSVersionInfo structure OSVI.dwOSVersionInfoSize = Len(OSVI) Call GetVersionEx(OSVI) ' Fill in the SystemInformation structure. Call GetSystemInfo(si) End Sub Property Get OSMajorVersion() As Long ' Retrieve the major version number of the ' operating system. For example, for Windows ' NT version 3.51, the major version number ' is 3; and for Windows NT version 4.0, the ' major version number is 4. OSMajorVersion = OSVI.dwMajorVersion End Property
Because the information retrieved by the GetVersionEx API function isn't likely to change as your application runs, there's no reason to call the function more than once during the lifetime of your class. The properties of the MemoryStatus class, however, return data that changes constantly. Therefore, it makes sense to call the GlobalMemoryStatus API function each time you access any property of the MemoryStatus class. This ensures that the property values are always up to date. The code in Listing 9.5 has been excerpted from the MemoryStatus class (MEMORYSTATUS.CLS). This listing shows the type and API declarations, as well as the Initialize event procedure of the class and one of the property procedures. The Initialize event procedure of the class fills in the lngLength member of the structure, and this information never changes. The TotalPhysical property then calls the GlobalMemoryStatus API function, passing in the structure, and returns the lngTotalPhys member of the structure as its return value.
Listing 9.5: Excerpts from the MemoryStatus Class Module
Private Type typMemoryStatus lngLength As Long lngMemoryLoad As Long lngTotalPhys As Long lngAvailPhys As Long lngTotalPageFile As Long lngAvailPageFile As Long lngTotalVirtual As Long lngAvailVirtual As Long End Type Private Declare Sub GlobalMemoryStatus Lib "kernel32" _ (lpBuffer As typMemoryStatus) Dim ms As typMemoryStatus Private Sub Class_Initialize() ' ms is declared at the module level. ms.lngLength = Len(ms) End Sub Property Get TotalPhysical() As Long ' Indicates the total number of bytes of physical memory. Call GlobalMemoryStatus(ms) TotalPhysical = ms.lngTotalPhys End Property
The remainder of the chapter provides details on each of the nine system information classes we've created. (Although there are, in reality, ten class modules associated with this chapter, FONT.CLS is used only within other classes, so there's no section devoted to this small class.) In each case, you'll find a table listing all the properties and methods of the class. If creating the class provided an unusual challenge (aside from the issues already discussed in the chapter), the sections will also include a description of the coding techniques used by the specific class.
To make it easier for you to experiment with the various classes presented in this chapter, we've created a simple starting point, Sub Main in SYSINFOTEST.BAS. This procedure declares variables for each of the various classes and then hits a Stop statement. All you need to do is run Main from the Immediate window, and then, once it's stopped, enter test lines of code in the Immediate window.