Microsoft KB Archive/266767: Difference between revisions

From BetaArchive Wiki
m (Text replacement - "<" to "<")
m (Text replacement - "&" to "&")
 
(One intermediate revision by the same user not shown)
Line 66: Line 66:
<li>Start a new Standard EXE project in Visual Basic. Form1 is created by default.</li>
<li>Start a new Standard EXE project in Visual Basic. Form1 is created by default.</li>
<li><p>Add a new module to the project and insert the following code:</p>
<li><p>Add a new module to the project and insert the following code:</p>
<pre class="codesample">Public Const HWND_BROADCAST = &amp;HFFFF
<pre class="codesample">Public Const HWND_BROADCAST = &HFFFF
Public Const WM_WININICHANGE = &amp;H1A
Public Const WM_WININICHANGE = &H1A


' constants for DEVMODE structure
' constants for DEVMODE structure
Line 74: Line 74:


' constants for DesiredAccess member of PRINTER_DEFAULTS
' constants for DesiredAccess member of PRINTER_DEFAULTS
Public Const STANDARD_RIGHTS_REQUIRED = &amp;HF0000
Public Const STANDARD_RIGHTS_REQUIRED = &HF0000
Public Const PRINTER_ACCESS_ADMINISTER = &amp;H4
Public Const PRINTER_ACCESS_ADMINISTER = &H4
Public Const PRINTER_ACCESS_USE = &amp;H8
Public Const PRINTER_ACCESS_USE = &H8
Public Const PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED Or _
Public Const PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED Or _
PRINTER_ACCESS_ADMINISTER Or PRINTER_ACCESS_USE)
PRINTER_ACCESS_ADMINISTER Or PRINTER_ACCESS_USE)
Line 229: Line 229:
     Dim r As Long
     Dim r As Long
     Dim l As Long
     Dim l As Long
     DeviceLine = PrinterName &amp; &quot;,&quot; &amp; DriverName &amp; &quot;,&quot; &amp; PrinterPort
     DeviceLine = PrinterName & &quot;,&quot; & DriverName & &quot;,&quot; & PrinterPort
     ' Store the new printer information in the [WINDOWS] section of
     ' Store the new printer information in the [WINDOWS] section of
     ' the WIN.INI file for the DEVICE= item
     ' the WIN.INI file for the DEVICE= item
Line 254: Line 254:


     ' set the PRINTER_DEFAULTS members
     ' set the PRINTER_DEFAULTS members
     pd.pDatatype = 0&amp;
     pd.pDatatype = 0&
     pd.DesiredAccess = PRINTER_ALL_ACCESS Or pd.DesiredAccess
     pd.DesiredAccess = PRINTER_ALL_ACCESS Or pd.DesiredAccess


Line 268: Line 268:
     ' (PRINTER_INFO_5) information, to determine how many bytes
     ' (PRINTER_INFO_5) information, to determine how many bytes
     ' you need
     ' you need
     x = GetPrinter(Handle, 5, ByVal 0&amp;, 0, need)
     x = GetPrinter(Handle, 5, ByVal 0&, 0, need)
     ' don't want to check Err.LastDllError here - it's supposed
     ' don't want to check Err.LastDllError here - it's supposed
     ' to fail
     ' to fail
Line 301: Line 301:


       If X = False Then  ' SetPrinter failed
       If X = False Then  ' SetPrinter failed
           MsgBox &quot;SetPrinter Failed. Error code: &quot; &amp; Err.LastDllError
           MsgBox &quot;SetPrinter Failed. Error code: &quot; & Err.LastDllError
           Exit Sub
           Exit Sub
       Else
       Else
           If Printer.DeviceName <&gt; List1.Text Then
           If Printer.DeviceName <> List1.Text Then
           ' Make sure Printer object is set to the new printer
           ' Make sure Printer object is set to the new printer
                 SelectPrinter (List1.Text)
                 SelectPrinter (List1.Text)
Line 324: Line 324:
     ' The driver name is first in the string terminated by a comma
     ' The driver name is first in the string terminated by a comma
     iDriver = InStr(Buffer, &quot;,&quot;)
     iDriver = InStr(Buffer, &quot;,&quot;)
     If iDriver &gt; 0 Then
     If iDriver > 0 Then


         ' Strip out the driver name
         ' Strip out the driver name
Line 333: Line 333:
         iPort = InStr(iDriver + 1, Buffer, &quot;,&quot;)
         iPort = InStr(iDriver + 1, Buffer, &quot;,&quot;)


         If iPort &gt; 0 Then
         If iPort > 0 Then
             ' Strip out the port name
             ' Strip out the port name
             PrinterPort = Mid(Buffer, iDriver + 1, _
             PrinterPort = Mid(Buffer, iDriver + 1, _
Line 347: Line 347:
     Do
     Do
         i = InStr(Buffer, Chr(0))
         i = InStr(Buffer, Chr(0))
         If i &gt; 0 Then
         If i > 0 Then
             s = Left(Buffer, i - 1)
             s = Left(Buffer, i - 1)
             If Len(Trim(s)) Then lstCtl.AddItem s
             If Len(Trim(s)) Then lstCtl.AddItem s
Line 355: Line 355:
             Buffer = &quot;&quot;
             Buffer = &quot;&quot;
         End If
         End If
     Loop While i &gt; 0
     Loop While i > 0
End Sub
End Sub


Line 365: Line 365:
     Dim PrinterName As String
     Dim PrinterName As String
     Dim r As Long
     Dim r As Long
     If List1.ListIndex &gt; -1 Then
     If List1.ListIndex > -1 Then
         ' Get the printer information for the currently selected
         ' Get the printer information for the currently selected
         ' printer in the list. The information is taken from the
         ' printer in the list. The information is taken from the
Line 377: Line 377:
         GetDriverAndPort Buffer, DriverName, PrinterPort
         GetDriverAndPort Buffer, DriverName, PrinterPort


           If DriverName <&gt; &quot;&quot; And PrinterPort <&gt; &quot;&quot; Then
           If DriverName <> &quot;&quot; And PrinterPort <> &quot;&quot; Then
               SetDefaultPrinter List1.Text, DriverName, PrinterPort
               SetDefaultPrinter List1.Text, DriverName, PrinterPort
               If Printer.DeviceName <&gt; List1.Text Then
               If Printer.DeviceName <> List1.Text Then
               ' Make sure Printer object is set to the new printer
               ' Make sure Printer object is set to the new printer
                   SelectPrinter (List1.Text)
                   SelectPrinter (List1.Text)

Latest revision as of 11:35, 21 July 2020

Knowledge Base


Article ID: 266767

Article Last Modified on 8/23/2006



APPLIES TO

  • Microsoft Visual Basic 4.0 Professional Edition
  • Microsoft Visual Basic 5.0 Professional Edition
  • Microsoft Visual Basic 6.0 Professional Edition
  • Microsoft Visual Basic 4.0 Enterprise Edition
  • Microsoft Visual Basic 5.0 Enterprise Edition
  • Microsoft Visual Basic 6.0 Enterprise Edition
  • Microsoft Visual Basic 5.0 Learning Edition
  • Microsoft Visual Basic 6.0 Learning Edition



This article was previously published under Q266767

SUMMARY

This article shows how to programmatically set which printer is the system default printer. Not all applications or components can select a specific printer to use. This often makes it necessary to change the default printer for the system so that the application or component will use the desired printer.

MORE INFORMATION

NOTE: This code changes the default printer for the entire system. So all applications that do not specify a printer, even applications that are currently running, use this same default. For this reason, you may want to have your code remember the previous default and then set it back when your print job is finished.

The following code sample provides a means to determine which printers are available, and to designate one as the system default printer.

Step-by-Step Example

  1. Start a new Standard EXE project in Visual Basic. Form1 is created by default.
  2. Add a new module to the project and insert the following code:

    Public Const HWND_BROADCAST = &HFFFF
    Public Const WM_WININICHANGE = &H1A
    
    ' constants for DEVMODE structure
    Public Const CCHDEVICENAME = 32
    Public Const CCHFORMNAME = 32
    
    ' constants for DesiredAccess member of PRINTER_DEFAULTS
    Public Const STANDARD_RIGHTS_REQUIRED = &HF0000
    Public Const PRINTER_ACCESS_ADMINISTER = &H4
    Public Const PRINTER_ACCESS_USE = &H8
    Public Const PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED Or _
    PRINTER_ACCESS_ADMINISTER Or PRINTER_ACCESS_USE)
    
    ' constant that goes into PRINTER_INFO_5 Attributes member
    ' to set it as default
    Public Const PRINTER_ATTRIBUTE_DEFAULT = 4
    
    ' Constant for OSVERSIONINFO.dwPlatformId
    Public Const VER_PLATFORM_WIN32_WINDOWS = 1
    
    Public Type OSVERSIONINFO
        dwOSVersionInfoSize As Long
        dwMajorVersion As Long
        dwMinorVersion As Long
        dwBuildNumber As Long
        dwPlatformId As Long
        szCSDVersion As String * 128
    End Type
    
    Public Type DEVMODE
         dmDeviceName As String * CCHDEVICENAME
         dmSpecVersion As Integer
         dmDriverVersion As Integer
         dmSize As Integer
         dmDriverExtra As Integer
         dmFields As Long
         dmOrientation As Integer
         dmPaperSize As Integer
         dmPaperLength As Integer
         dmPaperWidth As Integer
         dmScale As Integer
         dmCopies As Integer
         dmDefaultSource As Integer
         dmPrintQuality As Integer
         dmColor As Integer
         dmDuplex As Integer
         dmYResolution As Integer
         dmTTOption As Integer
         dmCollate As Integer
         dmFormName As String * CCHFORMNAME
         dmLogPixels As Integer
         dmBitsPerPel As Long
         dmPelsWidth As Long
         dmPelsHeight As Long
         dmDisplayFlags As Long
         dmDisplayFrequency As Long
         dmICMMethod As Long        ' // Windows 95 only
         dmICMIntent As Long        ' // Windows 95 only
         dmMediaType As Long        ' // Windows 95 only
         dmDitherType As Long       ' // Windows 95 only
         dmReserved1 As Long        ' // Windows 95 only
         dmReserved2 As Long        ' // Windows 95 only
    End Type
    
    Public Type PRINTER_INFO_5
         pPrinterName As String
         pPortName As String
         Attributes As Long
         DeviceNotSelectedTimeout As Long
         TransmissionRetryTimeout As Long
    End Type
    
    Public Type PRINTER_DEFAULTS
         pDatatype As Long
         pDevMode As Long
         DesiredAccess As Long
    End Type
    
    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
    
    Declare Function WriteProfileString Lib "kernel32" _
    Alias "WriteProfileStringA" _
    (ByVal lpszSection As String, _
    ByVal lpszKeyName As String, _
    ByVal lpszString As String) As Long
    
    Declare Function SendMessage Lib "user32" _
    Alias "SendMessageA" _
    (ByVal hwnd As Long, _
    ByVal wMsg As Long, _
    ByVal wParam As Long, _
    lparam As String) As Long
    
    Declare Function GetVersionExA Lib "kernel32" _
    (lpVersionInformation As OSVERSIONINFO) As Integer
    
    Public Declare Function OpenPrinter Lib "winspool.drv" _
    Alias "OpenPrinterA" _
    (ByVal pPrinterName As String, _
    phPrinter As Long, _
    pDefault As PRINTER_DEFAULTS) As Long
    
    Public Declare Function SetPrinter Lib "winspool.drv" _
    Alias "SetPrinterA" _
    (ByVal hPrinter As Long, _
    ByVal Level As Long, _
    pPrinter As Any, _
    ByVal Command As Long) As Long
    
    Public Declare Function GetPrinter Lib "winspool.drv" _
    Alias "GetPrinterA" _
    (ByVal hPrinter As Long, _
    ByVal Level As Long, _
    pPrinter As Any, _
    ByVal cbBuf As Long, _
    pcbNeeded As Long) As Long
    
    Public Declare Function lstrcpy Lib "kernel32" _
    Alias "lstrcpyA" _
    (ByVal lpString1 As String, _
    ByVal lpString2 As Any) As Long
    
    Public Declare Function ClosePrinter Lib "winspool.drv" _
    (ByVal hPrinter As Long) As Long
    
        Public Sub SelectPrinter(NewPrinter As String)
            Dim Prt As Printer
            
            For Each Prt In Printers
                If Prt.DeviceName = NewPrinter Then
                    Set Printer = Prt
                Exit For
                End If
            Next
        End Sub
                        
  3. Place a ListBox and a CommandButton on Form1.
  4. Add the following code to the General Declarations section of Form1:

    Option Explicit
    
    Private Function PtrCtoVbString(Add As Long) As String
        Dim sTemp As String * 512, x As Long
    
        x = lstrcpy(sTemp, Add)
        If (InStr(1, sTemp, Chr(0)) = 0) Then
             PtrCtoVbString = ""
        Else
             PtrCtoVbString = Left(sTemp, InStr(1, sTemp, Chr(0)) - 1)
        End If
    End Function
    
    Private Sub SetDefaultPrinter(ByVal PrinterName As String, _
        ByVal DriverName As String, ByVal PrinterPort As String)
        Dim DeviceLine As String
        Dim r As Long
        Dim l As Long
        DeviceLine = PrinterName & "," & DriverName & "," & PrinterPort
        ' Store the new printer information in the [WINDOWS] section of
        ' the WIN.INI file for the DEVICE= item
        r = WriteProfileString("windows", "Device", DeviceLine)
        ' Cause all applications to reload the INI file:
        l = SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0, "windows")
    End Sub
    
    Private Sub Win95SetDefaultPrinter()
        Dim Handle As Long          'handle to printer
        Dim PrinterName As String
        Dim pd As PRINTER_DEFAULTS
        Dim x As Long
        Dim need As Long            ' bytes needed
        Dim pi5 As PRINTER_INFO_5   ' your PRINTER_INFO structure
        Dim LastError As Long
    
        ' determine which printer was selected
        PrinterName = List1.List(List1.ListIndex)
        ' none - exit
        If PrinterName = "" Then
            Exit Sub
        End If
    
        ' set the PRINTER_DEFAULTS members
        pd.pDatatype = 0&
        pd.DesiredAccess = PRINTER_ALL_ACCESS Or pd.DesiredAccess
    
        ' Get a handle to the printer
        x = OpenPrinter(PrinterName, Handle, pd)
        ' failed the open
        If x = False Then
            'error handler code goes here
            Exit Sub
        End If
    
        ' Make an initial call to GetPrinter, requesting Level 5
        ' (PRINTER_INFO_5) information, to determine how many bytes
        ' you need
        x = GetPrinter(Handle, 5, ByVal 0&, 0, need)
        ' don't want to check Err.LastDllError here - it's supposed
        ' to fail
        ' with a 122 - ERROR_INSUFFICIENT_BUFFER
        ' redim t as large as you need
        ReDim t((need \ 4)) As Long
    
        ' and call GetPrinter for keepers this time
        x = GetPrinter(Handle, 5, t(0), need, need)
        ' failed the GetPrinter
        If x = False Then
            'error handler code goes here
            Exit Sub
        End If
    
        ' set the members of the pi5 structure for use with SetPrinter.
        ' PtrCtoVbString copies the memory pointed at by the two string
        ' pointers contained in the t() array into a Visual Basic string.
        ' The other three elements are just DWORDS (long integers) and
        ' don't require any conversion
        pi5.pPrinterName = PtrCtoVbString(t(0))
        pi5.pPortName = PtrCtoVbString(t(1))
        pi5.Attributes = t(2)
        pi5.DeviceNotSelectedTimeout = t(3)
        pi5.TransmissionRetryTimeout = t(4)
    
        ' this is the critical flag that makes it the default printer
        pi5.Attributes = PRINTER_ATTRIBUTE_DEFAULT
    
           ' call SetPrinter to set it
           X = SetPrinter(Handle, 5, pi5, 0)
    
           If X = False Then   ' SetPrinter failed
               MsgBox "SetPrinter Failed. Error code: " & Err.LastDllError
               Exit Sub
           Else
               If Printer.DeviceName <> List1.Text Then
               ' Make sure Printer object is set to the new printer
                    SelectPrinter (List1.Text)
               End If
           End If
    
        ' and close the handle
        ClosePrinter (Handle)
    End Sub
    
    Private Sub GetDriverAndPort(ByVal Buffer As String, DriverName As _
        String, PrinterPort As String)
    
        Dim iDriver As Integer
        Dim iPort As Integer
        DriverName = ""
        PrinterPort = ""
    
        ' The driver name is first in the string terminated by a comma
        iDriver = InStr(Buffer, ",")
        If iDriver > 0 Then
    
             ' Strip out the driver name
            DriverName = Left(Buffer, iDriver - 1)
    
            ' The port name is the second entry after the driver name
            ' separated by commas.
            iPort = InStr(iDriver + 1, Buffer, ",")
    
            If iPort > 0 Then
                ' Strip out the port name
                PrinterPort = Mid(Buffer, iDriver + 1, _
                iPort - iDriver - 1)
            End If
        End If
    End Sub
    
    Private Sub ParseList(lstCtl As Control, ByVal Buffer As String)
        Dim i As Integer
        Dim s As String
    
        Do
            i = InStr(Buffer, Chr(0))
            If i > 0 Then
                s = Left(Buffer, i - 1)
                If Len(Trim(s)) Then lstCtl.AddItem s
                Buffer = Mid(Buffer, i + 1)
            Else
                If Len(Trim(Buffer)) Then lstCtl.AddItem Buffer
                Buffer = ""
            End If
        Loop While i > 0
    End Sub
    
    Private Sub WinNTSetDefaultPrinter()
        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.Text
            r = GetProfileString("PrinterPorts", PrinterName, "", _
                Buffer, Len(Buffer))
    
            ' Parse the driver name and port name out of the buffer
            GetDriverAndPort Buffer, DriverName, PrinterPort
    
               If DriverName <> "" And PrinterPort <> "" Then
                   SetDefaultPrinter List1.Text, DriverName, PrinterPort
                   If Printer.DeviceName <> List1.Text Then
                   ' Make sure Printer object is set to the new printer
                      SelectPrinter (List1.Text)
                   End If
               End If
        End If
    End Sub
    
    Private Sub Command1_Click()
        Dim osinfo As OSVERSIONINFO
        Dim retvalue As Integer
    
        osinfo.dwOSVersionInfoSize = 148
        osinfo.szCSDVersion = Space$(128)
        retvalue = GetVersionExA(osinfo)
    
        If osinfo.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS Then
            Call Win95SetDefaultPrinter
        Else
        ' This assumes that future versions of Windows use the NT method
            Call WinNTSetDefaultPrinter
        End If
    End Sub
    
    Private Sub Form_Load()
        Dim r As Long
        Dim Buffer As String
    
        ' Get the list of available printers from WIN.INI
        Buffer = Space(8192)
        r = GetProfileString("PrinterPorts", vbNullString, "", _
           Buffer, Len(Buffer))
    
        ' Display the list of printer in the ListBox List1
        ParseList List1, Buffer
    End Sub
                        
  5. Run the project and note that the preceding code populates a ListBox with all available printers.
  6. Select one printer in the list and make it the default by clicking the CommandButton.
  7. Confirm that the default printer has changed: On the Start button, select Settings, select Printers, and then check which printer is marked as the default. Alternatively, you can print to the default printer from any application on your system.


REFERENCES

For additional information, click the article numbers below to view the articles in the Microsoft Knowledge Base:

167735 FIX: Setting Printer to Item in the Printers Collection Fails


253612 FIX: Printers Collection May Not Contain All Printers in the Printers Folder


246772 How To Retrieve and Set the Default Printer in Windows



Additional query words: global

Keywords: kbapi kbcodesnippet kbgdi kbhowto kbprint kbspooler KB266767