Solved

Changing the Microsoft Windows Default Printer

Posted on 1999-01-19
10
820 Views
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?

0
Comment
Question by:andrejt
  • 3
  • 3
  • 2
  • +1
10 Comments
 
LVL 3

Expert Comment

by:jjbyers
ID: 1977163
Use the commondialog control to change any printer settings.
0
 
LVL 7

Expert Comment

by:Dedushka
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.

Setting

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.

Remarks

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

Regards,
Dedushka
0
 
LVL 3

Expert Comment

by:jjbyers
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.
0
 
LVL 7

Expert Comment

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

Author Comment

by:andrejt
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?

0
Backup Your Microsoft Windows Server®

Backup all your Microsoft Windows Server – on-premises, in remote locations, in private and hybrid clouds. Your entire Windows Server will be backed up in one easy step with patented, block-level disk imaging. We achieve RTOs (recovery time objectives) as low as 15 seconds.

 
LVL 7

Expert Comment

by:Dedushka
ID: 1977168
andrejt,
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
Next
------
This text from MSDN library.

Regards,
Dedushka

0
 
LVL 3

Accepted Solution

by:
Sendoh earned 110 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

Public Const HWND_BROADCAST = &HFFFF
Public Const WM_WININICHANGE = &H1A

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

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

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

Type PRINTER_INFO_2
        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

Public Type PRINTER_DEFAULTS
   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 = ""
   Else
      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
    ' 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 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
   pi5.Attributes = PRINTER_ATTRIBUTE_DEFAULT
   
    ' 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
   
   lstCtl.Clear
   
   Do
      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)
      Else
         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 ^_^.
0
 

Author Comment

by:andrejt
ID: 1977170
Sendoh,
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;
} PRINTER_INFO_5;

where the crucial Attribute PRINTER_ATTRIBUTE_DEFAULT  is Windows 95 only

PRINTER_ATTRIBUTE_QUEUED
PRINTER_ATTRIBUTE_DIRECT
PRINTER_ATTRIBUTE_DEFAULT (Windows 95 only)
PRINTER_ATTRIBUTE_SHARED
PRINTER_ATTRIBUTE_WORK_OFFLINE

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

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

regards,
Andrejt
0
 

Author Comment

by:andrejt
ID: 1977171
Sendoh,
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.
Right?

regards,
Andrej
0
 
LVL 3

Expert Comment

by:Sendoh
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 !! ^_^
0

Featured Post

Comprehensive Backup Solutions for Microsoft

Acronis protects the complete Microsoft technology stack: Windows Server, Windows PC, laptop and Surface data; Microsoft business applications; Microsoft Hyper-V; Azure VMs; Microsoft Windows Server 2016; Microsoft Exchange 2016 and SQL Server 2016.

Join & Write a Comment

QuickBooks® has a great invoice interface that we were happy with for a while but that changed in 2001 through no fault of Intuit®. Our industry's unit names are dictated by RUS: the Rural Utilities Services division of USDA. Contracts contain un…
Experts-Exchange is a great place to come for help with solutions for your database issues, and many problems are resolved within minutes of being posted.  Others take a little more time and effort and often providing a sample database is very helpf…
In Microsoft Access, learn how to “cascade” or have the displayed data of one combo control depend upon what’s entered in another. Base the dependent combo on a query for its row source: Add a reference to the first combo on the form as criteria i…
In Microsoft Access, learn how to use Dlookup and other domain aggregate functions and one method of specifying a string value within a string. Specify the first argument, which is the expression to be returned: Specify the second argument, which …

762 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

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now