here's my problem.
I am trying to access the printer and change the colour and duplex settings. So far the code I have allows me to change the user preferences of the networked printer. But I have the following two problems below.
1) The codes set's the printer to either simplex or duplex as intended, however is does not set the colour preference correctly!
2) Excel is not automatically picking up the new settings, I still have to go in and manually click the reset button for the new changes to take affect.
Here is the code I am using:
Private Type PRINTER_INFO_9
pDevmode As Long ' Pointer to DEVMODE
End Type
Private Type DEVMODE
dmDeviceName As String * 32
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 * 32
dmUnusedPadding As Integer
dmBitsPerPel As Integer
dmPelsWidth As Long
dmPelsHeight As Long
dmDisplayFlags As Long
dmDisplayFrequency As Long
dmICMMethod As Long
dmICMIntent As Long
dmMediaType As Long
dmDitherType As Long
dmReserved1 As Long
dmReserved2 As Long
End Type
Private Declare Function OpenPrinter Lib "winspool.drv" Alias _
"OpenPrinterA" (ByVal pPrinterName As String, phPrinter As Long, _
pDefault As Any) As Long
Private Declare Function GetPrinter Lib "winspool.drv" Alias _
"GetPrinterA" (ByVal hPrinter As Long, ByVal Level As Long, _
buffer As Long, ByVal pbSize As Long, pbSizeNeeded As Long) As Long
Private 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
Private Declare Function DocumentProperties Lib "winspool.drv" _
Alias "DocumentPropertiesA" (ByVal hwnd As Long, _
ByVal hPrinter As Long, ByVal pDeviceName As String, _
ByVal pDevModeOutput As Long, ByVal pDevModeInput As Long, _
ByVal fMode As Long) As Long
Private Declare Function ClosePrinter Lib "winspool.drv" _
(ByVal hPrinter As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
(pDest As Any, pSource As Any, ByVal cbLength As Long)
Private Const DM_IN_BUFFER = 8
Private Const DM_OUT_BUFFER = 2
Private Sub CommandButton1_Click()
Dim sPrinterName As String
Dim my_printer_address As String
Dim hPrinter As Long
Dim Pinfo9 As PRINTER_INFO_9
Dim dm As DEVMODE
Dim yDevModeData() As Byte
Dim nRet As Long
my_printer_address = Application.ActivePrinter
'slice string for printer name (minus port name)
sPrinterName = Left(my_printer_address, InStr(my_printer_address, " on ") - 1)
'Open Printer
nRet = OpenPrinter(sPrinterName, hPrinter, ByVal 0&)
'Get the size of the DEVMODE structure
nRet = DocumentProperties(0, hPrinter, sPrinterName, 0, 0, 0)
If (nRet < 0) Then MsgBox "Cannot get the size of the DEVMODE structure.": Exit Sub
'Get DEVMODE Structure
ReDim yDevModeData(nRet + 100) As Byte
nRet = DocumentProperties(0, hPrinter, sPrinterName, VarPtr(yDevModeData(0)), 0, DM_OUT_BUFFER)
If (nRet < 0) Then
MsgBox "Cannot get the DEVMODE structure."
Exit Sub
End If
'Copy the DEVMODE structure
Call CopyMemory(dm, yDevModeData(0), Len(dm))
'Change DEVMODE Stucture as required
dm.dmColor = 1 ' 1 = colour, 2 = b/w
dm.dmDuplex = 2 ' 1 = simplex, 2 = duplex
'Replace the DEVMODE structure
Call CopyMemory(yDevModeData(0), dm, Len(dm))
'Verify DEVMODE Stucture
nRet = DocumentProperties(0, hPrinter, sPrinterName, VarPtr(yDevModeData(0)), VarPtr(yDevModeData(0)), DM_IN_BUFFER Or DM_OUT_BUFFER)
Pinfo9.pDevmode = VarPtr(yDevModeData(0))
'Set DEVMODE Stucture with any changes made
nRet = SetPrinter(hPrinter, 9, Pinfo9, 0)
If (nRet <= 0) Then MsgBox "Cannot set the DEVMODE structure.": Exit Sub
'Close the Printer
nRet = ClosePrinter(hPrinter)
End Sub
Any help you can provide will be much appreciated!! I have been hitting my head against a wall with this for weeks now!
After some extensive research, I have found the answer I was looking for. I have posted it here, in case anyone has a similar situation.
The main issue I was having was getting excel to accept the new changes with closing the workbook or having to go into the print preferences and click reset.
The solution I came up with was to temporarily set the active printer to another printer then set it back to the printer the settings were changed on, this forces Excel to pick up the new settings.
Here are the Public Types, Functions and Constants:
This is the routine i am using to set the new values:
I then call either of these two subs to set set preferences:
Awesome. Thank you for this fix. Our office recently switched to Windows 10 and Office 16 and my old duplex code no longer worked for printing out worksheets in duplex mode. Your code is incredibly complicated, but it works (for reasons beyond my understanding as a novice programmer) and saves a lot of paper from being wasted. Thank you very much. I did notice one thing about your function that needs to be addressed. There is a call to another function you did not provide.
Coincidentally I happened to have the function GetPrinterFullName() in another module so it was running but not returning the full name of "CutePDF". That was because "CutePDF" does not exist on my computer. So I simply went to settings, set the default to "Microsoft Print to PDF" and then did a small test routine (below) to get the full name of the active default printer:
This returned "Microsoft Print to PDF on Ne03:" So any user could send the full name of any second printer to your function by adding a 3rd variable and avoid the call to GetPrinterFullName(), or they can hard code the name into your function like I did to avoid the call. Or they can add the following function to the module: (I've been to 30 different sites this morning to find a solution, and yours is the one that works. But the credits for the following function are inside the function below. It is not my code. I think it is credited to Frans Bus)