Visual Basic Enumeration/Callback Routines

EnumPrinterDrivers: Enumerate Print Drivers on Specific Printer Server
     
Posted:   Monday February 10, 2003
Updated:   Monday December 26, 2011
     
Applies to:   VB5, VB6
Developed with:   VB6, Windows XP
OS restrictions:   Windows 2000, Windows XP. See Prerequisites
Author:   VBnet - Randy Birch
     
Related:   AddPort: Adding and Deleting Application-Defined Ports
AddPrinter: Add/Delete Local/Remote Printers using Existing Drivers
EnumPorts: Identify Windows' Available Ports
EnumPrinters: Enumerating Local and Network Printers
EnumPrinterDrivers: Enumerate Print Drivers on Specific Printer Server
SetDefaultPrinter: Changing Windows' Default Printer
WriteProfileString: Changing Windows' Default Printer
     
 Prerequisites
As coded, this demo uses the DRIVER_INFO_4 structure for Windows 2000 and Windows XP, although the code below can be modified to run on all Windows versions using the appropriate driver info level.

EnumPrinterDrivers enumerates the printer drivers installed on a specified printer server. This demo targets Windows 2000 and Windows XP specifically through the use of the DRIVER_INFO_4 structure.

There are six DRIVER_INFO_* structures available for the various versions of Windows:

Level Structure

1 DRIVER_INFO_1
2 DRIVER_INFO_2
3 Windows 95/98/Me, Windows NT4.0 and later: DRIVER_INFO_3
4 Windows 2000/XP: DRIVER_INFO_4
5 Windows 2000/XP: DRIVER_INFO_5
6 Windows Me, Windows 2000/XP: DRIVER_INFO_6

Each of the different DRIVER_INFO_* types is defined in the code below. In order to allow the routines to handle any of the six DRIVER_INFO_* types (when supported by the operating system), two sets of constants are defined: one, prefixed DRIVER_LEVEL and with the values 1 through 6, represents the DRIVER_INFO_* level you are using in the call. The second, prefixed SIZEOF_DRIVERINFO_, contains a long value representing the size (Len) of the corresponding DRIVER_INFO_* structure.

Therefore, in order to use a DRIVER_INFO_* level  other than the demo's DRIVER_INFO_4, you must change variables in four places within the EnumPrintServerDrivers function:

  • re-define the array pntr() to assign the appropriate DRIVER_INFO_* structure
  • change the ReDim of pntr() from SIZEOFDRIVER_INFO_4 to the corresponding SIZEOF_* constant
  • replace the coded DRIVER_LEVEL4 constant in each of the two calls to EnumPrinterDrivers to the corresponding DRIVER_LEVEL* constant.
 BAS Module Code
None.

 Form Code
Add a command button (Command1) and a listbox (List1) to a form, along with the following code:

Option Explicit
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Copyright ©1996-2011 VBnet/Randy Birch, All Rights Reserved.
' Some pages may also contain other copyrights by the author.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Distribution: You can freely use this code in your own
'               applications, but you may not reproduce 
'               or publish this code on any web site,
'               online service, or distribute as source 
'               on any media without express permission.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Type DRIVER_INFO_1
   pName As Long
End Type

Private Type DRIVER_INFO_2
   cVersion As Long
   pName As Long
   pEnvironment As Long
   pDriverPath As Long
   pDataFile As Long
   pConfigFile As Long
End Type

Private Type DRIVER_INFO_3
   cVersion As Long
   pName As Long
   pEnvironment As Long
   pDriverPath As Long
   pDataFile As Long
   pConfigFile As Long
   pHelpFile As Long
   pDependentFiles As Long
   pMonitorName As Long
   pDefaultDataType As Long
End Type

Private Type DRIVER_INFO_4
   cVersion As Long
   pName As Long
   pEnvironment As Long
   pDriverPath As Long
   pDataFile As Long
   pConfigFile As Long
   pHelpFile As Long
   pDependentFiles As Long
   pMonitorName As Long
   pDefaultDataType As Long
   pszzPreviousNames As Long
End Type

Private Type DRIVER_INFO_5
   cVersion As Long
   pName As Long
   pEnvironment As Long
   pDriverPath As Long
   pDataFile As Long
   pConfigFile As Long
   dwDriverAttributes As Long
   dwConfigVersion As Long
   dwDriverVersion  As Long
End Type

Private Type DRIVER_INFO_6
   cVersion As Long
   pName As Long
   pEnvironment As Long
   pDriverPath As Long
   pDataFile As Long
   pConfigFile As Long
   pHelpFile As Long
   pDependentFiles As Long
   pMonitorName As Long
   pDefaultDataType As Long
   pszzPreviousNames As Long
   ftDriverDate As Long  'FILETIME pointer
   dwlDriverVersion As Long
   pszMfgName As Long
   pszOEMUrl As Long
   pszHardwareID As Long
   pszProvider As Long
End Type

Private Const SIZEOFDRIVER_INFO_1 = 4
Private Const SIZEOFDRIVER_INFO_2 = 24
Private Const SIZEOFDRIVER_INFO_3 = 40
Private Const SIZEOFDRIVER_INFO_4 = 44
Private Const SIZEOFDRIVER_INFO_5 = 36
Private Const SIZEOFDRIVER_INFO_6 = 68

Private Const DRIVER_LEVEL1 = &H1
Private Const DRIVER_LEVEL2 = &H2
Private Const DRIVER_LEVEL3 = &H3
Private Const DRIVER_LEVEL4 = &H4
Private Const DRIVER_LEVEL5 = &H5
Private Const DRIVER_LEVEL6 = &H6

Private Const LB_SETTABSTOPS As Long = &H192

Private Declare Function SendMessage Lib "user32" _
   Alias "SendMessageA" _
  (ByVal hwnd As Long, _
   ByVal wMsg As Long, _
   ByVal wParam As Long, _
   lParam As Any) As Long

Private Declare Function EnumPrinterDrivers Lib "winspool.drv" _
   Alias "EnumPrinterDriversA" _
  (ByVal pName As String, _
   ByVal pEnvironment As String, _
   ByVal Level As Long, _
   pDriverInfo As Any, _
   ByVal cdBuf As Long, _
   pcbNeeded As Long, _
   pcReturned As Long) As Long

Private Declare Function lstrcpyA Lib "kernel32" _
  (ByVal RetVal As String, ByVal Ptr As Long) As Long
                        
Private Declare Function lstrlenA Lib "kernel32" _
  (ByVal Ptr As Any) As Long

Private Declare Sub CopyMemory Lib "kernel32" _
   Alias "RtlMoveMemory" _
  (dst As Any, src As Any, ByVal bcount As Long)



Private Sub Form_Load()
   
   ReDim TabArray(0 To 0) As Long
   
   Command1.Caption = "Enum Printer Drivers"
   
   TabArray(0) = 60

   Call SendMessage(List1.hwnd, LB_SETTABSTOPS, 0&, ByVal 0&)
   Call SendMessage(List1.hwnd, LB_SETTABSTOPS, 1&, TabArray(0))
   List1.Refresh
   
End Sub


Private Sub Command1_Click()
   
   Dim numPrinters As Long

  'list printers and drivers on the 
  'local machine, for the environment 
  'specified. Note that if vbNullString 
  'is passed as the environment parameter, 
  'the function uses the current environment of 
  'the caller/client (not of the destination/server). 
  'Under XP the string "All" can also be used 
  'to enumerate printer drivers for all platforms 	
  'installed on the specified server.
   numPrinters = EnumPrintServerDrivers(vbNullString, "Windows NT x86", List1)
  'numPrinters = EnumPrintServerDrivers("\\svrWhatever", "All", List1)
      
End Sub


Private Function EnumPrintServerDrivers(ByVal sServer As String, _
                                        ByVal sEnviron As String, _
                                        ctl As ListBox) As Long
    
   Dim cbRequired As Long
   Dim cbBuffer As Long
   Dim pntr() As DRIVER_INFO_4
   Dim nEntries As Long
   Dim cnt As Long
   Dim j As Long
   Dim dwFileCount As Long
   Dim sDriverFiles() As String

   ctl.Clear
   
  'To determine the required buffer size,
  'call EnumPrinterDrivers with cbBuffer set
  'to zero. The call will fails specifying
  'ERROR_INSUFFICIENT_BUFFER and filling in
  'cbRequired with the required size, in bytes,
  'of the buffer required to hold the array
  'of structures and data.
   Call EnumPrinterDrivers(sServer, _
                           sEnviron, _
                           DRIVER_LEVEL4, _
                           0, 0, _
                           cbRequired, _
                           nEntries)
            
   
  'Allocate space for the structure
   ReDim pntr((cbRequired \ SIZEOFDRIVER_INFO_4))
       
  'Set cbBuffer equal to the size of the buffer
   cbBuffer = cbRequired
    
  'Enumerate the print drivers. If the
  'function succeeds, the return value
  'is nonzero; 0 if it fails
   If EnumPrinterDrivers(sServer, _
                         sEnviron, _
                         DRIVER_LEVEL4, _
                         pntr(0), _
                         cbBuffer, _
                         cbRequired, _
                         nEntries) <> 0 Then
              
     'sanity check - these should still be the same!
      If cbRequired = cbBuffer Then
        
        'for each returned entry
         For cnt = 0 To nEntries - 1
           
            With pntr(cnt)
                        
              'add the printer name to the list
               ctl.AddItem "printer:" & vbTab & GetStrFromPtrA(.pName)
               
              'add some other driver info
               ctl.AddItem "environ:" & vbTab & LCase$(GetStrFromPtrA(.pEnvironment))
               ctl.AddItem "driver path:" & vbTab & LCase$(GetStrFromPtrA(.pDriverPath))
               ctl.AddItem "config file:" & vbTab & LCase$(GetStrFromPtrA(.pConfigFile))
               ctl.AddItem "data file:" & vbTab & LCase$(GetStrFromPtrA(.pDataFile))
                           
              'determine if the print driver lists
              'dependent files
               dwFileCount = GetDependentDriverFiles(.pDependentFiles, sDriverFiles())
                  
               If dwFileCount > 0 Then
               
                  ctl.AddItem "dependent files:" & vbTab & dwFileCount
               
                 'add each to the list
                  For j = 0 To dwFileCount - 1 '0-based!
                     ctl.AddItem vbTab & LCase$(sDriverFiles(j))
                  Next
               
               Else
               
                 'no dependencies returned
                  ctl.AddItem "dependent files:" & vbTab & dwFileCount
                  ctl.AddItem vbTab & "(no dependent files)"
                  
               End If  'dwFileCount > 0
                     
            End With  'pntr(cnt)
            
           'add spacer line
            ctl.AddItem ""
              
         Next cnt
           
      Else
         ctl.AddItem "Error enumerating printer drivers."
      End If  'cbRequired
        
   Else
      ctl.AddItem "Error enumerating printer drivers."
   End If  'EnumPrinterDrivers
   
  'return the number of entries read
  'as a sign of success
   EnumPrintServerDrivers = nEntries
       
End Function


Public Function GetStrFromPtrA(ByVal lpszA As Long) As String

   GetStrFromPtrA = String$(lstrlenA(ByVal lpszA), 0)
   Call lstrcpyA(ByVal GetStrFromPtrA, ByVal lpszA)
   
End Function


Public Function GetDependentDriverFiles(ByVal lpszA As Long, _
                                        sDriverFiles() As String) As Long

   Dim buff As String
   Dim pos As Long
   
  'ensure string has data
   If lstrlenA(ByVal lpszA) > 0 Then
   
     'pad a buffer large enough to
     'hold the dependent strings. On
     'my system the Epson driver has
     '71 dependent files. If pos below
     'fails to locate the pair of terminating
     'nulls indicating the end of data, buff
     'is too small.
      buff = Space$(8192)
      
     'copy the data from the string
     'pointed to by lpsza
      CopyMemory ByVal buff, ByVal lpszA, Len(buff)
   
     'Sanity check. The MSDN states each driver
     'file is separated from the next by a null
     'char, with the entire list terminated by
     'a pair of nulls. This checks to ensure
     'the pair are present. Note too the full 
     'path is returned for each file!
      pos = InStr(buff, vbNullChar & vbNullChar)
   
      If pos > 0 Then
      
        'remove the pair of terminating nulls
         buff = Left$(buff, pos - 1)
         
        'create an array from the remaining data
         sDriverFiles() = Split(buff, vbNullChar)
         
        'return the number of files in the
        'array, adding 1 to accommodate the
        '0-based array.
         GetDependentDriverFiles = UBound(sDriverFiles) + 1
         Exit Function
      
      End If
   
   End If
   
   GetDependentDriverFiles = 0
   
End Function
 Comments
 

 
 

PayPal Link
Make payments with PayPal - it's fast, free and secure!

 
 
 
 

Copyright ©1996-2011 VBnet and Randy Birch. All Rights Reserved.
Terms of Use  |  Your Privacy

 

Hit Counter