Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 845
  • Last Modified:

Changing the Microsoft Windows Default Printer

In Microsoft Technical support (Article ID: Q129397) it says:
To change the Microsoft Windows default printer using Visual Basic code (or Access Basic code in version 2.0 or earlier), use WriteProfileString to
     change the Device= entry of the Microsoft Windows section of the Win.ini file.
That's fine butWin32-based applications should store initialization information in the registry. What API functions should I call to do this?

  • 3
  • 3
  • 2
  • +1
1 Solution
Use the commondialog control to change any printer settings.
Hi, jjbyers!

I think, that you need PrtDevNames property of Report object.
Here is text from MS Access online Help:
You can use the PrtDevNames property to set or return information about the printer selected in the Print dialog box for a form or report.

Note   It is strongly recommended that you consult the Win32 Software Development Kit for complete documentation on the PrtDevMode, PrtDevNames, and PrtMip properties.


The PrtDevNames property is a variable-length structure that mirrors the DEVNAMES structure defined in the Win32 Software Development Kit.
The PrtDevNames property uses the following members.

Member      Description
DriverOffset      Specifies the offset from the beginning of the structure to a Null-terminated string that specifies the file name (without an extension) of the device driver. This string is used to specify which printer is initially displayed in the Print dialog box.
DeviceOffset      Specifies the offset from the beginning of the structure to the Null-terminated string that specifies the name of the device. This string can't be longer than 32 bytes (including the null character) and must be identical to the DeviceName member of the DEVMODE structure.
OutputOffset      Specifies the offset from the beginning of the structure to the Null-terminated string that specifies the MS-DOS device name for the physical output medium (output port); for example, "LPT1:".
Default      Specifies whether the strings specified in the DEVNAMES structure identify the default printer. Before the Print dialog box is displayed, if Default is set to 1 and all of the values in the DEVNAMES structure match the current default printer, the selected printer is set to the default printer. Default is set to 1 if the current default printer has been selected.
Microsoft Access sets the PrtDevNames property when you make selections in the Printer section of the Print dialog box. You can also set the property by using Visual Basic.


Microsoft Access uses the DEVNAMES structure to initialize the Print dialog box. When the user chooses OK to close the dialog box, information about the selected printer is returned by the PrtDevNames property.

Sorry, spending way to much time in VB these days. Although you should still be able to use the commondialog control on a form.

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Sorry, andrejt, i posted info for you.
andrejtAuthor Commented:
I am familiar with both commondialog control and PrtDevMode, PrtDevNames but that is not what I want. I need to change report's printer without user intervention and without having to open report in design view first (PrtDevMode, PrtDevNames work only in design view). I want to save current default printer, set new current printer, print (fax) report and restore the old printer. To do this I need to use APIs to get/set printer keys (HKEY_LOCAL_MACHINE\Config\......) in registry.
Any fresh ideas out there?

I understand, but i don't know Windows API.
In VBA you can't do this directly, in VB it can be done such:
The Printers collection enables you to query the available printers so you can specify a default printer for your application. For example, you may want to find out which of the available printers uses a specific printer driver. The following code searches all available printers to locate the first printer with its page orientation set to Portrait, then sets it as the default printer:

Dim X As Printer
For Each X In Printers
   If X.Orientation = vbPRORPortrait Then
      ' Set printer as system default.
      Set Printer = X
      ' Stop looking for a printer.
      Exit For
   End If
This text from MSDN library.


HI !
The code as follow :

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


    dwOSVersionInfoSize As Long
    dwMajorVersion  As Long
    dwMinorVersion As Long
    dwBuildNumber As Long
    dwPlatformId As Long
    szCSDVersion As String * 128
End Type

Public 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 Declare Function GetLastError Lib "kernel32" () As Long

' *** constants for DEVMODE structure
Public Const CCHDEVICENAME = 32
Public Const CCHFORMNAME = 32

' *** constants for DesiredAccess member of PRINTER_DEFAULTS

' *** constant that goes into PRINTER_INFO_5 Attributes member to set it as default

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

Type ACL
        AclRevision As Byte
        Sbz1 As Byte
        AclSize As Integer
        AceCount As Integer
        Sbz2 As Integer
End Type

        Revision As Byte
        Sbz1 As Byte
        Control As Long
        Owner As Long
        Group As Long
        Sacl As ACL
        Dacl As ACL
End Type

        pServerName As String
        pPrinterName As String
        pShareName As String
        pPortName As String
        pDriverName As String
        pComment As String
        pLocation As String
        pDevMode As DEVMODE
        pSepFile As String
        pPrintProcessor As String
        pDatatype As String
        pParameters As String
        pSecurityDescriptor As SECURITY_DESCRIPTOR
        Attributes As Long
        Priority As Long
        DefaultPriority As Long
        StartTime As Long
        UntilTime As Long
        Status As Long
        cJobs As Long
        AveragePPM As Long
End Type

Public Type PRINTER_INFO_5
   pPrinterName               As String
   pPortName                  As String
   Attributes                 As Long
   DeviceNotSelectedTimeout   As Long
   TransmissionRetryTimeout   As Long
End Type

   pDatatype            As Long
   pDevMode             As DEVMODE
   DesiredAccess        As Long
End Type

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 = ""
      PtrCtoVbString = Left(sTemp, InStr(1, sTemp, Chr(0)) - 1)
   End If

End Function

Public 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

Public Sub Win95SetDefaultPrinter(sPrinter As String)
   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 = sPrinter
    ' none - exit
   If printerName = "" Then Exit Sub
    ' set the PRINTER_DEFAULTS members
   pd.pDatatype = 0&
   pd.DesiredAccess = PRINTER_ALL_ACCESS
    ' Get a handle to the printer
   x = OpenPrinter(printerName, Handle, pd)
    ' failed the open
   If x = False Then Exit Sub
    ' 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 GetLastError here - it's supposed to fail
    ' 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 Exit Sub
    ' 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
    ' call SetPrinter to set it
   x = SetPrinter(Handle, 5, pi5, 0)
    ' failed the SetPrinter
   If x = False Then Exit Sub
    ' and close the handle
   ClosePrinter (Handle)
End Sub

Public 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

Public Sub ParseList(lstCtl As Control, ByVal buffer As String)
   Dim i As Integer
      i = InStr(buffer, Chr(0))
      If i > 0 Then
         If (Trim(Left(buffer, i - 1)) <> "") Then lstCtl.AddItem Left(buffer, i - 1)
         buffer = Mid(buffer, i + 1)
         If (Trim(buffer) <> "") Then lstCtl.AddItem buffer
         buffer = ""
      End If
   Loop While i > 0

End Sub

Public Sub WinNTSetDefaultPrinter(sPrinter As String)
   Dim buffer        As String
   Dim DeviceName    As String
   Dim DriverName    As String
   Dim PrinterPort   As String
   Dim printerName   As String
   Dim r             As Long
   buffer = Space(1024)
   printerName = sPrinter
   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 sPrinter, DriverName, PrinterPort
   End If

End Sub

Hope this'll help you ^_^.
andrejtAuthor Commented:
before I test this in my code please tell me if the Win95SetDefaultPrinter subroutine works only with Win95?

I am asking this because I checked the MSDN regarding the structure:

typedef struct _PRINTER_INFO_5 { // pri5    
LPTSTR    pPrinterName;
LPTSTR    pPortName;    
DWORD     Attributes;
DWORD     DeviceNotSelectedTimeout;    
DWORD     TransmissionRetryTimeout;

where the crucial Attribute PRINTER_ATTRIBUTE_DEFAULT  is Windows 95 only


I assume it should work also with Win98?! Am I right?

Besides, this seems to be the RIGHT SOLUTION I have been looking for.

andrejtAuthor Commented:
is there any API function  that returns Windows default printer?
If not then I need to obtain the list of installed printers (how?) and check their PI5 structures.

HI !
All printer info the installed on the machien were stored on
win.ini -> Devices.
You can enumerate it by calling :
    ' Get a whole section from Win.INI. For example:
    ' will retrieve a list of all the devices in Win.INI,
    ' delimited with Null characters.
    Dim strBuffer As String
    dim iCount as long
    strBuffer = Space(500)
    intCount = getProfileSection("Devices", strBuffer, 500)
    adhGetProfileSection = Left(strBuffer, intCount)

Then if you want to determine default printer, just call
    GetProfileString "windows", "device",",,,",buffer,len(buffer)

Hope it'll help you !! ^_^

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

  • 3
  • 3
  • 2
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now