I am running two macros to print selections of a sheet. They are both included below. Can I add a setting somewhere in the macro to make them print duplex.
1st
2ndWith ActiveSheet.PageSetup .PrintArea = "bq19:cl99" .PrintTitleRows = "" .PrintTitleColumns = "" .LeftHeader = "" .CenterHeader = "" .RightHeader = "" .LeftFooter = "" .CenterFooter = "" .RightFooter = "" .LeftMargin = Application.InchesToPoints(0) .RightMargin = Application.InchesToPoints(0) .TopMargin = Application.InchesToPoints(0) .BottomMargin = Application.InchesToPoints(0) .HeaderMargin = Application.InchesToPoints(0) .FooterMargin = Application.InchesToPoints(0) .PrintHeadings = False .PrintGridlines = False .PrintComments = xlPrintNoComments .CenterHorizontally = True .CenterVertically = True .Orientation = xlLandscape .Draft = False .PaperSize = xlPaperLetter .FirstPageNumber = xlAutomatic .Order = xlOverThenDown .BlackAndWhite = False .Zoom = False .FitToPagesTall = 1 .FitToPagesWide = 1 End With ActiveSheet.PrintOut Copies:=1, Collate:=True Range("A1").Select Range("a1").Select End Sub
I am running both macros at the same time in a seperate macro and calling on both macros I just didnt know if it was possible or where it would go.Range("W1:AH38").Select Selection.PrintOut Copies:=1, Collate:=True End Sub
Thanks
Hello Redeoclown,
Unfortunately VBA did not add a Printer Object as Visual Basic did. If Microsoft had then this would wouldn't be so difficult. Actually, I have done the difficult part for you. Copy all of this code into a separate VBA module. This is what is needed to set a printer to duplex or back to simplex mode.
'Written: June 17, 2010 'Author: Leith Ross 'Summary: Sets a printer to Duplex mode or back to Simplex. There are 2 duplex settings: ' Book style and Legal (Flip) style. See comment box below for the values. Public Type PRINTER_DEFAULTS pDatatype As Long pDevmode As Long DesiredAccess As Long End Type Type PRINTER_INFO_2 pServerName As Long pPrinterName As Long pShareName As Long pPortName As Long pDriverName As Long pComment As Long pLocation As Long pDevmode As Long ' Pointer to DEVMODE pSepFile As Long pPrintProcessor As Long pDatatype As Long pParameters As Long pSecurityDescriptor As Long ' Pointer to 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 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 Const DM_DUPLEX = &H1000& Const DM_IN_BUFFER = 8 Const DM_OUT_BUFFER = 2 Const PRINTER_ACCESS_ADMINISTER = &H4 Const PRINTER_ACCESS_USE = &H8 Const STANDARD_RIGHTS_REQUIRED = &HF0000 Const PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED Or _ PRINTER_ACCESS_ADMINISTER Or PRINTER_ACCESS_USE) Private Declare Function ClosePrinter _ Lib "winspool.drv" _ (ByVal hPrinter 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 GetPrinter _ Lib "winspool.drv" _ Alias "GetPrinterA" _ (ByVal hPrinter As Long, _ ByVal Level As Long, _ ByRef pPrinter As Byte, _ ByVal cbBuf As Long, _ ByRef pcbNeeded As Long) _ As Long Private Declare Function OpenPrinter _ Lib "winspool.drv" _ Alias "OpenPrinterA" _ (ByVal pPrinterName As String, _ ByRef phPrinter As Long, _ ByRef pDefault As PRINTER_DEFAULTS) _ As Long Private Declare Function SetPrinter _ Lib "winspool.drv" _ Alias "SetPrinterA" _ (ByVal hPrinter As Long, _ ByVal Level As Long, _ ByRef pPrinter As Byte, _ ByVal Command As Long) _ As Long Private Declare Sub CopyMemory _ Lib "kernel32" _ Alias "RtlMoveMemory" _ (ByRef pDest As Any, _ ByRef pSource As Any, _ ByVal cbLength As Long) Private Declare Function StrLen _ Lib "kernel32" _ Alias "lstrlenA" _ (ByVal lpString As Long) As Long ' ================================================================== ' SetPrinterToDuplex. ' ' Set the Duplex flag for the specified default properties ' of the printer driver. ' ' Returns: True on success and False on error. An error will also ' display a message box. These messages are displayed for information ' only. ' ' Parameters: ' PrinterName - The name of the printer to be used as an ANSI string. ' ' DuplexSetting - One of the following standard settings: ' 1 = None ' 2 = Duplex on long edge (book) ' 3 = Duplex on short edge (legal) ' ' ================================================================== Public Function SetPrinterToDuplex(ByVal PrinterName As String, _ ByVal DuplexSetting As Long) As Boolean Dim hPrinter As Long Dim PD As PRINTER_DEFAULTS Dim PINFO As PRINTER_INFO_2 Dim DM As DEVMODE Dim DevModeData() As Byte Dim PInfoMemory() As Byte Dim nBytesNeeded As Long Dim nRet As Long, nJunk As Long On Error GoTo cleanup If (DuplexSetting < 1) Or (DuplexSetting > 3) Then MsgBox "Error: dwDuplexSetting is incorrect." Exit Function End If PD.DesiredAccess = PRINTER_ALL_ACCESS nRet = OpenPrinter(PrinterName, hPrinter, PD) If (nRet = 0) Or (hPrinter = 0) Then If Err.LastDllError = 5 Then MsgBox "Access denied." Else MsgBox "Cannot open the printer specified " & _ "(make sure the printer name is correct)." End If Exit Function End If nRet = DocumentProperties(0&, hPrinter, PrinterName, 0&, 0&, 0&) If (nRet < 0) Then MsgBox "Cannot get the size of the DEVMODE structure." GoTo cleanup End If ReDim DevModeData(nRet + 100) As Byte nRet = DocumentProperties(0&, hPrinter, PrinterName, _ VarPtr(DevModeData(0)), 0&, DM_OUT_BUFFER) If (nRet < 0) Then MsgBox "Cannot get the DEVMODE structure." GoTo cleanup End If Call CopyMemory(DM, DevModeData(0), Len(DM)) If Not CBool(DM.dmFields And DM_DUPLEX) Then MsgBox "You cannot modify the duplex flag for this printer " & _ "because it does not support duplex or the driver " & _ "does not support setting it from the Windows API." GoTo cleanup End If DM.dmDuplex = DuplexSetting Call CopyMemory(DevModeData(0), DM, Len(DM)) nRet = DocumentProperties(0&, hPrinter, PrinterName, _ VarPtr(DevModeData(0)), VarPtr(DevModeData(0)), _ DM_IN_BUFFER Or DM_OUT_BUFFER) If (nRet < 0) Then MsgBox "Unable to set duplex setting to this printer." GoTo cleanup End If Call GetPrinter(hPrinter, 2&, 0&, 0&, nBytesNeeded) If (nBytesNeeded = 0) Then GoTo cleanup ReDim PInfoMemory(nBytesNeeded + 100) As Byte nRet = GetPrinter(hPrinter, 2&, PInfoMemory(0), nBytesNeeded, nJunk) If (nRet = 0) Then MsgBox "Unable to get shared printer settings." GoTo cleanup End If Call CopyMemory(PINFO, PInfoMemory(0), Len(PINFO)) PINFO.pDevmode = VarPtr(DevModeData(0)) PINFO.pSecurityDescriptor = 0 Call CopyMemory(PInfoMemory(0), PINFO, Len(PINFO)) nRet = SetPrinter(hPrinter, 2&, PInfoMemory(0), 0&) If (nRet = 0) Then MsgBox "Unable to set shared printer settings." End If SetPrinterToDuplex = CBool(nRet) cleanup: If (hPrinter <> 0) Then Call ClosePrinter(hPrinter) End Function
Example for Setting the ActivePrinter to Duplex (Book style)
Sub DuplexTest() Dim PrinterName As String PrinterName = Application.ActivePrinter SetPrinterToDuplex Left(PrinterName, InStr(1, PrinterName, " on") - 1), 2 End Sub
Sincerely,
Leith Ross
Remember To Do the Following....
1. Use code tags. Place [CODE] before the first line of code and [/CODE] after the last line of code.2. Thank those who have helped you by clicking the Starbelow the post.
3. Please mark your post [SOLVED] if it has been answered satisfactorily.
Old Scottish Proverb...
Luathaid gu deanamh maille! (Rushing causes delays!)
Leith,
I have serched all over the internet and you seem to be the only one that has addressed this issue. However after applying your code I cannot get the printer to switch to duplex or back (it stays in whatever mode it was in before I run the code). The code runs without error and I tried all three duplex settings (1-3) but no go? I am running Windows 7 and Excel 2010 - any suggestions on what it might be or trouble shooting I could do?
Thanks,
Tom
Hello Tom,
I will check on what the cause might be or ways we can troubleshoot it. The API has evolved some since Windows XP. The biggest change is with 64 bit Windows. However, if you were using Windows 64 the code would have failed to run.
What printer are you using this on?
Sincerely,
Leith Ross
Remember To Do the Following....
1. Use code tags. Place [CODE] before the first line of code and [/CODE] after the last line of code.2. Thank those who have helped you by clicking the Starbelow the post.
3. Please mark your post [SOLVED] if it has been answered satisfactorily.
Old Scottish Proverb...
Luathaid gu deanamh maille! (Rushing causes delays!)
Leith,
Thanks for the quick reply. The printer is an HP 2605DN, about 4 yrs old.
Tom
Last edited by tom.hogan; 01-24-2012 at 10:00 PM.
Hello Tom,
Thanks for the printer info. Is this a personal printer or a networked printer?
Sincerely,
Leith Ross
Remember To Do the Following....
1. Use code tags. Place [CODE] before the first line of code and [/CODE] after the last line of code.2. Thank those who have helped you by clicking the Starbelow the post.
3. Please mark your post [SOLVED] if it has been answered satisfactorily.
Old Scottish Proverb...
Luathaid gu deanamh maille! (Rushing causes delays!)
Hello Tom,
No need to answer the last post. The printer specs indicate it uses HP PLC (Printer Control Language) 6. It most likely is not responding to API command because it expects a PLC command to set the duplex option. I will work on some code to send the PLC command to printer. That should work for you.
Sincerely,
Leith Ross
Remember To Do the Following....
1. Use code tags. Place [CODE] before the first line of code and [/CODE] after the last line of code.2. Thank those who have helped you by clicking the Starbelow the post.
3. Please mark your post [SOLVED] if it has been answered satisfactorily.
Old Scottish Proverb...
Luathaid gu deanamh maille! (Rushing causes delays!)
Leith,
I am currently using the PCL driver but it has as a postscript driver that I could use if that would make it easier.
Tom
Hello Tom,
Try this macro. It should send the set duplex command directly to the printer in PCL.
'Written: January 24, 2012 'Author: Leith Ross 'Summary: Sends HP PCL Simplex/Duplex commands to a printer. ' Print Spooler Win32 API Calls ' Private Declare Function OpenPrinter _ Lib "winspool.drv" Alias "OpenPrinterA" _ (ByVal pPrinterName As String, _ ByRef phPrn As Long, _ ByRef pDefault As Any) As Long Private Declare Function StartDocPrinter _ Lib "winspool.drv" Alias "StartDocPrinterA" _ (ByVal hPrn As Long, _ ByVal level As Long, _ ByRef pDocInfo As DOC_INFO_1) As Long Private Declare Function StartPagePrinter _ Lib "winspool.drv" _ (ByVal hPrn As Long) As Long Private Declare Function WritePrinter _ Lib "winspool.drv" _ (ByVal hPrn As Long, _ ByVal pBuf As String, _ ByVal cdBuf As Long, _ ByRef pcWritten As Long) As Long Private Declare Function EndPagePrinter _ Lib "winspool.drv" _ (ByVal hPrn As Long) As Long Private Declare Function EndDocPrinter _ Lib "winspool.drv" _ (ByVal hPrn As Long) As Long Private Declare Function ClosePrinter _ Lib "winspool.drv" _ (ByVal hPrn As Long) As Long ' ' ' API Structure required by StartDocPrinter ' Private Type DOC_INFO_1 pDocName As String pOutputFile As String pDatatype As String End Type ' ' ' ' Steps to send raw data to a printer ' 1. Call OpenPrinter to get a handle to the printer. ' 2. Initialize a DOCINFO structure with the printer data. ' 3. Call StartDocPrinter to indicate that the application will be sending document data to the printer. ' 4. Call StartPagePrinter to indicate that the application will be sending a new page to the printer. ' 5. Call WritePrinter to send the data. ' 6. Call EndPagePrinter to indicate that all data for the current page has been sent. ' 7. Call EndDocPrinter to indicate that all data for this document has been sent. ' 8. Call ClosePrinter to release the resources. Sub SetDuplexMode() Dim BytesWritten As Long Dim Cmd As String Dim DocInfo As DOC_INFO_1 Dim hPrn As Long Dim PrinterName As String Dim Response As Boolean Dim Status As Long 'HP PLC Simplex and Duplex commands. SimplexMode = vbEsc & Chr(38) & Chr(108) & Chr(48) & Chr(83) DuplexLegal = vbEsc & Chr(38) & Chr(108) & Chr(49) & Chr(83) DuplexBook = vbEsc & Chr(38) & Chr(108) & Chr(50) & Chr(83) Cmd = DuplexBook PrinterName = Application.ActivePrinter PrinterName = Left(PrinterName, InStr(1, PrinterName, " on") - 1) Status = OpenPrinter(PrinterName, hPrn, ByVal 0) If Status <> 0 Then With DocInfo .pDatatype = "TEXT" .pDocName = "My Document" .pOutputFile = "" End With Job = StartDocPrinter(hPrn, 1, DocInfo) If Job > 0 Then Status = StartPagePrinter(hPrn) If Status <> 0 Then Status = WritePrinter(hPrn, Cmd, Len(Cmd), BytesWritten) EndPagePrinter hPrn End If EndDocPrinter hPrn End If ClosePrinter hPrn End If If BytesWritten = Len(Cmd) Then MsgBox "Command sent to printer was successful." End If End Sub
Sincerely,
Leith Ross
Remember To Do the Following....
1. Use code tags. Place [CODE] before the first line of code and [/CODE] after the last line of code.2. Thank those who have helped you by clicking the Starbelow the post.
3. Please mark your post [SOLVED] if it has been answered satisfactorily.
Old Scottish Proverb...
Luathaid gu deanamh maille! (Rushing causes delays!)
Leith,
Thanks for all the help. I have tried your macro and it runs without error. It does duplex (I can see the page go through the duplexer) but it prints a blank page. I tried setting a print range with ActiviateSheet.PageSetup.PrintArea but that did not help. I also tried changing the CMD= to SimplexMode but it still duplexes a blank sheet. I did step through the macro and the value for CMD is changing based on the CMD = line but it still duplexes. I also tried setting CMD to DuplexLegal but got the same result.
Clearly some cmd is being sent to the printer, but it needs a little tweeking? Also, I relooked my print driver and it is PS not PCL. HP does not have a PCL driver for Windows 7.
Regards,
Tom
Hello Tom,
I will have to check on the Post Script method for setting the printer to duplex mode. At least we are making headway.
Sincerely,
Leith Ross
Remember To Do the Following....
1. Use code tags. Place [CODE] before the first line of code and [/CODE] after the last line of code.2. Thank those who have helped you by clicking the Starbelow the post.
3. Please mark your post [SOLVED] if it has been answered satisfactorily.
Old Scottish Proverb...
Luathaid gu deanamh maille! (Rushing causes delays!)
Leith,
I give up. I got so frustrated I went out an bought a new printer, HP CP2025dn. I did a bunch of internet research and your API code looks perfect. I also confirmed that the PCL code is correct. So i installed the new printer wiht PCL driver and tried both of your codes (plus a simular API code form MSFT site) and none of them work. I can only guess that it has something to do with the fact that I am printing to it as a network printer (static IP) but I don't understand why that would matter.
Thanks again for your help, this may be one of those problems for which there is not a VBA solution.
Regards,
Tom
Leith,
The plot thickens. I read else where that if you changed the printer back and forth then the duplex setting would take. This did not work for me unitl i did it twice in a row. So with your code and the below macro I can now change my printer's duplex setting:I irritates me that I don't understand why this works, but it does so I guess it's solved. I can't mark this as solved but I have rated you highly thanks for the help.Sub Print_Duplex() Dim PrinterName As String Dim n As Integer For n = 1 To 2 Application.ActivePrinter = "test printer on Ne07:" Application.ActivePrinter = "test printer1 on Ne08:" PrinterName = Application.ActivePrinter SetPrinterToDuplex Left(PrinterName, InStr(1, PrinterName, " on") - 1), 2 Next n End Sub
Tom
P.S. If you can explain why this works I would like to hear it!
There are currently 1 users browsing this thread. (0 members and 1 guests)
Bookmarks