Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win


Changing the Microsoft Windows Default Printer

Posted on 1999-01-19
Medium Priority
Last Modified: 2012-05-04

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?

Question by:andrejt
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 3
  • 2
  • +1

Expert Comment

ID: 1977163
Use the commondialog control to change any printer settings.

Expert Comment

ID: 1977164
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.


Expert Comment

ID: 1977165
Sorry, spending way to much time in VB these days. Although you should still be able to use the commondialog control on a form.
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!


Expert Comment

ID: 1977166
Sorry, andrejt, i posted info for you.

Author Comment

ID: 1977167
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?


Expert Comment

ID: 1977168
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.



Accepted Solution

Sendoh earned 440 total points
ID: 1977169
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 ^_^.

Author Comment

ID: 1977170
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.


Author Comment

ID: 1977171
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.


Expert Comment

ID: 1977172
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

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Access developers frequently have requirements to interact with Excel (import from or output to) in their applications.  You might be able to accomplish this with the TransferSpreadsheet and OutputTo methods, but in this series of articles I will di…
Instead of error trapping or hard-coding for non-updateable fields when using QODBC, let VBA automatically disable them when forms open. This way, users can view but not change the data. Part 1 explained how to use schema tables to do this. Part 2 h…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…
Have you created a query with information for a calendar? ... and then, abra-cadabra, the calendar is done?! I am going to show you how to make that happen. Visualize your data!  ... really see it To use the code to create a calendar from a q…

597 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question