首页 > C#双面打印解决方法(打印wordexcel图片)

C#双面打印解决方法(打印wordexcel图片)

最近需要按顺序打印word、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_DESCRIPTORpublic 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/// 
/// Method Name : GetPrinterDuplex 
/// Programmatically get the Duplex flag for the specified printer 
/// driver's default properties. 
/// 
///  The name of the printer to be used. 
///  this will contain error messsage if any. 
///  
/// nDuplexSetting - One of the following standard settings: 
/// 0 = Error
/// 1 = None (Simplex)
/// 2 = Duplex on long edge (book) 
/// 3 = Duplex on short edge (legal) 
/// 
/// 
/// 
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;
}/// 
/// Method Name : SetPrinterDuplex     
/// Programmatically set the Duplex flag for the specified printer driver's default properties. 
/// 
///  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) 
/// 
///   this will contain error messsage if any. 
/// 
/// Returns: True on success, False on error.
/// 
/// 
/// 
/// 
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 itProcess[] 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 itProcess[] 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++;};

 

 

我辛苦了几天累的代码,分享给有用之人:)

 

自己在做独立开发,希望广结英豪,尤其是像我一样脑子短路不用react硬拼anroid、ios原生想干点什么的朋友。

App独立开发群533838427

微信公众号『懒文』-->lanwenapp<--

转载于:https://www.cnblogs.com/matoo/p/3680117.html

更多相关:

  • 在.Net Framework中,配置文件一般采用的是XML格式的,.NET Framework提供了专门的ConfigurationManager来读取配置文件的内容,.net core中推荐使用json格式的配置文件,那么在.net core中该如何读取json文件呢?1、在Startup类中读取json配置文件1、使用Confi...

  •   1 public class FrameSubject extends JFrame {   2    3   …………..   4    5   //因为无法使用多重继承,这儿就只能使用对象组合的方式来引入一个   6    7   //java.util.Observerable对象了。   8    9   DateSub...

  • 本案例主要说明如何使用NSwag 工具使用桌面工具快速生成c# 客户端代码、快速的访问Web Api。 NSwagStudio 下载地址 比较强大、可以生成TypeScript、WebApi Controller、CSharp Client  1、运行WebApi项目  URL http://yourserver/swagger 然后...

  •   在绑定完Action的所有参数后,WebAPI并不会马上执行该方法,而要对参数进行验证,以保证输入的合法性.   ModelState 在ApiController中一个ModelState属性用来获取参数验证结果.   public abstract class ApiController : IHttpController,...

  • 1# 引用  C:AVEVAMarineOH12.1.SP4Aveva.ApplicationFramework.dll C:AVEVAMarineOH12.1.SP4Aveva.ApplicationFramework.Presentation.dll 2# 引用命名空间, using Aveva.Applicati...

  • #include #include #include #include #include #include #include

  • 题目:表示数值的字符串 请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100"、"5e2"、"-123"、"3.1416"、"0123"及"-1E-16"都表示数值,但"12e"、"1a3.14"、"1.2.3"、"+-5"及"12e+5.4"都不是。 解题: 数值错误的形式有多种多样,但是正确的...

  • 加法伺候  //超过20位数值相加---------------------------------------- function bigNumAdd(a, b) {if (!(typeof a === "string" && typeof b === "string")) return console.log("传入参数必...

  • 业务场景: 从中文字句中匹配出指定的中文子字符串 .这样的情况我在工作中遇到非常多, 特梳理总结如下. 难点: 处理GBK和utf8之类的字符编码, 同时正则匹配Pattern中包含汉字,要汉字正常发挥作用,必须非常谨慎.推荐最好统一为utf8编码,如果不是这种最优情况,也有酌情处理. 往往一个具有普适性的正则表达式会简化程...

  • 简单record 一下 #include // 'struct sockaddr_in' #include #include // 'struct ifreq' and 'struct if_nameindex' #include #inc...

  • 本文将给出一个实例用于介绍如何利用C#遍历目录中的文件并打印Word文件中的内容,同时在界面上利用一个相对平滑的进度条来显示文件处理的情况。下面是程序运行时的截图:   下面来看看程序的具体实现步骤。   首先是读取指定的目录并遍历其中的文件。这个功能很简单,我们只需要通过一个foreach循环遍历DirectoryInfo对象中...