C#双面打印解决方法(打印word\excel\图片)
最近需要按顺序打印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_DESCRIPTOR
public int pSecurityDescriptor;
} public const short CCDEVICENAME = ; public const short CCFORMNAME = ; [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 = ;
public const Int32 DM_COPY = ;
public const Int32 DM_IN_BUFFER = ;
public const Int32 DM_OUT_BUFFER = ;
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 = ;
//added this
public const int CCHFORMNAME = ; #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 = ;
IntPtr hPrinter = default(IntPtr);
PRINTER_DEFAULTS pd = default(PRINTER_DEFAULTS);
DEVMODE dm = new DEVMODE();
int nRet = ;
pd.DesiredAccess = PRINTER_ACCESS_USE;
nRet = OpenPrinter(sPrinterName, out hPrinter, ref pd);
if ((nRet == ) | (hPrinter.ToInt32() == )) {
if (GetLastError() == ) {
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, );
if ((nRet < )) {
errorMessage = "Cannot get the size of the DEVMODE structure.";
goto cleanup;
}
IntPtr iparg = Marshal.AllocCoTaskMem(nRet + );
nRet = DocumentProperties(IntPtr.Zero, hPrinter, sPrinterName, iparg, IntPtr.Zero, DM_OUT_BUFFER);
if ((nRet < )) {
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() != ))
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 = ;
int nRet = ;
Int32 nJunk = default(Int32);
if ((nDuplexSetting < ) | (nDuplexSetting > )) {
errorMessage = "Error: dwDuplexSetting is incorrect.";
return functionReturnValue;
}
pd.DesiredAccess = PRINTER_ACCESS_USE;
nRet = OpenPrinter(sPrinterName, out hPrinter, ref pd);
if ((nRet == ) | (hPrinter.ToInt32() == )) {
if (GetLastError() == ) {
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, );
if ((nRet < )) {
errorMessage = "Cannot get the size of the DEVMODE structure.";
goto cleanup;
}
IntPtr iparg = Marshal.AllocCoTaskMem(nRet + );
nRet = DocumentProperties(IntPtr.Zero, hPrinter, sPrinterName, iparg, IntPtr.Zero, DM_OUT_BUFFER);
if ((nRet < )) {
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 < )) {
errorMessage = "Unable to set duplex setting to this printer.";
goto cleanup;
}
GetPrinter(hPrinter, , IntPtr.Zero, , ref nBytesNeeded);
if ((nBytesNeeded == )) {
errorMessage = "GetPrinter failed.";
goto cleanup;
}
ptrPrinterInfo = Marshal.AllocCoTaskMem(nBytesNeeded + );
nRet = GetPrinter(hPrinter, , ptrPrinterInfo, nBytesNeeded, ref nJunk)?:;
if ((nRet == )) {
errorMessage = "Unable to get shared printer settings.";
goto cleanup;
}
pinfo = (PRINTER_INFO_9)Marshal.PtrToStructure(ptrPrinterInfo, pinfo.GetType());
pinfo.pDevMode = iparg;
pinfo.pSecurityDescriptor = ;
Marshal.StructureToPtr(pinfo, ptrPrinterInfo, true);
nRet = SetPrinter(hPrinter, , ptrPrinterInfo, )?:;
if ((nRet == )) {
errorMessage = "Unable to set shared printer settings.";
}
functionReturnValue = Convert.ToBoolean(nRet);
cleanup:
if ((hPrinter.ToInt32() != ))
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 = ; 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 = "";
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 = ; 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 == )
{ objWorkbooks = ExcelTool.GetWorkSheets(objExcel);
object[] parameters = null;
try
{
parameters = new object[];
parameters[] = ;
parameters[] = ;
parameters[] = ;
parameters[] = Missing;
parameters[] = pd.PrinterSettings.PrinterName;
parameters[] = Missing;
parameters[] = true;
parameters[] = 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[];
parameters[] = ;
parameters[] = ;
parameters[] = ;
parameters[] = Missing;
parameters[] = pd.PrinterSettings.PrinterName;
parameters[] = Missing;
parameters[] = true;
parameters[] = 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, , , e.PageSettings.PrintableArea.Width, e.PageSettings.PrintableArea.Height);
if (i == FileName.Length - )
{
e.HasMorePages = false;
}
else
{
e.HasMorePages = true;
}
i++;
};
如果是固定大小的话:
pd.PrintPage += (_, e) =>
{
var img = System.Drawing.Image.FromFile(FileName[i]);
int iWidth = ;
double hFactor = iWidth / (double)img.Width;
int iHeight = Convert.ToInt32(img.Height * hFactor);
Rectangle Rect = new Rectangle(, , iWidth, iHeight);
e.Graphics.DrawImage(img, Rect);
if (i == FileName.Length - )
{
e.HasMorePages = false;
}
else
{
e.HasMorePages = true;
}
i++;
};
我辛苦了几天累的代码,分享给有用之人:)
自己在做独立开发,希望广结英豪,尤其是像我一样脑子短路不用react硬拼anroid、ios原生想干点什么的朋友。
App独立开发群533838427
微信公众号『懒文』-->lanwenapp<--
C#双面打印解决方法(打印word\excel\图片)的更多相关文章
- 一个简单的解决方法:word文档打不开,错误提示mso.dll模块错误。
最近电脑Word无故出现故障,无法打开,提示错误信息如下: 问题事件名称: APPCRASH应用程序名: WINWORD.EXE应用程序版本: 11.0.8328.0应用程序时间戳: 4c717ed1 ...
- PDF/WORD/EXCEL 图片预览
一.PDF/WORD/EXCEL 转 XPS 转 第一页内容 转 图片 WORD.EXCEL转XPS (Office2010) public bool WordToXPS(string sourceP ...
- word插入图片显示不完整的解决的方法
有时在编写word文档,插入图片时,会出现图不完整的情况. 解决方法是:选中图片,段落格式设置为单位行距(不是22磅),图片格式为嵌入式.问题解决.
- PHP导出excel时数字变为科学计数的解决方法
在数据导出到excel时数字格式不对,一般分为以下两种情况. 1.excel单元格设置长度不够 解决方法: //在excel.php文件中 $objActSheet = $objPHPExcel-&g ...
- Excel公式的常见错误值及其解决方法
Excel公式的常见错误值及其解决方法 经常用Excel的朋友可能都会遇到一些莫名奇妙的错误值信息:# N/A!.#VALUE!.#DIV/O!等等,出现这些错误的原因有很多种,如果公式不能计算正确结 ...
- PDF/WORD/EXCEL/PPT 文档在线阅读
查资料看了2种解决方法: 1.通过办公软件dll转换,用flans去看 2.通过Aspose转换成pdf格式,在用js前台读pdf(我用的pdf.js) 今天我解决的就是WORD/EXCEL/PPT ...
- eWebeditor编辑器上传图片路径错误解决方法[疑难杂症]【转,作者:unvs】
做了一个多版本的网站,后台用的编辑器是eWebeditor,NET版,后面发现上传图片或者文件之后,路径错误无法显示,必须手工修改才行.. 为了更清楚的说明问题,我下面会说的比较详细,首先是网站文件框 ...
- css插入背景图片底部有白边的解决方法
相信很多小伙伴遇到过用CSS插入背景图时,底部出现白边的情况,如下图: 个人总结了2个方法如下: 解决方法1:给图片都加上 vertical-align: middle属性.有时,移动端也会有类似 ...
- WPF图片放大后模糊的解决方法
原文:WPF图片放大后模糊的解决方法 WPF中显示图片的方式很多,可以用Image控件来显示图像,或者直接设置一个控件的Background.图片的放大也很简单,直接设置显示图片的控件的Width和H ...
随机推荐
- 在Java中,你真的会日期转换吗
1.什么是SimpleDateFormat 在java doc对SimpleDateFormat的解释如下: SimpleDateFormat is a concrete class for form ...
- Class类和ClassLoader类的简单介绍
反射机制中的Class Class内部到底有什么呢?看下图! 代码: Class cls=Person.class; 1.Class类: 1. 对象照镜子后可以得到的信息:某个类的数据成员名,方法和构 ...
- 01布尔模型&倒排索引
原文链接: http://www.cnblogs.com/jacklu/p/8379726.html 博士一年级选了这门课 SEEM 5680 Text Mining Models and Appli ...
- 树莓派开发系列教程3--ssh、vnc远程访问
注意:树莓派系列的3篇文章里面的图片因为博客转移过程丢失了,非常抱歉 前言 远程访问有很多种方式可以实现.比如ssh.telnet.ftp.samba.远程桌面等等,各有优缺点.本文主要以ssh和远程 ...
- WPF拖动DataGrid滚动条时内容混乱的解决方法
WPF拖动DataGrid滚动条时内容混乱的解决方法 在WPF中,如果DataGrid里使用了模板列,当拖动滚动条时,往往会出现列表内容显示混乱的情况.解决方法就是在Binding的时候给Update ...
- jmeter主要组件
1.测试计划(Test plan) 2.线程组(Thread Group) 3.配置原件(Configuration) 4.逻辑控制器(Login Controller) 5.取样器(Sampler) ...
- mui app页面刷新问题 plus.webview.getWebviewById("").reload()
/** * 放回指定页面,并且刷新指定页面 * @param {Object} pageId 指定页面ID */ mui.app_refresh=function(pageId){ if(!mui.i ...
- 轻量级运维工具-pssh,pscp,prsync,pslurp,pnuke
批量执行,并行传输,远程killall #yum安装 yum install pssh -y #yun安装后pscp改名为pscp.pssh #源码编译 wget https://pypi.pytho ...
- [ python ] 字典的使用
数据类型划分: 可变数据类型:list.dict.set 不可哈希 不可变数据类型:tuple.bool.int.str 可哈希 字典 python内置了字典类型,使用键-值( ...
- 【转载】python-协程
转载自:廖雪峰的官方网站 协程,又称微线程,纤程.英文名Coroutine. 协程的概念很早就提出来了,但直到最近几年才在某些语言(如Lua)中得到广泛应用. 子程序,或者称为函数,在所有语言中都是层 ...