XLS+VBA

VBA로 현재 프린터 단면/양면 인쇄 설정

쵸코난 2025. 3. 2. 01:17

 

 

관련: 지식인1, 지식인2

 

 

이번 미션은  엑셀에서 시트이름이 '양면3'이면 양면 3부 인쇄, '단면1'이면 단면 1부로 모든 엑셀 시트를 한꺼번에 일괄 인쇄하는 것입니다.

 

 

VBA로 원하는 인쇄 매수대로 인쇄하는 것은 쉬우나

양면 인쇄는 VBA로도 설정하기 까다롭습니다.

한 가지 방법은 프린터를 하나 더 추가한 다음 양면으로 설정하고

단면일 때는 프린터1을 현재 프린터(ActivePrinter)로 설정하고

양면일 때는 프린터2를 현재 프린터(ActivePrinter)로 설정하는 방법이 있습니다.

 

여기서는 이 방법대신 새로운 프린터를 설정할 필요 없이 API를 이용해서 그때마다 양면/단면을 설정해서 인쇄하는 방법을 모색합니다.

 

아래와 같은 코드를 참고하였습니다.

 

  • VBA7 환경(오피스2010이상)

https://answers.microsoft.com/en-us/msoffice/forum/all/set-duplex-printing-for-word-automation-for-vba7/994416cc-bca4-4f68-971d-27332b826a12

  • VB6 하위버전(~오피스2010이전)

https://web.archive.org/web/20130915062449/http://pubs.logicalexpressions.com/Pub0009/LPMArticle.asp?ID=116

윈도우 API를 이용한 위 코드를 활용 및 수정했습니다.

 

그런데 넘어야할 문제점이 많습니다.

 

 

먼저 위 코드를 활용해도 양면 설정이 현재 프린터에 반영이 되지 않습니다.

 

>>  임시로 다른 PDF프린터로 현재 프린터로 설정했다가

다시 원래 프린터로 설정해서 양면/단면 설정이 반영되도록 합니다.

따라서 임시로 다른 프린터로 설정하기 위해 시스템에 PDF프린터가 설치되어 있어야 합니다.

없다면 nPDF 등의 가상 PDF 프린터를 설치하세요.

현재 프린터는 양면 인쇄를 지원하는 프린터여야 합니다.

PDF프린터는 가상 프린터이므로 양면을 지원하지 않습니다.

Alt+F8 누르고 myPrint 매크로를 실행하면 됩니다.

 

숨겨진 시트는 인쇄에서 제외합니다.

인쇄 후에는 단면/양면 원래 설정을 복구합니다.

 

시트 이름이 '양면2' 처럼 이름이 겹칠 수 없기 때문에 문제가 생깁니다.

>> '양면2 설명1' 처럼 빈칸 다음에 설명을 추가하면 시트 이름이 달라져 같은 방식 인쇄가 중복되어도 됩니다.

 

Module1:

Option Explicit

' 시트이름이 '양면3'이면 양면 3부 인쇄, '단면1'이면 단면 1부 인쇄
' *************************************
' *** 기본 프린터 설정 후 실행      ***
' *** 시스템에 PDF 프린터 설치 필요 ***
' *************************************
Sub myPrint()

    Dim sht As Worksheet
    Dim str As String, p As Integer, ret As Boolean, iDuplex As Long
    
    iDuplex = GetDuplex
    'sht.PageSetup.PaperSize = xlPaperA4
    'sht.PageSetup.FitToPagesTall
    For Each sht In ActiveWorkbook.Worksheets
        If sht.Visible = xlSheetVisible Then
            str = sht.name
            If InStr(str, " ") > 0 Then str = Left(str, InStr(str, " ") - 1)
            If str Like "?면*" Then
                '페이지수
                On Error Resume Next
                
                p = Int(Mid(str, 3))
                On Error GoTo 0
                If p = 0 Then p = 1
                
                '단면/양면
                If sht.name Like "양면*" Then
                    ret = SetActiveDuplex(2)    '2: 긴면 묶음, 3: 짧은면 묶음
                Else
                    ret = SetActiveDuplex(1)
                End If
                DoEvents
                
                If ret = False Then _
                    If MsgBox("양면/단면 설정이 실패했습니다! 계속할까요?", vbCritical + vbOKCancel) = vbCancel Then _
                        Exit For
                '인쇄
                sht.PrintOut Copies:=p
            End If
        End If
    Next sht
    SetActiveDuplex iDuplex
 
End Sub

 

 

오피스2010이상인 경우와 미만인 경우를 반영하기 위해

#IF VBA7 이 사용되었습니다.

 

또한 오피스2010에서도 작동하고 2021이나 365에서도 작동하도록 여러가지 상황을 고려하느라 많은 테스트와 수정작업이 필요했습니다. Type 선언에 따라 특정 시스템에서 엑셀이 말없이 종료되는 현상이 여러번 발생했습니다.

 

Module2:

더보기
'https://answers.microsoft.com/en-us/msoffice/forum/all/set-duplex-printing-for-word-automation-for-vba7/994416cc-bca4-4f68-971d-27332b826a12
'https://web.archive.org/web/20030225011214/http://support.microsoft.com:80/?kbid=230743
'http://www.lessanvaezi.com/changing-printer-settings-using-the-windows-api/

Option Explicit

#If VBA7 Then
    
    'constants form DEVMODE structure
    Public Const CCHDEVICENAME = 32
    Public Const CCHFORMNAME = 32
    Public Type DEVMODE
        dmDeviceName(0 To CCHDEVICENAME - 1) As Byte
        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(0 To CCHFORMNAME - 1) As Byte
        dmUnusedPadding As Integer
        dmBitsPerPel As Long
        dmPelsWidth As Long
        dmPelsHeight As Long
        dmDisplayFlags As Long
        dmDisplayFrequency As Long        '#if(WINVER >= 0x0400)
        dmICMMethod As Long
        dmICMIntent As Long
        dmMediaType As Long
        dmDitherType As Long
        dmReserved1 As Long
        dmReserved2 As Long           '  #if (WINVER >= 0x0500) || (_WIN32_WINNT >= _WIN32_WINNT_NT4)
        dwPanningWidth As Long
        dwPanningHeight As Long       '  #endif#endif /* WINVER >= 0x0400 */
    End Type
    
    Public Type PRINTER_DEFAULTS
        pDatatype As String
        pDevmode As LongPtr     'DEVMODE
        DesiredAccess As Long
    End Type
    
'    Public 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 LongPtr 'DEVMODE
'        pSepFile As String
'        pPrintProcessor As String
'        pDatatype As String
'        pParameters As String
'        pSecurityDescriptor As LongPtr  '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_2
    pServerName As LongPtr
    pPrinterName As LongPtr
    pShareName As LongPtr
    pPortName As LongPtr
    pDriverName As LongPtr
    pComment As LongPtr
    pLocation As LongPtr
    pDevmode As LongPtr 'Pointer to DEVMODE
    pSepFile As LongPtr
    pPrintProcessor As LongPtr
    pDatatype As LongPtr
    pParameters As LongPtr
    pSecurityDescriptor As LongPtr 'Pointer to SECURITY_DESCRIPTOR
    Attributes As LongPtr
    Priority As LongPtr
    DefaultPriority As LongPtr
    StartTime As LongPtr
    UntilTime As LongPtr
    Status As LongPtr
    cJobs As LongPtr
    AveragePPM As LongPtr
End Type

    Public Declare PtrSafe Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" (ByVal pPrinterName As String, phPrinter As LongPtr, pDefault As PRINTER_DEFAULTS) As Long
    Public Declare PtrSafe Function ClosePrinter Lib "winspool.drv" (ByVal hPrinter As LongPtr) As Long
    Public Declare PtrSafe Function DocumentProperties Lib "winspool.drv" Alias "DocumentPropertiesA" (ByVal hwnd As LongPtr, ByVal hPrinter As LongPtr, ByVal pDeviceName As String, ByVal pDevModeOutput As LongPtr, ByVal pDevModeInput As LongPtr, ByVal fMode As Long) As Long
    Public Declare PtrSafe Function GetPrinter Lib "winspool.drv" Alias "GetPrinterA" (ByVal hPrinter As LongPtr, ByVal Level As Long, pPrinter As Any, ByVal cbBuf As Long, pcbNeeded As Long) As Long
    Public Declare PtrSafe Function SetPrinter Lib "winspool.drv" Alias "SetPrinterA" (ByVal hPrinter As LongPtr, ByVal Level As Long, pPrinter As Byte, ByVal Command As Long) As Long
    Public Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)

#Else
    'constants form DEVMODE structure
    Public Const CCHDEVICENAME = 32
    Public Const CCHFORMNAME = 32
    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
        dmLogPizels As Integer
        dmBitsPerPel As Long
        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 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 Declare Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" (ByVal pPrinterName As String, phPrinter As Long, pDefault As PRINTER_DEFAULTS) As Long
    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, pDevModeOutput As Long, 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 Any, ByVal cbBuf As Long, pcbNeeded As Long) 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" (Destination As Any, Source As Any, ByVal Length As Long)

#End If

'Access levels for interacting with a device
Const DELETE = &H10000
Const READ_CONTROL = &H20000 ' Read device information
Const WRITE_DAC = &H40000 ' Write Device Access Control info
Const WRITE_OWNER = &H80000 ' Change the object owner

' Combining these for full access to the device
Const STANDARD_RIGHTS_REQUIRED = &HF0000
Const PRINTER_ACCESS_USE = &H8
Const PRINTER_NORMAL_ACCESS = (READ_CONTROL Or PRINTER_ACCESS_USE)
Const DM_ORIENTATION = &H1
Const DM_PAPERSIZE = &H2
Const DM_PAPERLENGTH = &H4
Const DM_PAPERWIDTH = &H8
Const DM_DEFAULTSOURCE = &H200
Const DM_PRINTQUALITY = &H400
Const DM_COLOR = &H800
Const DM_DUPLEX = &H1000
Const DM_IN_BUFFER = 8
Const DM_OUT_BUFFER = 2

Private Sub test_SetActiveDuplex()

    Debug.Print SetActiveDuplex(2)
    
End Sub

Function SetActiveDuplex(iDuplex As Long) As Boolean
 
    Dim dPrinter As String, tPrinter As String
    Dim ret As Long
    
    dPrinter = getActivePrinter(True)
    tPrinter = FindPrinter("PDF")
    'Debug.Print getActivePrinter
    ret = SetPrinterProperty(DM_DUPLEX, iDuplex) '1: simplex, 2: duplex/long side binding, 3: duplex/ short side binding
    Application.ActivePrinter = tPrinter
    Application.ActivePrinter = dPrinter
    ret = GetPrinterProperty(DM_DUPLEX)
    If ret = iDuplex Then SetActiveDuplex = True Else SetActiveDuplex = False
    
End Function

Public Function SetDuplex(iDuplex As Long) As Boolean
   SetDuplex = SetPrinterProperty(DM_DUPLEX, iDuplex)
End Function

Public Function GetDuplex() As Long
   GetDuplex = GetPrinterProperty(DM_DUPLEX)
End Function

Public Sub SetPrintQuality(iQuality As Long)
   SetPrinterProperty DM_PRINTQUALITY, iQuality ' -1: Draft, -2: Low, -3:Medium, -4: High, int(300): dpi
End Sub

Public Function GetPrintQuality() As Long
   GetPrintQuality = GetPrinterProperty(DM_PRINTQUALITY)
End Function
 

' ==================================================================
' Set Printer to Duplex by calling SetPrinterProperty
'
' Programmatically set the Duplex flag for the specified printer
' driver's default properties.
'
' Returns: True on success, False on error.
'
' Parameters:
' lngPropertyType - The name of the parameter to be modified (in our case, DM_DUPLEX)
'
' lngPropertyValue - One of the following standard settings (in our case, 2):
' 1 = None
' 2 = Duplex on long edge (book)
' 3 = Duplex on short edge (legal)
'
' ==================================================================
Function SetPrinterProperty(ByVal lngPropertyType As Long, ByVal lngPropertyValue As Long) As Boolean

    Dim udtPD As PRINTER_DEFAULTS
    Dim udtPI As PRINTER_INFO_2
    Dim udtDM As DEVMODE
    Dim strPrinterName As String
    Dim bytDevModeData() As Byte
    Dim bytPInfoMemory() As Byte
    Dim lngPrinter As LongPtr
    Dim lngBytesNeeded As Long
    Dim lngReturn As Long
    Dim lngJunk As Long
    
    On Error GoTo err_exit
    
    'this defines the printer we want to use. You may want to adjust this to Your needs
    'Samsung MLXXXX Series on LPT1:
    'Ne01:에 있는 Samsung MLXXXX Series (192.168.0.xxx)
     strPrinterName = getActivePrinter
    'You may have to use...
    'Trim$ (Left$(ActivePrinter, InStr(ActivePrinter, " on ")))
    '...here in case the name of Your printer looks something like this: "
    
    udtPD.DesiredAccess = PRINTER_NORMAL_ACCESS
    
    'Get the printer handle ("lngPrinter")
    lngReturn = OpenPrinter(strPrinterName, lngPrinter, udtPD)
    If (lngReturn = 0) Or (lngPrinter = 0) Then Exit Function 'Can't access current printer. Bail out doing nothing
    
    'Get the size of the DEVMODE structure to be loaded
    lngReturn = DocumentProperties(0, lngPrinter, strPrinterName, 0, 0, 0)
    If (lngReturn < 0) Then Err.Raise vbObjectError + 1 'Can't access printer properties.
    
    'Make sure the byte array is large enough
    'Some printer drivers lie about the size of the DEVMODE structure they
    'return, so an extra 100 bytes is provided just in case!
    ReDim bytDevModeData(0 To CLng(lngReturn) + 100) As Byte
    
    'Load the byte array
    lngReturn = DocumentProperties(0, lngPrinter, strPrinterName, VarPtr(bytDevModeData(0)), 0, DM_OUT_BUFFER)
    If (lngReturn < 0) Then Err.Raise vbObjectError + 2
    
    'Copy the byte array into a structure so it can be manipulated
    Call CopyMemory(udtDM, bytDevModeData(0), Len(udtDM))
    If udtDM.dmFields And lngPropertyType = 0 Then Err.Raise vbObjectError + 3 'Wanted property not available. Bail out.
    
    'Set the property to the appropriate value
    Select Case lngPropertyType
        Case DM_ORIENTATION
            udtDM.dmOrientation = lngPropertyValue
        Case DM_PAPERSIZE
            udtDM.dmPaperSize = lngPropertyValue
        Case DM_PAPERLENGTH
            udtDM.dmPaperLength = lngPropertyValue
        Case DM_PAPERWIDTH
            udtDM.dmPaperWidth = lngPropertyValue
        Case DM_DEFAULTSOURCE
            udtDM.dmDefaultSource = lngPropertyValue
        Case DM_PRINTQUALITY
            udtDM.dmPrintQuality = lngPropertyValue
        Case DM_COLOR
            udtDM.dmColor = lngPropertyValue
        Case DM_DUPLEX
            udtDM.dmDuplex = lngPropertyValue
    End Select
    
    'Load the structure back into the byte arra
    Call CopyMemory(bytDevModeData(0), udtDM, Len(udtDM))
    
    'Tell the printer about the new property, specifying both the DM_IN_BUFFER and DM_OUT_BUFFER values (which are combined using the OR operator)
    lngReturn = DocumentProperties(0, lngPrinter, strPrinterName, VarPtr(bytDevModeData(0)), VarPtr(bytDevModeData(0)), DM_IN_BUFFER Or DM_OUT_BUFFER)
    If (lngReturn < 0) Then Err.Raise vbObjectError + 4
    
    'The code above *ought* to be sufficient to set the property
    'correctly. Unfortunately some brands of Postscript printer don't
    'seem to respond correctly. The following code is used to make
    'sure they also respond correctly.
    Call GetPrinter(lngPrinter, 2, 0, 0, lngBytesNeeded)
    If (lngBytesNeeded = 0) Then Err.Raise vbObjectError + 5 'Couldn't access shared printer settings
    
    'Set byte array large enough for PRINTER_INFO_2 structure
    ReDim bytPInfoMemory(0 To lngBytesNeeded + 100) As Byte
    
    'Load the PRINTER_INFO_2 structure into byte array
    lngReturn = GetPrinter(lngPrinter, 2, bytPInfoMemory(0), lngBytesNeeded, lngJunk)
    If (lngReturn = 0) Then Err.Raise vbObjectError + 6 'Couldn't access shared printer settings
    
    'Copy byte array into the structured type
    Call CopyMemory(udtPI, bytPInfoMemory(0), Len(udtPI))
    
    'Load the DEVMODE structure with byte array containing
    'the new property value
    udtPI.pDevmode = VarPtr(bytDevModeData(0))
    
    'Set security descriptor to null
    udtPI.pSecurityDescriptor = 0
    
    'Copy the PRINTER_INFO_2 structure back into byte array
    Call CopyMemory(bytPInfoMemory(0), udtPI, Len(udtPI))
    
    'Send the new details to the printer
    lngReturn = SetPrinter(lngPrinter, 2, bytPInfoMemory(0), 0)
    
    'Indicate whether it all worked or not!
    SetPrinterProperty = CBool(lngReturn)

err_exit:
    'Release the printer handle
    If (lngPrinter <> 0) Then Call ClosePrinter(lngPrinter)
    
End Function

' ==================================================================
' Find the Printer's Duplex setting by calling GetPrinterProperty
'
' Returns: The number value of the desired setting
'
' Parameters:
' lngPropertyType - The name of the parameter to be modified (in our case, DM_DUPLEX)
'
' ==================================================================
Function GetPrinterProperty(ByVal lngPropertyType As Long) As Long
    Dim udtPD As PRINTER_DEFAULTS
    Dim udtDM As DEVMODE
    Dim strPrinterName As String
    Dim bytDevModeData() As Byte
    Dim lngPrinter As LongPtr, lngReturn As Long
    
    On Error GoTo err_exit
    
    'this defines the printer we want to use. You may want to adjust this to Your needs
    strPrinterName = getActivePrinter
    
    'You may have to use...
    'Trim$ (Left$(ActivePrinter, InStr(ActivePrinter, " on ")))
    '...here in case the name of Your printer looks something like this: "
    udtPD.DesiredAccess = PRINTER_NORMAL_ACCESS
    
    'Get the printer handle ("lngPrinter")
    lngReturn = OpenPrinter(strPrinterName, lngPrinter, udtPD)
    If (lngReturn = 0) Or (lngPrinter = 0) Then Exit Function
    
    'Get the size of the DEVMODE structure to be loaded
    lngReturn = DocumentProperties(0, lngPrinter, strPrinterName, 0, 0, 0)
    If (lngReturn < 0) Then Err.Raise vbObjectError + 1 'Can't access printer properties.
    
    'Make sure the byte array is large enough
    'Some printer drivers lie about the size of the DEVMODE structure they
    'return, so an extra 100 bytes is provided just in case!
    ReDim bytDevModeData(0 To CLng(lngReturn) + 100) As Byte
    
    'Load the byte array
    lngReturn = DocumentProperties(0, lngPrinter, strPrinterName, VarPtr(bytDevModeData(0)), 0, DM_OUT_BUFFER)
    If (lngReturn < 0) Then Err.Raise vbObjectError + 2
    
    'Copy the byte array into a structure so it can be manipulated
    Call CopyMemory(udtDM, bytDevModeData(0), Len(udtDM))
    If udtDM.dmFields And lngPropertyType = 0 Then Err.Raise vbObjectError + 3 'Wanted property not available. Bail out.
    
    Select Case lngPropertyType
        Case DM_ORIENTATION
            GetPrinterProperty = udtDM.dmOrientation
        Case DM_PAPERSIZE
            GetPrinterProperty = udtDM.dmPaperSize
        Case DM_PAPERLENGTH
            GetPrinterProperty = udtDM.dmPaperLength
        Case DM_PAPERWIDTH
            GetPrinterProperty = udtDM.dmPaperWidth
        Case DM_DEFAULTSOURCE
            GetPrinterProperty = udtDM.dmDefaultSource
        Case DM_PRINTQUALITY
            GetPrinterProperty = udtDM.dmPrintQuality
        Case DM_COLOR
            GetPrinterProperty = udtDM.dmColor
        Case DM_DUPLEX
            GetPrinterProperty = udtDM.dmDuplex
    End Select
    
err_exit:
    If (lngPrinter <> 0) Then Call ClosePrinter(lngPrinter)
    
End Function

Function getActivePrinter(Optional Full As Boolean) As String
    Dim str As String
    str = ActivePrinter
    If Full Then
        getActivePrinter = str
        Exit Function
    End If
    If InStr(str, " on ") > 0 Then
        getActivePrinter = Split(str, " on ")(0)
    'Ne01:에 있는 Samsung MLXXXX Series (192.168.0.xxx)
    ElseIf InStr(str, "에 있는 ") > 0 Then
        getActivePrinter = Split(str, "에 있는 ")(1)
    Else
        getActivePrinter = str
    End If
    
End Function

Private Sub test_FindPrinter()
    FindPrinter "PDF"
End Sub

Function FindPrinter(ByVal PrinterName As String) As String

    'This works with Windows 2000 and up
    
    Dim Arr As Variant
    Dim Device As Variant
    Dim Devices As Variant
    Dim Printer As String
    Dim RegObj As Object
    Dim RegValue As String
    Const HKEY_CURRENT_USER = &H80000001
    
    Set RegObj = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv")
    RegObj.EnumValues HKEY_CURRENT_USER, "Software\Microsoft\Windows NT\CurrentVersion\Devices", Devices, Arr
    
    For Each Device In Devices
        RegObj.GetStringValue HKEY_CURRENT_USER, "Software\Microsoft\Windows NT\CurrentVersion\Devices", Device, RegValue
        'Debug.Print Device
        'Printer = Device & " on " & Split(RegValue, ",")(1)  'English
        Printer = Split(RegValue, ",")(1) & "에 있는 " & Device 'Korean
        
        'If InStr(1, Printer, PrinterName, vbTextCompare) > 0 Then  'original code
        'If StrComp(Device, printerName, vbTextCompare) = 0 Then
        If Device Like "*" & PrinterName & "*" Then
            FindPrinter = Printer
            Exit Function
        End If
    Next
End Function

 

 

 

테스트만 하려면 test_SetActiveDuplex 에서 인수를 바꿔보세요.

2를 넘기면 양면인쇄(긴면묶기)로 설정하고

3을 넘기면 양면인쇄(짧은면묶기),

1을 넘기면 단면인쇄로 바뀝니다.

 

 

 

 

엑셀 2010 이상에서 지원합니다.

 

양면/단면, 프린트 품질, 흑백/칼라, 용지크기, 가로/세로크기, 용지함, 가로/세로 등의 속성도 추가로 설정이 가능합니다.

 

VBA7이상(2010)인 경우와 이하인 경우를 대비했지만 하위 버전에서는 테스트해보지 못해 작동을 보장하지 못합니다.

 

프린터 이름 때문에 한글 환경에서만 작동합니다.

영문 윈도우에서는 마지막 FindPrinter에서 프린터 이름이 " on " 이 사용되도록 주석을 수정해야됩니다.

코드 길이에서 보듯이 여러가지조건과 상황을 고려해서 시간을 투자했습니다.

 

온라인에도 구버전에서 작동하는 코드만 있고 365같은 버전에서도 제대로 작동하는 코드가 없는 상태라 여러가지 시행착오를 거쳐 2010이든 365든 상관없이 작동하도록 이렇게 코드를 올려 놓습니다.