C# 양면 인쇄 솔루션(word\excel\그림 인쇄)

31229 단어
최근에는 워드, excel, 그림을 순서대로 인쇄해야 하는데, 그 중 일부는 단면 인쇄가 필요하고, 어떤 것은 양면 인쇄가 필요하다.인터넷에서 많은 방법을 찾아보았다.주로 몇 가지 방식으로 해결하는 데 집중한다
1,word의 print와 excel의 printout에 단양면을 설정합니다
2. printdocument의 printsettings의duplex 설정 단양면
시험해 본 후에 효과가 좋지 않았는데, 어제 마침내 MSDN에서 프린터의 단면을 직접 설정하는 코드를 찾았는데, 매우 유용하다.
using System.Runtime.InteropServices;
using System;

namespace MyDuplexSettings
{
class DuplexSettings
{
#region Win32 API Declaration


    [DllImport("kernel32.dll", EntryPoint = "GetLastError", SetLastError = false, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern Int32 GetLastError();


[DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool ClosePrinter(IntPtr hPrinter);


[DllImport("winspool.Drv", EntryPoint = "DocumentPropertiesA", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern int DocumentProperties(IntPtr hwnd, IntPtr hPrinter, [MarshalAs(UnmanagedType.LPStr)]
string pDeviceNameg, IntPtr pDevModeOutput, IntPtr pDevModeInput, int fMode);


[DllImport("winspool.Drv", EntryPoint = "GetPrinterA", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool GetPrinter(IntPtr hPrinter, Int32 dwLevel, IntPtr pPrinter, Int32 dwBuf, ref Int32 dwNeeded);


[DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
static extern int OpenPrinter(string pPrinterName, out IntPtr phPrinter, ref PRINTER_DEFAULTS pDefault);


[DllImport("winspool.Drv", EntryPoint = "SetPrinterA", ExactSpelling = true, SetLastError = true)]
public static extern bool SetPrinter(IntPtr hPrinter, int Level, IntPtr pPrinter, int Command);


[StructLayout(LayoutKind.Sequential)]
public struct PRINTER_DEFAULTS
{
    public IntPtr pDatatype;
    public IntPtr pDevMode;
    public int DesiredAccess;
}

[StructLayout(LayoutKind.Sequential)]
public struct PRINTER_INFO_9
{

    public IntPtr pDevMode;
        // Pointer to SECURITY_DESCRIPTOR
    public int pSecurityDescriptor;
}

public const short CCDEVICENAME = 32;

public const short CCFORMNAME = 32;

[StructLayout(LayoutKind.Sequential)]
public struct DEVMODE
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCDEVICENAME)]
    public string dmDeviceName;
    public short dmSpecVersion;
    public short dmDriverVersion;
    public short dmSize;
    public short dmDriverExtra;
    public int dmFields;
    public short dmOrientation;
    public short dmPaperSize;
    public short dmPaperLength;
    public short dmPaperWidth;
    public short dmScale;
    public short dmCopies;
    public short dmDefaultSource;
    public short dmPrintQuality;
    public short dmColor;
    public short dmDuplex;
    public short dmYResolution;
    public short dmTTOption;
    public short dmCollate;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCFORMNAME)]
    public string dmFormName;
    public short dmUnusedPadding;
    public short dmBitsPerPel;
    public int dmPelsWidth;
    public int dmPelsHeight;
    public int dmDisplayFlags;
    public int dmDisplayFrequency;
}


public const Int64    DM_DUPLEX = 0x1000L;
public const Int64 DM_ORIENTATION = 0x1L;
public const Int64 DM_SCALE = 0x10L;
public const Int64 DMORIENT_PORTRAIT = 0x1L;
public const Int64 DMORIENT_LANDSCAPE = 0x2L;
public const Int32  DM_MODIFY = 8;
public const Int32 DM_COPY = 2;
public const Int32 DM_IN_BUFFER = 8;
public const Int32 DM_OUT_BUFFER = 2;
public const Int32 PRINTER_ACCESS_ADMINISTER = 0x4;
public const Int32 PRINTER_ACCESS_USE = 0x8;
public const Int32 STANDARD_RIGHTS_REQUIRED = 0xf0000;
public const int PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE);
    //added this 
public const int CCHDEVICENAME = 32;
    //added this 
public const int CCHFORMNAME = 32;

    #endregion

#region Public Methods


/// <summary>
/// Method Name : GetPrinterDuplex 
/// Programmatically get the Duplex flag for the specified printer 
/// driver's default properties. 
/// </summary>
/// <param name="sPrinterName"> The name of the printer to be used. </param>
/// <param name="errorMessage"> this will contain error messsage if any. </param>
/// <returns> 
/// nDuplexSetting - One of the following standard settings: 
/// 0 = Error
/// 1 = None (Simplex)
/// 2 = Duplex on long edge (book) 
/// 3 = Duplex on short edge (legal) 
/// </returns>
/// <remarks>
/// </remarks>
public short GetPrinterDuplex(string sPrinterName, out string errorMessage)
{
    errorMessage = string.Empty;
    short functionReturnValue = 0;
    IntPtr hPrinter = default(IntPtr);
    PRINTER_DEFAULTS pd = default(PRINTER_DEFAULTS);
    DEVMODE dm = new DEVMODE();
    int nRet = 0;
    pd.DesiredAccess = PRINTER_ACCESS_USE;
    nRet = OpenPrinter(sPrinterName, out hPrinter, ref pd);
    if ((nRet == 0) | (hPrinter.ToInt32() == 0)) {
        if (GetLastError() == 5) {
            errorMessage = "Access denied -- See the article for more info.";
        } else {
            errorMessage = "Cannot open the printer specified " + "(make sure the printer name is correct).";
        }
        return functionReturnValue;
    }
    nRet = DocumentProperties(IntPtr.Zero, hPrinter, sPrinterName, IntPtr.Zero, IntPtr.Zero, 0);
    if ((nRet < 0)) {
        errorMessage = "Cannot get the size of the DEVMODE structure.";
        goto cleanup;
    }
    IntPtr iparg = Marshal.AllocCoTaskMem(nRet + 100);
    nRet = DocumentProperties(IntPtr.Zero, hPrinter, sPrinterName, iparg, IntPtr.Zero, DM_OUT_BUFFER);
    if ((nRet < 0)) {
        errorMessage = "Cannot get the DEVMODE structure.";
        goto cleanup;
    }
    dm = (DEVMODE)Marshal.PtrToStructure(iparg, dm.GetType());
    if (!Convert.ToBoolean(dm.dmFields & DM_DUPLEX)) {
        errorMessage = "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;
    }
    functionReturnValue = dm.dmDuplex;
    
    cleanup:
    if ((hPrinter.ToInt32() != 0))
        ClosePrinter(hPrinter);    
    return functionReturnValue;
}


/// <summary>
/// Method Name : SetPrinterDuplex     
/// Programmatically set the Duplex flag for the specified printer driver's default properties. 
/// </summary>
/// <param name="sPrinterName"> sPrinterName - The name of the printer to be used. </param>
/// <param name="nDuplexSetting"> 
/// nDuplexSetting - One of the following standard settings: 
/// 1 = None 
/// 2 = Duplex on long edge (book) 
/// 3 = Duplex on short edge (legal) 
/// </param>
///  <param name="errorMessage"> this will contain error messsage if any. </param>
/// <returns>
/// Returns: True on success, False on error.
/// </returns>
/// <remarks>
/// 
/// </remarks>
public bool SetPrinterDuplex(string sPrinterName, int nDuplexSetting, out string errorMessage)
{
    errorMessage = string.Empty;
    bool functionReturnValue = false;
    IntPtr hPrinter = default(IntPtr);
    PRINTER_DEFAULTS pd = default(PRINTER_DEFAULTS);
    PRINTER_INFO_9 pinfo = new PRINTER_INFO_9();
    DEVMODE dm = new DEVMODE();
    IntPtr ptrPrinterInfo = default(IntPtr);
    int nBytesNeeded = 0;
    int nRet = 0;
    Int32 nJunk = default(Int32);
    if ((nDuplexSetting < 1) | (nDuplexSetting > 3)) {
        errorMessage = "Error: dwDuplexSetting is incorrect.";
        return functionReturnValue;
    }
    pd.DesiredAccess = PRINTER_ACCESS_USE;
    nRet = OpenPrinter(sPrinterName, out hPrinter, ref pd);
    if ((nRet == 0) | (hPrinter.ToInt32() == 0)) {
        if (GetLastError() == 5) {
            errorMessage = "Access denied -- See the article for more info." ;
        } else {
            errorMessage = "Cannot open the printer specified " + "(make sure the printer name is correct).";
        }
        return functionReturnValue;
    }
    nRet = DocumentProperties(IntPtr.Zero, hPrinter, sPrinterName, IntPtr.Zero, IntPtr.Zero, 0);
    if ((nRet < 0)) {
        errorMessage = "Cannot get the size of the DEVMODE structure.";
        goto cleanup;
    }
    IntPtr iparg = Marshal.AllocCoTaskMem(nRet + 100);
    nRet = DocumentProperties(IntPtr.Zero, hPrinter, sPrinterName, iparg, IntPtr.Zero, DM_OUT_BUFFER);
    if ((nRet < 0)) {
        errorMessage = "Cannot get the DEVMODE structure.";
        goto cleanup;
    }
    dm = (DEVMODE)Marshal.PtrToStructure(iparg, dm.GetType());
    if (!Convert.ToBoolean(dm.dmFields & DM_DUPLEX)) {
        errorMessage = "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;
    }
    dm.dmDuplex = (short) nDuplexSetting;
    Marshal.StructureToPtr(dm, iparg, true);
    nRet = DocumentProperties(IntPtr.Zero, hPrinter, sPrinterName, pinfo.pDevMode, pinfo.pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER);
    if ((nRet < 0)) {
        errorMessage = "Unable to set duplex setting to this printer.";
        goto cleanup;
    }
    GetPrinter(hPrinter, 9, IntPtr.Zero, 0, ref nBytesNeeded);
    if ((nBytesNeeded == 0)) {
        errorMessage = "GetPrinter failed.";
        goto cleanup;
    }
    ptrPrinterInfo = Marshal.AllocCoTaskMem(nBytesNeeded + 100);
    nRet = GetPrinter(hPrinter, 9, ptrPrinterInfo, nBytesNeeded, ref nJunk)?1:0;
    if ((nRet == 0)) {
        errorMessage = "Unable to get shared printer settings.";
        goto cleanup;
    }
    pinfo = (PRINTER_INFO_9)Marshal.PtrToStructure(ptrPrinterInfo, pinfo.GetType());
    pinfo.pDevMode = iparg;
    pinfo.pSecurityDescriptor = 0;
    Marshal.StructureToPtr(pinfo, ptrPrinterInfo, true);
    nRet = SetPrinter(hPrinter, 9, ptrPrinterInfo, 0)?1:0;
    if ((nRet == 0)) {
        errorMessage = "Unable to set shared printer settings.";
    }
    functionReturnValue = Convert.ToBoolean(nRet);
    cleanup:
    if ((hPrinter.ToInt32() != 0))
        ClosePrinter(hPrinter);
    return functionReturnValue;
}
#endregion

}
}

사용 방법, word를 예로 들면:
public static void PrintWord(string FileName, PrintDocument pd)
        {
            //0 check if there are any winword process exist
            //if is,kill it
            Process[] wordProcess = Process.GetProcessesByName("WINWORD");
            for (int i = 0; i < wordProcess.Length; i++)
            {
                wordProcess[i].Kill();
            }
            object missing = System.Reflection.Missing.Value;
            object objFileName = FileName;
            object objPrintName = pd.PrinterSettings.PrinterName;
            WORD.Application objApp = new WORD.Application();
            WORD.Document objDoc = null;
            try
            {

                objDoc = FrameWork.WordTool.OpenWord(objApp, FileName);
                objDoc.Activate();
                object copies = "1";
                object pages = "";
                object range = WORD.WdPrintOutRange.wdPrintAllDocument;
                object items = WORD.WdPrintOutItem.wdPrintDocumentContent;
                object pageType = WORD.WdPrintOutPages.wdPrintAllPages;
                object oTrue = true;
                object oFalse = false;
                objApp.Options.PrintOddPagesInAscendingOrder = true;
                objApp.Options.PrintEvenPagesInAscendingOrder = true;
                objDoc.PrintOut(
                ref oTrue, ref oFalse, ref range, ref missing, ref missing, ref missing,
                ref items, ref copies, ref pages, ref pageType, ref oFalse, ref oTrue,
                ref missing, ref oFalse, ref missing, ref missing, ref missing, ref missing);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (objDoc != null)
                {
                    Marshal.ReleaseComObject(objDoc);
                    Marshal.FinalReleaseComObject(objDoc);
                    objDoc = null;
                }
                if (objApp != null)
                {
                    objApp.Quit(ref missing, ref missing, ref missing);
                    Marshal.ReleaseComObject(objApp);
                    Marshal.FinalReleaseComObject(objApp);
                    objApp = null;
                }
            }
        }

사용 방법, excel을 예로 들면, 나는 두 가지 표를 가지고 있는데, 인쇄 페이지 수를 인쇄에 고정시켰다.
public static void PrintExcel(string excelFileName, PrintDocument pd, int iFlag)
        {
            //0 check if there are any winword process exist
            //if is,kill it
            Process[] wordProcess = Process.GetProcessesByName("EXCEL");
            for (int i = 0; i < wordProcess.Length; i++)
            {
                wordProcess[i].Kill();
            }
            object Missing = System.Reflection.Missing.Value;
            object objExcel = null;
            object objWorkbooks = null;

            try
            {
                objExcel = ExcelTool.OpenExcel(excelFileName);
                if (iFlag == 1)
                {
                   
                    objWorkbooks = ExcelTool.GetWorkSheets(objExcel);
                    object[] parameters = null;
                    try
                    {
                        parameters = new object[8];
                        parameters[0] = 1;
                        parameters[1] = 4;
                        parameters[2] = 1;
                        parameters[3] = Missing;
                        parameters[4] = pd.PrinterSettings.PrinterName;
                        parameters[5] = Missing;
                        parameters[6] = true;
                        parameters[7] = Missing;
                        objWorkbooks.GetType().InvokeMember("PrintOut", System.Reflection.BindingFlags.InvokeMethod, null, objWorkbooks, parameters);
                    }
                    catch (Exception ex)
                    {
                        throw ex;
                    }
                }
                else
                {
                    
                    objWorkbooks = ExcelTool.GetWorkSheets(objExcel);
                    object[] parameters = null;
                    try
                    {
                        parameters = new object[8];
                        parameters[0] = 5;
                        parameters[1] = 5;
                        parameters[2] = 1;
                        parameters[3] = Missing;
                        parameters[4] = pd.PrinterSettings.PrinterName;
                        parameters[5] = Missing;
                        parameters[6] = true;
                        parameters[7] = Missing;
                        objWorkbooks.GetType().InvokeMember("PrintOut", System.Reflection.BindingFlags.InvokeMethod, null, objWorkbooks, parameters);
                    }
                    catch (Exception ex)
                    {
                        throw ex;
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (objWorkbooks != null)
                {
                    ExcelTool.ReleaseComObj(objWorkbooks);
                }
                if (objExcel != null)
                {
                    ExcelTool.ReleaseComObj(objExcel);
                }
                System.GC.Collect();
            }
        }

마지막으로 A4용지 인쇄 설정을 말하자면 다른 코드는 생략하고 이 문제를 고민하는 사람은 문제가 어디에 있는지 단번에 알아볼 수 있다.
용지 크기에 맞추려면:
 pd.PrintPage += (_, e) =>
                    {
                        var img = System.Drawing.Image.FromFile(FileName[i]);
                        e.Graphics.DrawImage(img, 20, 20, e.PageSettings.PrintableArea.Width, e.PageSettings.PrintableArea.Height);
                        if (i == FileName.Length - 1)
                        {
                            e.HasMorePages = false;
                        }
                        else
                        {
                            e.HasMorePages = true;
                        }
                        i++;
                    };

고정 크기라면:
pd.PrintPage += (_, e) =>
                    {
                        var img = System.Drawing.Image.FromFile(FileName[i]);
                        int iWidth = 520;
                        double hFactor = iWidth / (double)img.Width;
                        int iHeight = Convert.ToInt32(img.Height * hFactor);
                        Rectangle Rect = new Rectangle(170, 330, iWidth, iHeight);
                        e.Graphics.DrawImage(img, Rect);
                        if (i == FileName.Length - 1)
                        {
                            e.HasMorePages = false;
                        }
                        else
                        {
                            e.HasMorePages = true;
                        }
                        i++;
                    };

 
 
며칠 동안 고생한 코드를 유용한 사람에게 공유합니다:)

좋은 웹페이지 즐겨찾기