现在的位置: 首页 > 综合 > 正文

水晶报表自定义打印非完美解决方案 .

2012年09月25日 ⁄ 综合 ⁄ 共 12030字 ⁄ 字号 评论关闭

最近,项目中要使用水晶报表打印发票,必须用程序自定义纸张,并且设置为默认打印机的默认纸张,但是微软并没有在.NET1.1中给出很好的办法,大家在网上就此问题也是众说纷纭,百度狗狗了许久,终于找到了一个不算很好的办法,有不少不爽之处,但是整体功能上还是可以实现自定义纸张和设纸,这里稍加整理贴出来,但愿能抛砖引玉,以图能有完美的解决方案。

 

using System;
using System.ComponentModel;
using System.Drawing.Printing;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;

namespace HowToUseCustomPaper.MyPrinter
...{
/**//****************************************************************
* 原始来源:网上
* 创建日期: 2007-12-27
* 创 建 人: JueJue
* 描 述: Windows非完美实现添加和删除自定义纸张的类
* 更新时间:
* ****************************************************************
*/

/**//// <summary>
/// Windows非完美实现添加和删除自定义纸张的类
/// </summary>
public class UseCustomPaper
...{
private const int HWND_BROADCAST = 0xffff;
private const int WM_SETTINGCHANGE = 0x1a;

添加自定义纸张到打印机可用纸张中#region 添加自定义纸张到打印机可用纸张中
/**//// <summary>
/// 添加自定义纸张到打印机可用纸张中
/// </summary>
/// <param name="printerName">打印机名称</param>
/// <param name="paperName">纸张名称</param>
/// <param name="widthCm">宽度(厘米)</param>
/// <param name="heightCm">高度(厘米)</param>
/// <param name="leftCm">左边距</param>
/// <param name="rightCm">右边距</param>
/// <param name="topCm">顶部边距</param>
/// <param name="bottomCm">底部边距</param>
private static void AddCustomPaperSize(string printerName, string paperName, float widthCm, float heightCm, float leftCm, float rightCm, float topCm, float bottomCm)
...{
if (PlatformID.Win32NT == Environment.OSVersion.Platform)
...{
StringBuilder builder;
structPrinterDefaults pd = new structPrinterDefaults();
pd.pDatatype = null;
pd.pDevMode = IntPtr.Zero;
pd.DesiredAccess = 12;
IntPtr zero = IntPtr.Zero;
if (!OpenPrinter(printerName, out zero, ref pd)) // 打开打印机
...{
builder = new StringBuilder();
builder.AppendFormat("Failed to open the {0} printer, System error number: {1}", printerName, GetLastError());
throw new ApplicationException(builder.ToString());
}
try
...{
IntPtr ptr3;
PRINTER_INFO_9 printer_info_;
int num;
int num2;
DeleteForm(zero, paperName); // 先删除形
FormInfo1 form = new FormInfo1();
form.Flags = 0; // 此处可能表示纵向
form.pName = paperName;
form.Size.width = (int) (widthCm * 10000);
form.Size.height = (int) (heightCm * 10000);
form.ImageableArea.left = (int) (leftCm * 10000);
form.ImageableArea.right = (int) ((widthCm - rightCm) * 10000);
form.ImageableArea.top = (int) (topCm * 10000);
form.ImageableArea.bottom = (int) ((heightCm - bottomCm) * 10000);
if (!AddForm(zero, 1, ref form)) // 添加到形中
...{
builder = new StringBuilder();
builder.AppendFormat("Failed to add the custom paper size {0} to the printer {1}, System error number: {2}", paperName, printerName, GetLastError());
throw new ApplicationException(builder.ToString());
}
structDevMode structure = new structDevMode();
printer_info_.pDevMode = IntPtr.Zero;
int num3 = DocumentProperties(IntPtr.Zero, zero, printerName, IntPtr.Zero, IntPtr.Zero, 0);
if (num3 < 0)
...{
// 未能获取DEVMODE结构的大小
throw new ApplicationException("Cannot get the size of the DEVMODE structure.");
}
IntPtr pDevModeOutput = Marshal.AllocCoTaskMem(num3 + 100);
if (DocumentProperties(IntPtr.Zero, zero, printerName, pDevModeOutput, IntPtr.Zero, 2) < 0)
...{
// 未能正确获取DEVMODE结构
throw new ApplicationException("Cannot get the DEVMODE structure.");
}
structure = (structDevMode) Marshal.PtrToStructure(pDevModeOutput, structure.GetType());
structure.dmFields = 0x10000;
structure.dmFormName = paperName;

Marshal.StructureToPtr(structure, pDevModeOutput, true);
if (DocumentProperties(IntPtr.Zero, zero, printerName, printer_info_.pDevMode, printer_info_.pDevMode, 10 ) < 0) // 10
...{
// 不能设置打印机的纵/横向打印
throw new ApplicationException("Unable to set the orientation setting for this printer.");
}
GetPrinter(zero, 9, IntPtr.Zero, 0, out num); // 获取打印机
if (num == 0)
...{
// 获取打印机失败
throw new ApplicationException("GetPrinter failed. Couldn't get the # bytes needed for shared PRINTER_INFO_9 structure");
}
IntPtr pPrinter = Marshal.AllocCoTaskMem(num + 100);
if (!GetPrinter(zero, 9, pPrinter, num, out num2))
...{
throw new ApplicationException("GetPrinter failed. Couldn't get the shared PRINTER_INFO_9 structure");
}
printer_info_ = (PRINTER_INFO_9) Marshal.PtrToStructure(pPrinter, printer_info_.GetType());
printer_info_.pDevMode = pDevModeOutput;
Marshal.StructureToPtr(printer_info_, pPrinter, true);
if (!SetPrinter(zero, 9, pPrinter, 0 )) // 0
...{
// 设置打印机失败
throw new Win32Exception(Marshal.GetLastWin32Error(), "SetPrinter() failed. Couldn't set the printer settings");
}
SendMessageTimeout(new IntPtr(0xffff), 0x1a, IntPtr.Zero, IntPtr.Zero, SendMessageTimeoutFlags.SMTO_NORMAL, 0x3e8, out ptr3);
}
finally
...{
ClosePrinter(zero); // 关闭打印机
}
}
else
...{
structDevMode pDevMode = new structDevMode();
IntPtr hDC = CreateDC(null, printerName, null, ref pDevMode);
if (hDC != IntPtr.Zero)
...{
pDevMode.dmFields = 14;

pDevMode.dmPaperSize = 0x100;
pDevMode.dmPaperWidth = (short) (widthCm * 10000);
pDevMode.dmPaperLength = (short) (heightCm * 10000);
ResetDC(hDC, ref pDevMode);
DeleteDC(hDC);
}
}
}
#endregion

设置默认打印机的默认纸张为指定的自定义纸张#region 设置默认打印机的默认纸张为指定的自定义纸张
/**//// <summary>
/// 设置默认打印机的默认纸张为指定的自定义纸张
/// </summary>
/// <param name="paperName">纸张名称</param>
/// <param name="widthCm">纸张宽度(厘米)</param>
/// <param name="heightCm">纸张高度(厘米)</param>
/// <param name="leftCm">左边距</param>
/// <param name="rightCm">右边距</param>
/// <param name="topCm">顶部边距</param>
/// <param name="bottomCm">底部边距</param>
public static void AddCustomPaperSizeToDefaultPrinter(string paperName, float widthCm, float heightCm, float leftCm, float rightCm, float topCm, float bottomCm)
...{
PrintDocument document = new PrintDocument();
AddCustomPaperSize(document.PrinterSettings.PrinterName, paperName, widthCm, heightCm, leftCm, rightCm, topCm, bottomCm);
}
#endregion

从打印机纸张类型中删除指定的纸张#region 从打印机纸张类型中删除指定的纸张
/**//// <summary>
/// 从打印机纸张类型中删除指定的纸张
/// </summary>
/// <param name="printerName">打印机名称</param>
/// <param name="paperName">要删除的纸张名称</param>
private static void DeletePaperSize(string printerName, string paperName)
...{
if (PlatformID.Win32NT == Environment.OSVersion.Platform)
...{
structPrinterDefaults pd = new structPrinterDefaults();
pd.pDatatype = null;
pd.pDevMode = IntPtr.Zero;
pd.DesiredAccess = 12;
IntPtr zero = IntPtr.Zero;
if (OpenPrinter(printerName, out zero, ref pd))
...{
try
...{
DeleteForm(zero, paperName);
}
finally
...{
ClosePrinter(zero);
}
}
}
}
#endregion

删除指定的纸张类型#region 删除指定的纸张类型
/**//// <summary>
/// 删除指定的纸张类型
/// </summary>
/// <param name="paperName">要删除的纸张类型名称</param>
public static void DeletePaperSizeToDefaultPrinter(string paperName)
...{
PrintDocument document = new PrintDocument();
DeletePaperSize(document.PrinterSettings.PrinterName, paperName);
}
#endregion

封装的结构和API#region 封装的结构和API

[SuppressUnmanagedCodeSecurity, DllImport("winspool.Drv", EntryPoint="AddFormW", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Unicode, SetLastError=true, ExactSpelling=true)]
private static extern bool AddForm(IntPtr phPrinter, [MarshalAs(UnmanagedType.I4)] int level, ref FormInfo1 form);
[SuppressUnmanagedCodeSecurity, DllImport("winspool.Drv", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Unicode, SetLastError=true)]
private static extern bool ClosePrinter(IntPtr phPrinter);
[SuppressUnmanagedCodeSecurity, DllImport("GDI32.dll", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Unicode, SetLastError=true)]
private static extern IntPtr CreateDC([MarshalAs(UnmanagedType.LPTStr)] string pDrive, [MarshalAs(UnmanagedType.LPTStr)] string pName, [MarshalAs(UnmanagedType.LPTStr)] string pOutput, ref structDevMode pDevMode);
[SuppressUnmanagedCodeSecurity, DllImport("GDI32.dll", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Unicode, SetLastError=true)]
private static extern bool DeleteDC(IntPtr hDC);
[SuppressUnmanagedCodeSecurity, DllImport("winspool.Drv", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Unicode, SetLastError=true)]
private static extern bool DeleteForm(IntPtr phPrinter, [MarshalAs(UnmanagedType.LPTStr)] string pName);



[DllImport("winspool.Drv", EntryPoint="DocumentPropertiesA", CallingConvention=CallingConvention.StdCall, SetLastError=true, ExactSpelling=true)]
private static extern int DocumentProperties(IntPtr hwnd, IntPtr hPrinter, [MarshalAs(UnmanagedType.LPStr)] string pDeviceName, IntPtr pDevModeOutput, IntPtr pDevModeInput, int fMode);
[SuppressUnmanagedCodeSecurity, DllImport("kernel32.dll", CallingConvention=CallingConvention.StdCall, ExactSpelling=true)]
private static extern int GetLastError();
[DllImport("winspool.Drv", EntryPoint="GetPrinterA", CallingConvention=CallingConvention.StdCall, SetLastError=true, ExactSpelling=true)]
private static extern bool GetPrinter(IntPtr hPrinter, int dwLevel, IntPtr pPrinter, int dwBuf, out int dwNeeded);
[SuppressUnmanagedCodeSecurity, DllImport("winspool.Drv", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Unicode, SetLastError=true)]
private static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPTStr)] string printerName, out IntPtr phPrinter, ref structPrinterDefaults pd);
[SuppressUnmanagedCodeSecurity, DllImport("GDI32.dll", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Unicode, SetLastError=true)]
private static extern IntPtr ResetDC(IntPtr hDC, ref structDevMode pDevMode);
[DllImport("user32.dll", CharSet=CharSet.Auto, SetLastError=true)]
private static extern IntPtr SendMessageTimeout(IntPtr windowHandle, uint Msg, IntPtr wParam, IntPtr lParam, SendMessageTimeoutFlags flags, uint timeout, out IntPtr result);
[SuppressUnmanagedCodeSecurity, DllImport("winspool.Drv", EntryPoint="SetPrinterA", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Auto, SetLastError=true, ExactSpelling=true)]
private static extern bool SetPrinter(IntPtr hPrinter, [MarshalAs(UnmanagedType.I4)] int level, IntPtr pPrinter, [MarshalAs(UnmanagedType.I4)] int command);


[StructLayout(LayoutKind.Explicit, CharSet=CharSet.Unicode)]
private struct FormInfo1
...{
[MarshalAs(UnmanagedType.I4), FieldOffset(0)]
public uint Flags;
[FieldOffset(0x10)]
public UseCustomPaper.structRect ImageableArea;
[MarshalAs(UnmanagedType.LPWStr), FieldOffset(4)]
public string pName;
[FieldOffset(8)]
public UseCustomPaper.structSize Size;
}

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
private struct PRINTER_INFO_9
...{
public IntPtr pDevMode;
}

[Flags]
private enum SendMessageTimeoutFlags : uint
...{
SMTO_ABORTIFHUNG = 2,
SMTO_BLOCK = 1,
SMTO_NORMAL = 0,
SMTO_NOTIMEOUTIFNOTHUNG = 8
}

[StructLayout(LayoutKind.Sequential)]
private struct structDevMode
...{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=0x20)]
public string dmDeviceName;
[MarshalAs(UnmanagedType.U2)]
public short dmSpecVersion;
[MarshalAs(UnmanagedType.U2)]
public short dmDriverVersion;
[MarshalAs(UnmanagedType.U2)]
public short dmSize;
[MarshalAs(UnmanagedType.U2)]
public short dmDriverExtra;
[MarshalAs(UnmanagedType.U4)]
public int dmFields;
[MarshalAs(UnmanagedType.I2)]
public short dmOrientation;
[MarshalAs(UnmanagedType.I2)]
public short dmPaperSize;
[MarshalAs(UnmanagedType.I2)]
public short dmPaperLength;
[MarshalAs(UnmanagedType.I2)]
public short dmPaperWidth;
[MarshalAs(UnmanagedType.I2)]
public short dmScale;
[MarshalAs(UnmanagedType.I2)]
public short dmCopies;
[MarshalAs(UnmanagedType.I2)]
public short dmDefaultSource;
[MarshalAs(UnmanagedType.I2)]
public short dmPrintQuality;
[MarshalAs(UnmanagedType.I2)]
public short dmColor;
[MarshalAs(UnmanagedType.I2)]
public short dmDuplex;
[MarshalAs(UnmanagedType.I2)]
public short dmYResolution;
[MarshalAs(UnmanagedType.I2)]
public short dmTTOption;
[MarshalAs(UnmanagedType.I2)]
public short dmCollate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=0x20)]
public string dmFormName;
[MarshalAs(UnmanagedType.U2)]
public short dmLogPixels;
[MarshalAs(UnmanagedType.U4)]
public int dmBitsPerPel;
[MarshalAs(UnmanagedType.U4)]
public int dmPelsWidth;
[MarshalAs(UnmanagedType.U4)]
public int dmPelsHeight;
[MarshalAs(UnmanagedType.U4)]
public int dmNup;
[MarshalAs(UnmanagedType.U4)]
public int dmDisplayFrequency;
[MarshalAs(UnmanagedType.U4)]
public int dmICMMethod;
[MarshalAs(UnmanagedType.U4)]
public int dmICMIntent;
[MarshalAs(UnmanagedType.U4)]
public int dmMediaType;
[MarshalAs(UnmanagedType.U4)]
public int dmDitherType;
[MarshalAs(UnmanagedType.U4)]
public int dmReserved1;
[MarshalAs(UnmanagedType.U4)]
public int dmReserved2;
}

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
public struct structPrinterDefaults
...{
[MarshalAs(UnmanagedType.LPTStr)]
public string pDatatype;
public IntPtr pDevMode;
[MarshalAs(UnmanagedType.I4)]
public int DesiredAccess;
}

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
private struct structRect
...{
public int left;
public int top;
public int right;
public int bottom;
}

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
private struct structSize
...{
public int width;
public int height;
}
#endregion
}
}

然后,就可以在程序中调用其中方法:

 

ReportDocument rd = new ReportDocument();

rd.Load( ReportSourcePath );

rd.PrintOptions.PaperSize = DefaultPaperSize;

CrystalReportViewer crv = new CrystalReportViewer();

crv.ReportSource = rd;

crv.Invalidate();

rd.PrintToPrinter( 0, true, 0, 0 );

抱歉!评论已关闭.