Win32 API Programming with Visual Basic

Page 118
  7. System Information Functions  
   
  Let us put some of what we have learned to immediate practice. One of the areas of the Win32 API that we can use profitably even without knowing much about how Windows itself works is the area devoted to system information.  
   
  There are several API functions that can be used to gather information about the computer upon which the functions are running. The Win32 System Information functions are listed in Table 7-1.  
   
  Table 7-1. System Information Functions  
   
  GetComputerName  
   
  GetSystemMetrics  
   
  GetWindowsDirectory  
   
  GetKeyboardType  
   
  GetTempPath  
   
  SetComputerName  
   
  GetSysColor  
 
   
  GetUserNameSesSysColors  
   
  GetSystemDirectory  
   
  GetVersion  
   
  SystemParametersInfo  
   
  GetSystemInfo  
   
  GetVersionEx  
 

   
  Let us look at a few of these functions.  
 
  The Computer's Name  
   
  The GetComputerName function is used to get the current computer's name. The corresponding SetComputerName will set the computer's name. The VC++ declaration is:  
 
  BOOL GetComputerName(

   LPTSTR lpBuffer,    // address of name buffer

   LPDWORD nSize      // address of size of name buffer

);

 
Page 119
   
  Here the parameters are an LPSTR and a pointer to a DWORD, and the return type is BOOL. A corresponding VB declaration is:  
 
  Declare Function GetComputerName Lib "kernel32" Alias "GetComputerNameA" ( _

   ByVal lpBuffer As String, _

   nSize As Long _

) As Long

 
   
  According to the documentation, under Windows 9x the GetComputerName function will fail if the input size is less than the constant MAX_COMPUTERNAME_LENGTH + 1. This constant is defined in WINBASE.H as:  
 
  #define MAX_COMPUTERNAME_LENGTH 15  
   
  which in VB becomes:  
 
  Public Const MAX_COMPUTERNAME_LENGTH = 15  
   
  We can now write a small function to return the computer's name:  
 
  Public Function GetTheComputerName As String

Dim s As String

s = String(MAX_COMPUTERNAME_LENGTH + 1, 0)

lng = GetComputerName(s, MAX_COMPUTERNAME_LENGTH)

GetComputerName = Trim0(s)

End Function

 
   
  (Recall that Trim0 is a simple function to trim a string at the first null.) On my system, the return value is:  
 
  SRCOMPUTER  
 
  Special Windows Paths  
   
  The GetWindowsDirectory, GetSystemDirectory, and GetTempPath retrieve the path to the Windows, Windows System, and Windows temporary files directories. The functions are defined as follows:  
 
  UINT GetSystemDirectory(

   LPTSTR lpBuffer,     // address of buffer for system directory

   UINT uSize           // size of directory buffer

);

UINT GetWindowsDirectory( _

   LPTSTR lpBuffer,     // address of buffer for Windows directory

   UINT uSize           // size of directory buffer

);

DWORD GetTempPath(

   DWORD nBufferLength // size, in characters, of the buffer

 

 

Page 120
 
     LPTSTR lpBuffer     // pointer to buffer for temp path

);

 
   
  The VB declarations are:  
 
  Declare Function GetSystemDirectory Lib "kernel32" Alias "GetSystemDirectoryA" ( _

   ByVal lpBuffer As String, _

   ByVal nSize As Long _

) As Long

Declare Function GetWindowsDirectory Lib "kernel32" _

Alias "GetWindowsDirectoryA" ( _

   ByVal lpBuffer As String, _

   ByVal nSize As Long _

) As Long

Declare Function GetTempPath Lib "kernel32" Alias "GetTempPathA" ( _

   ByVal nBufferLength As Long, _

   ByVal lpBuffer As String _

) As Long

 
   
  Each of these functions returns the number of characters placed in the string buffer. The size of the buffers should be set one larger than the symbolic constant:  
 
  Public Const MAX_PATH = 260  
   
  Here is some sample code:  
 
  Dim s As String, lng As Long

s = String(MAX_PATH + 1, 0)

lng = GetWindowsDirectory(s, MAX_PATH)

Debug.Print Left$(s, lng)

lng=GetSystemDirectory(s, MAX_PATH)

Debug.Print Left$(s, lng)

lng = GetTempPath(MAX_PATH, s)

Debug.Print Left$(s, lng)

 
   
  On my system, the output is:  
 
  C:\WINNT

C:\WINNT\System32

C:\TEMP\

 
   
  Note that, in each case, the documentation says that the return value is the number of characters copied to the buffer, not including the terminating null. This is why we can use the Left$ function to extract just the return string. On the other hand, the documentation for GetComputerName simply says that the return value in nonzero on success, so we used the Trim0 function instead.  
Page 121
 
  The Operating System Version  
   
  The GetVersionEx function returns version information about the Windows operating system and can be used to determine whether the system is running Windows 95, Windows 98, or Windows NT. The declaration is:  
 
  BOOL GetVersionEx(

   LPOSVERSIONINFO lpVersionInformation   // pointer to version info structure

);

 
   
  where lpVersionInformation is a pointer to an OSVERSIONINFO structure, which is defined as follows:  
 
  typedef struct_OSVERSIONINFO{

   DWORD dwOSVersionInfoSize;

   DWORD dwMajorVersion;

   DWORD dwMinorVersion;

   DWORD dwBuildNumber;

   DWORD dwPlatformId;

   TCHAR szCSDVersion[ 128 ];

} OSVERSIONINFO;

 
   
  The documentation for this structure is as follows:  
 
  dwOSVersionInfoSize

Specifies the size, in bytes, of the OSVERSIONINFO structure. This is a common requirement in structures. Since a DWORD is a 4-byte unsigned long and since VB will translate the 128-character string into a 128-byte ANSI character array, the total size is 4*5+128=148.This is also the value returned by the Len function, but not the LenB function, which doesn't take into account the Unicode-to-ANSI translation

 
 
  dwMajorVersion

Indicates the major version number of the operating system. For example, for Windows NT Version 3.51, the major version number is 3. For Windows NT 4. 0 and Windows 9x, the major version number is 4.

 
 
  dwMinorVersion

Indicates the minor version number of the operating system. For example, for Windows NT Version 3.51, the minor version number is 51. For Windows NT 4.0, the minor version number is 0. For Windows 95, the minor version number is 0. For Windows 98, the minor version number is 10.

 
 
  dwBuildNumber

Indicates the build number of the operating system under Windows NT. For Windows 9x, the low-order word contains the build number of the operating system, and the high-order word contains the major and minor version numbers.

 
Page 122
 
  dwPlatformId

Identifies the operating system platform, and can be one of the following values:

 
 
  VER_PLATFORM_WIN32s (= 0)

Win32s running on Windows 3.1

 
 
  VER_PLATFORM_WIN32_WINDOWS (= 1)

Win32 running on Windows 95 or Windows 98

 
 
  VER_PLATFORM_WIN32_NT (= 2)

Win32 running on Windows NT

 
 
  szCSDVersion

For Windows NT, contains a null-terminated string, such as ''Service Pack 3," that indicates the latest Service Pack installed on the system. If no Service Pack has been installed, the string is empty. For Windows 95, this string contains a null-terminated string that provides arbitrary additional information about the operating system.

 
   
  Translating the GetVersionEx declaration into VB gives:  
 
  Declare Function GetVersionEx Lib "kernel32" Alias "GetVersionExA" ( _

   lpVersionInformation As OSVERSIONINFO _

) As Long

 
   
  The intention here is to pass the address of an OSVERSIONINFO structure by reference.  
   
  To translate the structure definition, we replace the DWORDs with Longs, and the TCHAR array, being fixed length, with either a fixed-length string or a byte array. In the former case, VB will do the usual Unicode-to-ANSI translation, but that's fine:  
 
  Type OSVERSIONINFO

   dwOSVersionInfoSize As Long

   dwMajorVersion As Long

   dwMinorVersion As Long

   dwBuildNumber As Long

   dwPlatformId As Long

   szCSDVersion As String * 128 ' 128 characters

End Type

 
   
  Let's give this a try:  
 
  Public Sub PrintVersionInfo

Dim lret As Long

Dim osverinfo As OSVERSIONINFO

osverinfo.dwOSVersionInfoSize = Len(osverinfo)

lret = GetVersionEx(osverinfo)

If lret = 0 Then

   RaiseApiError lret

 

 

Page 123
 
  Else

   Debug.Print "Version: " & osverinfo.dwMajorVersion & "." _

      & osverinfo.dwMinorVersion

   Debug.Print "Build: " & osverinfo.dwBuildNumber

   Debug.Print "Platform ID: " & osverinfo.dwPlatformId

   Debug.Print "String: " & osverinfo.szCSDVersion

End If

End Sub

 
   
  (You will find the RaiseAPIError function defined at the end of Chapter 3, API Declarations.) The output on my system is:  
 
  Version: 4.0

Build: 1381

Platform ID: 2

String: Service Pack 3

 
   
  Here is a short function that returns the name of the operating system:  
 
  Public Function GetOSVersion() As String

' Return name of operating system

Dim lret As Long

Dim osverinfo As OSVERSIONINFO

osverinfo.dwOSVersionInfoSize = Len(osverinfo)

lret = GetVersionEx(osverinfo)

If lret = 0 Then

   GetOSVersion = "unknown"

Else

   Select Case osverinfo.dwPlatformId & "/" & osverinfo.dwMajorVersion

 & "/" & osverinfo.dwMinorVersion

      Case "1/4/0"

         GetOSVersion = "Win95"

      Case "1/4/10"

         GetOSVersion = "Win98"

      Case "2/3/51"

         GetOSVersion = "WinNT351"

      Case "2/4/0"

         GetOSVersion = "WinNT4"

   End Select

End If

End Function

 
 
  System Metrics  
   
  The GetSystemMetrics function retrieves metric (measurement) information about the system. The VC++ declaration is simply as follows.  
Page 124
 
  int GetSystemMetrics(

   int nIndex    // system metric or configuration setting to retrieve

);

 
   
  This translates into VB as:  
 
  Declare Function GetSystemMetrics Lib "user32" ( _

   ByVal nIndex As Long _

) As Long

 
   
  The nIndex parameter is set to one of 49 different possible constants. The requested measurement (generally in pixels or nondimensional units) is returned by the function.  
   
  To give you an idea of the type of information returned, here is a sampling of the constants for this function. All height and width measurements are in pixels:  

Const SM_CMOUSEBUTTONS = 43 ' Number of mouse buttons Const SM_MOUSEWHEELPRESENT = 75 ' True if mouse wheel present ' (Win NT 4 or Win 98 only) Const SM_SWAPBUTTON = 23 ' True if mouse buttons swapped Const SM_CXBORDER = 5 ' Width and height of a window border Const SM_CYBORDER = 6 Const SM_CXSCREEN = 0 ' Width and height of screen Const SM_CYSCREEN = 1 Const SM_CXFULLSCREEN = 16 ' Width and height of client area for a Const SM_CYFULLSCREEN = 17 ' full-screen window Const SM_CXHTUMB = 10 ' Width of the thumb box in a horizontal ' scroll bar. Const SM_CXICONSPACING = 38 ' Dimensions of a grid cell for items in Const SM_CYICONSPACING = 39 ' large icon view. Const SM_CYCAPTION = 4 ' Height of a normal caption area.

 
  System Parameters  
   
  The SystemParametersInfo function is a powerful function for getting or setting system-wide parameters. The function can also update the user profile while setting a parameter. The declaration is:  
 
  BOOL SystemParametersInfo(

   UINT uiAction, // system parameter to query or set

   UINT uiParam,  // depends on action to be taken

   PVOID pvParam, // depends on action to be taken

   UINT fWinIni   // user profile update flag

);

 
Page 125
   
  which can be translated into VB as:  
 
  Declare Function SystemParametersInfo Lib "user32" _

Alias "SystemParametersInfoA" ( _

   ByVal uiAction As Long, _

   ByVal uiParam As Long, _

   pvParam As Any, _

   ByVal fWinIni As Long _

) As Long

 
   
  Note that, for type safety, we can alter the data type of the pvParam depending upon the action to be taken.  
   
  This powerful function can take at least 90 different uiAction values. We will content ourselves with a single example. Note that the function returns a nonzero value on success and 0 on failure. It will set GetLastError, so we can use VB's Err.LastDLLError value.  
   
  System Icon Metrics  
   
  We can get or set the characteristics of system icons (such as those that appear on the desktop) using the constants  
 
  Public Const SPI_GETICONMETRICS = 45

Public Const SPI_SETICONMETRICS = 46

 
   
  For SPI_GETICONMETRICS, the documentation says that the parameter pvParam must point to an ICONMETRICS structure that receives the information. For SPI_SETICONMETRICS, the parameter pvParam must point to an ICONMETRICS structure that contains the new parameters.  
   
  In both cases, we must also set the cbSize member of the ICONMETRICS structure (see the following) and the uiParam parameter of SystemParametersInfo to the size, in bytes, of the structure.  
   
  The ICONMETRICS structure has declaration:  

typedef struct tagICONMETRICS { UINT cbSize; int iHorzSpacing; int iVertSpacing; int iTitleWrap; LOGFONT lfFont; } ICONMETRICS, FAR **LPICONMETRICS;

   
  and the LOGFONT structure is:  
 
  typedef struct tagLOGFONT { // lf

   LONG lfHeight;

   LONG lfWidth;

   LONG lfEscapement;

   LONG lfOrientation;

 

 

Page 126
 
     LONG lfWeight;

   BYTE lfItalic;

   BYTE lfUnderline;

   BYTE lfStrikeOut;

   BYTE lfCharSet;

   BYTE lfOutPrecision;

   BYTE lfClipPrecision;

   BYTE lfQuality;

   BYTE lfPitchAndFamily;

   TCHAR lfFaceName[LF_FACESIZE];

} LOGFONT;

 
   
  where:  
 
  Public Const LF_FACESIZE = 32  
   
  There is an important point to note here. Very often one structure will contain pointers to other structures. In this case, however, the lfFont variable is not a pointer it is the actual structure. Thus, we must combine the two structures when creating a VB version:  
 
  Public Type ICONMETRICS

   cbSize As Long

   iHorzSpacing As Long

   iVertSpacing As Long

   iTitleWrap As Long

   lfHeight As Long

   lfWidth As Long

   lfEscapement As Long

   lfOrientation As Long

   lfWeight As Long

   lfItalic As Byte

   lfUnderline As Byte

   lfStrikeOut As Byte

   lfCharSet As Byte

   lfOutPrecision As Byte

   lfClipPrecision As Byte

   lfQuality As Byte

   lfPitchAndFamily As Byte

   lfFaceName As String * LF_FACESIZE

End Type

 
   
  Note that this structure behaves well with respect to member alignment. (I'll bet you forgot to check that!) We could have used a byte array for lfFaceName as well as a fixed-length string. A fixed-length string is easier to use when outputting the return value, however.  
   
  Here is some code that uses this function:  
 
  Public Sub PrintIconMetrics

Dim im As ICONMETRICS

im.cbSize = Len(im)

lret = SystemParametersInfo(SPI_GETICONMETRICS, Len(im), im, 0&

 

 

Page 127
 
  If lret = 0 Then

   RaiseApiError Err.LastDllError

Else

   Debug.Print "Hor Spacing:" & im.iHorzSpacing

   Debug.Print "Vert Spacing:" & im.iVertSpacing

   Debug.Print im.lfFaceName & "/"

End If

End Sub

 
   
  The output on my system is:  
 
  Hor Spacing:101

Vert Spacing:109

MS Sans Serif

 
 
  System Colors  
   
  The functions GetSysColor and SetSysColors are used to get and set colors for various system elements, such as buttons, title bars, and so on. These items can also be set by the user through the Display applet in the Control Panel.  
   
  The declaration of GetSysColor is simple:  
 
  DWORD GetSysColor(

   int nIndex    // display element

);

 
   
  where nIndex can be set to one of many symbolic constants, for example:  
 
  #define COLOR_ACTIVECAPTION 2  
   
  In VB this becomes:  
 
  Declare Function GetSysColor Lib "user32" (ByVal nIndex As Long) As Long

Public Const COLOR_ACTIVECAPTION = 2

 
   
  The return value is the RGB color. In particular, each color gets a byte in the returned unsigned long: red is the least significant byte, green is next, followed by blue. The high-order byte is 0. (These color bytes appear in reverse order in the long because when it is stored in memory, the bytes are reversed.)  
   
  The SetSysColors function is:  

BOOL WINAPI SetSysColors( int cElements, // number of elements to change CONST INT *lpaElements, // address of array of elements CONST COLORREF *lpaRgbValues // address of array of RGB values );

   
  Here, cElements specifies the number of system elements whose color we want to change, lpaElements is a pointer to a VC++ integer array that contains the indices of elements to change, and lpaRgbValues points to a VC++ integer array of new RGB color values.  
Page 128
   
  The VB version is:  
 
  Declare Function SetSysColors Lib "user32" ( _

   ByVal nChanges As Long, _

   lpSysColor As Long, _

   lpColorValues As Long _

) As Long

 
   
  where we must call the function by specifying the first array element for each array parameter.  
   
  Note finally that both functions return 0 on success and set GetLastError.  
   
  The following example will flash the active title bar between its default color and red every 0.5 seconds, finally leaving the title bar in its original state:  
 
  Public Function FlashTitleBarColor()

Dim i As Integer

Dim lret As Long

Dim SaveColor As Long

Dim lIndices(0 To 0) As Long

Dim lNewColors(0 To 0) As Long

' Get and save current color

SaveColor = GetSysColor(COLOR_ACTIVECAPTION)

Debug.Print "Current color:" & Hex(SaveColor)

For i = 1 To 5

   ' Change to red

   lIndices(0) = COLOR_ACTIVECAPTION

   lNewColors(0) = &HFF

   lret = SetSysColors(1&, lIndices(0), lNewColors(0))

   If lret = 0 Then

      RaiseApiError Err.LastDllError

   End If

   Delay 0.5

   ' Restore original color

   lIndices(0) = COLOR_ACTIVECAPTION

   lNewColors(0) = SaveColor

   lret = SetSysColors(1&, lIndices(0), lNewColors(0))

   If lret = 0 Then

      RaiseApiError Err.LastDllError

   End If

   Delay 0.5

Next

End Function

 
Page 129
   
  The Delay utility is just:  
 
  Sub Delay(rTime As Single)

'Delay rTime seconds (min=.01, max=300)

Dim OldTime As Variant

'Safty net

If rTime < 0.01 Or rTime > 300 Then rTime = 1

OldTime = Timer

Do

    DoEvents

Loop Until Timer - OldTime >=rTime

End Sub

Категории