| 
 | 
|  |   |  | |
|  |  |  | |
|  |  | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 
 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 
 | ||
| Visual Basic System Services WriteProfileString: Changing Windows' Default Printer | ||
| Posted: | Monday March 20, 2000 | |
| Updated: | Monday December 26, 2011 | |
| Applies to: | VB4-32, VB5, VB6 | |
| Developed with: | VB6, Windows NT4 | |
| OS restrictions: | None | |
| 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 | 
| None. | 
|  | 
|  I
         suppose that this page could really be listed as a FAQ - it seems not a week goes by without a newsgroup post asking how to change the
         default printer from VB. This page details the steps to achieve this 
		using any Windows version, and is loosely based on the MSKB article Q167735 - FIX:
         Setting Printer to Item in the Printers Collection Fails. The article also discusses the more complex method of doing this under Win9x, for
         those interested. The traditional approach to setting the default printer, and one that should work according to documentation, is to enumerate the Printers collection until the desired printer is located, then assigning that to the Printer object. This doesn't work as advertised. The printer name will change, but output still goes to the original default device. Under Win9x, installed printers are listed in win.ini under the PrinterPorts key, with the system default printer listed under the Device key, and various documentation suggests that changing this key sets the default printer. But if you examine the win.ini file on a Window NT or later system, the file does not contain any printer port or default printer info. Not to worry. By default, using either GetProfileString / WriteProfileString or GetPrivateProfileString / WritePrivateProfileString on Window NT or later, the APIs actually first look to the registry under the key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\IniFileMapping for the ini file name of interest. If it's not found, then the physical disk ini file itself is checked. In the case of win.ini, if it's found in the registry under the key above, it is further examined for the section name desired (PrinterPorts). The registry value assigned to this key point to the location within the registry of the actual installed printers data (which in my case this points to "USR:Software\Microsoft\Windows NT\CurrentVersion\PrinterPorts"). Under the PrinterPorts key the installed printers are listed. As well, the default printer setting corresponding to the expected ini file "Device" entry is stored in the \windows section under that same parent key. When an operation has been mapped, the Get(Private)ProfileString functions retrieve information from the registry, not from the physical initialization file. This change in the storage location has no effect on the function's behavior and is transparent to the calling application. What this all means is that for Windows 9x the code sets the default printer. And for Window NT or later it means there is no need to resort to registry-reading/writing calls - the familiar ini file APIs can be utilized to change the default printer as outlined below. The code provides the means to enumerate the installed printers and to set a new default. Note that in performing this that changing the default printer affects all applications on the system. Therefore, it would be prudent to provide additional code to reset the original user's preference once printing has completed. To see the effect of this demo, I recommend constructing as below, then start an additional new project (so that there is no interaction between VB projects open), add a VB Common Dialog control and single button with the single command "CommonDialog1.ShowPrinter". Run this and keep it open. Also open your Printers folder and watch the default printer settings change. | 
| BAS Module Code | 
| None. | 
|  | 
| Form Code | 
|   | 
| Create a form containing a list box and command button, using the default names. Add the following code to the form: | 
|  | 
| 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 Const HWND_BROADCAST As Long = &HFFFF&
Private Const WM_WININICHANGE As Long = &H1A
Private Declare Function GetProfileString Lib "kernel32" _
   Alias "GetProfileStringA" _
  (ByVal lpAppName As String, _
   ByVal lpKeyName As String, _
   ByVal lpDefault As String, _
   ByVal lpReturnedString As String, _
   ByVal nSize As Long) As Long
Private Declare Function WriteProfileString Lib "kernel32" _
   Alias "WriteProfileStringA" _
  (ByVal lpszSection As String, _
   ByVal lpszKeyName As String, _
   ByVal lpszString As String) As Long
   
Private Declare Function SendNotifyMessage Lib "user32" _
   Alias "SendNotifyMessageA" _
  (ByVal hwnd As Long, _
   ByVal msg As Long, _
   ByVal wParam As Long, _
   lParam As Any) As Long   
   
         
Private Sub Form_Load()
   
    ProfileLoadWinIniList List1, "PrinterPorts"
    Command1.Enabled = False
    
End Sub
Private Sub Command1_Click()
   Call SetDefaultPrinterWinNT
End Sub
Private Sub List1_Click()
   Command1.Enabled = List1.ListIndex > -1
   
End Sub
Private Sub SetDefPrinter(ByVal PrinterName As String, _
                          ByVal DriverName As String, _
                          ByVal PrinterPort As String)
   Dim DeviceLine As String
    
  'rebuild a valid device line string
   DeviceLine = PrinterName & "," & DriverName & "," & PrinterPort
   
  'Store the new printer information in the
  '[WINDOWS] section of the WIN.INI file for
  'the DEVICE= item
   Call WriteProfileString("windows", "Device", DeviceLine)
    
  'Cause all applications to reload the INI file
   Call SendNotifyMessage(HWND_BROADCAST, WM_WININICHANGE, 0, ByVal "windows")
    
End Sub
Private Sub GetDriverAndPort(ByVal Buffer As String, _
                             DriverName As String, _
                             PrinterPort As String)
   Dim posDriver As Long
   Dim posPort As Long
   DriverName = ""
   PrinterPort = ""
  'The driver name is first in the string
  'terminated by a comma
   posDriver = InStr(Buffer, ",")
   
   If posDriver > 0 Then
     'Strip out the driver name
      DriverName = Left(Buffer, posDriver - 1)
     'The port name is the second entry after
     'the driver name separated by commas.
      posPort = InStr(posDriver + 1, Buffer, ",")
      If posPort > 0 Then
      
        'Strip out the port name
         PrinterPort = Mid(Buffer, posDriver + 1, posPort - posDriver - 1)
         
       End If
   End If
   
End Sub
Private Function ProfileLoadWinIniList(lst As ListBox, _
                                       lpSectionName As String) As Long
'Load the listbox data from win.ini.
   Dim success As Long
   Dim nSize As Long
   Dim lpKeyName As String
   Dim ret As String
  
  'call the API passing null as the parameter
  'for the lpKeyName parameter. This causes
  'the API to return a list of all keys under
  'that section. Pad the passed string large
  'enough to hold the data. Adjust to suit.
   ret = Space$(8102)
   nSize = Len(ret)
   success = GetProfileString(lpSectionName, _
                              vbNullString, _
                              "", _
                              ret, _
                              nSize)
   
  'The returned string is a null-separated
  'list terminated by a pair of null characters.
   If success Then
    
     'trim terminating null and trailing spaces
      ret = Left$(ret, success)
      
        'with the resulting string,
        'extract each element
         Do Until ret = ""
      
           'strip off an item and
           'add the item to the listbox
            lpKeyName = StripNulls(ret)
            lst.AddItem lpKeyName
      
         Loop
  
   End If
  
  'return the number of items as an
  'indicator of success
   ProfileLoadWinIniList = lst.ListCount
End Function
Private Function StripNulls(startstr As String) As String
 'Take a string separated by chr$(0)
 'and split off 1 item, shortening the
 'string so next item is ready for removal.
  Dim pos As Long
  pos = InStr(startstr$, Chr$(0))
  
  If pos Then
      
      StripNulls = Mid$(startstr, 1, pos - 1)
      startstr = Mid$(startstr, pos + 1, Len(startstr))
    
  End If
End Function
Private Sub SetDefaultPrinterWinNT()
   Dim Buffer As String
   Dim DeviceName As String
   Dim DriverName As String
   Dim PrinterPort As String
   Dim PrinterName As String
   Dim r As Long
   
   If List1.ListIndex > -1 Then
        
     'Get the printer information for the currently selected
     'printer in the list. The information is taken from the
     'WIN.INI file.
      Buffer = Space(1024)
      PrinterName = List1.list(list1.ListIndex)
      
      Call GetProfileString("PrinterPorts", _
                             PrinterName, "", _
                             Buffer, Len(Buffer))
 
     'Parse the driver name and port name out of the buffer
      GetDriverAndPort Buffer, DriverName, PrinterPort
      If (Len(DriverName) > 0) And (Len(PrinterPort) > 0) Then
         SetDefPrinter PrinterName, DriverName, PrinterPort
      End If
        
    End If
    
End Sub | 
| Comments | 
| Save the program and run. With the Printers folder open, change the default printer from the project. The appropriate printer icon should immediately reflect the change. If you have constructed a second project to show the VB common dialog, it will open with the current default printer selected. In addition, checking the Printer object's DeviceName property will also return the current selection. | 
|  | 
| 
 | 
|  | |||||
| 
 | |||||
|  | |||||
| 
            	
            	Copyright ©1996-2011 VBnet and Randy Birch. All Rights Reserved. | 
|  |