Using the SystemParametersInfo Function
Calling the SystemParametersInfo function is significantly more complex than calling GetSystemMetrics. Because SystemParametersInfo allows you to either set or retrieve information concerning your system's hardware and configuration, depending on the constant you send it, it must provide methods for both returning information and returning status (success or failure) information.
To make this possible, SystemParametersInfo requires four parameters:
A constant representing the information to be set or retrieved, beginning with SPI_.
A long integer, passed by value, sending information to SystemParametersInfo. Normally, this is where you place information to be used by SystemParametersInfo when it's setting values for you.
A long integer, passed by reference. This long integer can be the address of a variable or data structure, and it's through this parameter (declared “As Any” in your VBA code) that SystemParametersInfo can send information back to your functions.
- A long integer, passed by value, that tells SystemParametersInfo how you want it to broadcast information about the changes you've asked it to make. You can have your change made only for this session, or, if you want to make the change persistent, you can tell SystemParametersInfo to write the change to the Registry. In addition, if you write the change to the Registry, you can also instruct SystemParametersInfo to inform all other running Windows applications that you've made the change.
Of course, you needn't be concerned with all this information if you're just going to use the classes as we've provided them. If you want to add to the classes or modify the existing functionality, though, you'll need to be aware of how SystemParametersInfo uses each of these parameters.
In the sample classes, we opted for the “save and tell all” option when calling SystemParametersInfo; if you make any change, the code will write the change to the Registry and broadcast a message to all other running applications as well. If you want to change this behavior, change the value of the SPIF_TELLALL constant in each module. Set the constant to 0 to do nothing, or set it to be one or more of SPIF_UPDATEINIFILE and SPIF_SENDWININICHANGE, combined with the Or operator. The classes currently use the two constants combined.
For example, to get and set the number of screen lines to scroll when you scroll your mouse wheel (if you have a mouse wheel, of course), you can use SystemParametersInfo with its SPI_GETWHEELSCROLLLINES and SPI_SETWHEELSCROLLLINES constants. The WheelScrollLines property of the Mouse class (MOUSE.CLS) uses the Property Let and Get procedures, as shown in Listing 9.1.
In this example, the Property Let procedure is simple—it calls SystemParametersInfo, passing the SPI_SETWHEELSCROLLLINES constant, a value indicating the requested scroll lines, a 0 placeholder for the third parameter, and the SPIF_TELLALL constant indicating that the function call should save the information and update any running application. The Property Get procedure, however, is a bit more complex. In this case, you must first declare a variable to hold the returned value; call SystemParametersInfo, passing that variable as the third parameter; and return the filled-in value of the variable as the Property Get return value.
Listing 9.1: Use SystemParametersInfo to Get and Set System Information
Property Let WheelScrollLines(Value As Long) ' Works in Windows NT Only. ' Set the number of lines scrolled with each ' click of the mouse wheel. ' Set to 0 to disable wheel scrolling. ' Set to -1 to cause a scroll to act ' like a click in the PageUp or PageDown region of the ' scroll bar. Call SystemParametersInfo(SPI_SETWHEELSCROLLLINES, _ Value, 0, SPIF_TELLALL) End Property Property Get WheelScrollLines() As Long ' NT Only. ' Determine the number of lines scrolled with each ' click of the mouse wheel. Dim lngValue As Long Call SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, _ lngValue, 0) WheelScrollLines = lngValue End Property
In some cases, the Property Let and Get pairings require one call to GetSystemMetrics (to get the value) and one to SystemParametersInfo (to set the value). This is, of course, the sort of thing that makes the class module wrappers so convenient; you don't have to dig through the reference manuals to find that it requires two separate function calls to get your work done. For example, Windows allows you to control the width (and height) of the rectangle bordering the mouse position that determines whether the next click constitutes a double-click. To get this value, you call GetSystemMetrics. To set the value, however, you must call SystemParametersInfo. Listing 9.2 shows the code used by the DoubleClickX property of the Mouse class, which calls both functions.
Listing 9.2: Some Properties Require both GetSystemMetrics and SystemParametersInfo
Property Get DoubleClickX() As Long ' Width, in pixels, of the rectangle enclosing the ' location of the first mouse click in a double-click sequence. ' Second click must occur within the boundaries ' of this rectangle. DoubleClickX = GetSystemMetrics(SM_CXDOUBLECLK) End Property Property Let DoubleClickX(Width As Long) Call SystemParametersInfo(SPI_SETDOUBLECLKWIDTH, Width, _ 0, SPIF_TELLALL) End Property
Of course, the third parameter in a call to SystemParametersInfo might also be a reference to a user-defined type. If it is, SystemParametersInfo will fill in the datatype with the appropriate information. For example, the MinAnimation property of the Screen class (SCREEN.CLS) indicates whether Windows should display animation as it's minimizing windows. The code for the associated Property Get procedure is shown in Listing 9.3. This call to the SystemParametersInfo function requires you to send a variable of the ANIMATIONINFO datatype, with its lngSize member filled in with the size of the structure. SystemParametersInfo either fills in the lngMinAnimate member of the structure with the current animation setting (in the Property Get procedure) or gets the value from this member and applies it (in the Property Let procedure). In either case, you need to use the Len function to find the length of the data structure and place that value in the lngSize member of the structure before calling SystemParametersInfo. The class modules in this chapter use this technique several times, calling SystemParametersInfo with various datatypes.
Listing 9.3: Use SystemParametersInfo with a User-Defined Type
Private Type ANIMATIONINFO lngSize As Long lngMinAnimate As Long End Type Property Get MinAnimation() As Boolean ' Returns the state of minimize animation. Dim ai As ANIMATIONINFO ai.lngSize = Len(ai) Call SystemParametersInfo(SPI_GETANIMATION, _ ai.lngSize, ai, 0) MinAnimation = ai.lngMinAnimate End Property