|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
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. |