How to set duplex printing for Microsoft Word Automation clients

Summary

Microsoft Word Automation clients cannot set the duplex print flag before a print job starts in Microsoft Office Word 2003 or in Microsoft Office Word 2007. Although a parameter in the PrintOut method indicates that there is support for duplex printing, the parameter does not provide true duplex printing. Also, this parameter may not be available to you, based on your operating system or on your installed language. However, to work around this limitation on Microsoft Windows systems, you must change the duplex flag for the active printer driver before the PrintOut function is called in Word.

This article describes how to use the Microsoft Windows API to change the duplex setting of the active printer to permit a Word document to print in duplex.

back to the top

More Information

Add a local print driver for a network printer in Microsoft Windows 2000

The print driver does not reside on the local computer. The print driver resides on the print server. For Microsoft Windows 2000 users who must print to a shared network printer, this may be a problem. Although a security administrator can configure the print server to permit end users to change global settings, Microsoft does not typically recommend this action. To work around this problem, you can install a local print driver for the network printer. Then, you can let each of your users control the settings for their local systems. To do this, follow these steps:
  1. Click Start, click
    Settings, click Printers, and then double-click Add Printer.

    The Add Printer Wizard starts.

    Click Next.
  2. Click Local printer, and then click
    Next.
  3. Click Create a new port, and then click
    Local Port in the Port Type section.
  4. In the Port Name box, type the location of the printer on the network.

    For example, type \\printserver\printername.

    Note Use the exact path name to the printer.
  5. Click Next, and then select a Windows 2000 driver for your printer.
  6. Click Next, and then follow the instructions to finish the wizard.
back to the top

Build the sample

If you change the printer properties for the active printer, all the applications that use the active printer are affected, not just Word. If you must change the settings for a particular print job, restore the settings when the print job is complete.

The following code uses the DocumentProperties API to change the print settings of the printer driver to enable duplex printing. For this code to work successfully, the end user must have the correct permissions to change the global print settings for the printer. If the end user does not have the correct permissions to change the driver settings, the end user receives an "Access Denied" error message on the OpenPrinter API call.
  1. Start Microsoft Visual Basic 6.0. Create a new project.

    By default, Form1 is created.
  2. Add a standard .bas module to the project. Add the following code example to the code window of the module.
    Option Explicit

    Public Type PRINTER_DEFAULTS

    pDatatype As Long
    pDevmode As Long
    DesiredAccess As Long
    End Type

    Public 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

    Public 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

    Public Const DM_DUPLEX = &H1000&
    Public Const DM_IN_BUFFER = 8

    Public Const DM_OUT_BUFFER = 2
    Public Const PRINTER_ACCESS_ADMINISTER = &H4
    Public Const PRINTER_ACCESS_USE = &H8
    Public Const STANDARD_RIGHTS_REQUIRED = &HF0000
    Public Const PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED Or _
    PRINTER_ACCESS_ADMINISTER Or PRINTER_ACCESS_USE)

    Public Declare Function ClosePrinter Lib "winspool.drv" _
    (ByVal hPrinter As Long) As Long
    Public 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
    Public Declare Function GetPrinter Lib "winspool.drv" Alias _
    "GetPrinterA" (ByVal hPrinter As Long, ByVal Level As Long, _
    pPrinter As Byte, ByVal cbBuf As Long, pcbNeeded As Long) As Long
    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 Byte, ByVal Command As Long) As Long

    Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
    (pDest As Any, pSource As Any, ByVal cbLength As Long)

    ' ==================================================================
    ' SetPrinterDuplex.
    '
    ' Programmatically set the Duplex flag for the specified default properties
    ' of the printer driver.
    '
    ' Returns: True on success and False on error. An error also

    ' displays a message box. This message box is displayed for information
    ' only. You must modify the code to support better error
    ' handling in your production application.
    '
    ' Parameters:
    ' sPrinterName - The name of the printer to be used.
    '
    ' nDuplexSetting - One of the following standard settings:
    ' 1 = None
    ' 2 = Duplex on long edge (book)
    ' 3 = Duplex on short edge (legal)
    '
    ' ==================================================================
    Public Function SetPrinterDuplex(ByVal sPrinterName As String, _
    ByVal nDuplexSetting As Long) As Boolean

    Dim hPrinter As Long
    Dim pd As PRINTER_DEFAULTS
    Dim pinfo As PRINTER_INFO_2
    Dim dm As DEVMODE

    Dim yDevModeData() As Byte
    Dim yPInfoMemory() As Byte
    Dim nBytesNeeded As Long
    Dim nRet As Long, nJunk As Long

    On Error GoTo cleanup

    If (nDuplexSetting < 1) Or (nDuplexSetting > 3) Then
    MsgBox "Error: dwDuplexSetting is incorrect."
    Exit Function
    End If

    pd.DesiredAccess = PRINTER_ALL_ACCESS
    nRet = OpenPrinter(sPrinterName, hPrinter, pd)
    If (nRet = 0) Or (hPrinter = 0) Then
    If Err.LastDllError = 5 Then
    MsgBox "Access denied -- See the article for more info."
    Else
    MsgBox "Cannot open the printer specified " & _
    "(make sure the printer name is correct)."
    End If
    Exit Function
    End If

    nRet = DocumentProperties(0, hPrinter, sPrinterName, 0, 0, 0)
    If (nRet < 0) Then
    MsgBox "Cannot get the size of the DEVMODE structure."
    GoTo cleanup
    End If

    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."
    GoTo cleanup
    End If

    Call CopyMemory(dm, yDevModeData(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 = nDuplexSetting
    Call CopyMemory(yDevModeData(0), dm, Len(dm))

    nRet = DocumentProperties(0, hPrinter, sPrinterName, _
    VarPtr(yDevModeData(0)), VarPtr(yDevModeData(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 yPInfoMemory(nBytesNeeded + 100) As Byte

    nRet = GetPrinter(hPrinter, 2, yPInfoMemory(0), nBytesNeeded, nJunk)
    If (nRet = 0) Then
    MsgBox "Unable to get shared printer settings."
    GoTo cleanup
    End If

    Call CopyMemory(pinfo, yPInfoMemory(0), Len(pinfo))
    pinfo.pDevmode = VarPtr(yDevModeData(0))
    pinfo.pSecurityDescriptor = 0
    Call CopyMemory(yPInfoMemory(0), pinfo, Len(pinfo))

    nRet = SetPrinter(hPrinter, 2, yPInfoMemory(0), 0)
    If (nRet = 0) Then
    MsgBox "Unable to set shared printer settings."
    End If

    SetPrinterDuplex = CBool(nRet)

    cleanup:
    If (hPrinter <> 0) Then Call ClosePrinter(hPrinter)

    End Function


  3. Add a standard Command Button control to Form1.
  4. Add the following code example to the code window for Form1.
          
    Option Explicit
    Private Sub Command1_Click()
    Dim oWord As Object
    Dim oDoc As Object

    Set oWord = CreateObject("Word.application")

    oWord.Visible = True

    Set oDoc = oWord.Documents.Add
    oDoc.Range.Select


    oWord.Selection.TypeText "This is on page 1" & vbCr
    oWord.Selection.InsertBreak 1
    oWord.Selection.TypeText "This is page 2"

    SetPrinterDuplex Printer.DeviceName, 2

    oDoc.PrintOut Background:=False

    SetPrinterDuplex Printer.DeviceName, 1

    MsgBox "Print Done", vbMsgBoxSetForeground

    oDoc.Saved = True
    oDoc.Close
    Set oDoc = Nothing

    oWord.Quit
    Set oWord = Nothing
    End Sub

  5. Run the sample.

    If your printer supports duplex printing, the test document prints on both sides of the page.
back to the top

References

For more information about problems that may occur while you try to print Word documents by using a duplex printer, click the following article numbers to view the articles in the Microsoft Knowledge Base:

176189 Shading of solid black or gray won't print duplex on NT

196857 First page prints on back of last page with duplex

214683 Duplex printing does not work with objects on page

back to the top
Egenskaper

Artikel-id: 828638 – senaste granskning 23 mars 2009 – revision: 1

Feedback