因为水晶报表的PaperSize是enum类型,但有时客户用的纸张不在其定义范围内,虽然在设计报表时可以选择目的打印机和纸型,但如果重新配置过该打印机则报表默认纸型不再有效,报表将按A4进行预览且会失真。
//获取本机所有打印机将其名称填充到comboBoxPrinters中:包含本地和网络打印机
foreach(string printer in System.Drawing.Printing.PrinterSettings.InstalledPrinters) { this.comboBoxPrinters.Items.Add(printer); }
//当从comboBoxPrinters中选择打印机时获取其支持的纸张大小将其填充到listBoxPapers
this.listBoxPapers.Items.Clear(); string printer = this.comboBoxPrinters.Text; this.m_printer = printer; Microsoft.Win32.RegistryKey rk; if(!this.comboBoxPrinters.Text.StartsWith(@"\\")) //本地打印机
rk = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Printers\\" + this.comboBoxPrinters.Text + "\\DsDriver"); else //网络打印机
{ string[] p = printer.Remove(0,2).Split(new char[] { '\\' }); string path = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Providers\\LanMan Print Services\\Servers\\" + p[0] + "\\Printers\\" + p[1] + "\\DsDriver"; rk = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(path); }
string[] papers = (string[])(rk.GetValue("printMediaSupported")); for(int i=0;i<papers.Length;i++) { this.listBoxPapers.Items.Add(papers[i]); }
//根据纸张名称获取其所在本地机上的PaperSize:调用的是PaperSizeGetter.Get_PaperSizes静态方法(是从水晶报表中reflect精简出来的,版权归原作者所有)
public class PaperSizeGetter { public static string OutputPort = String.Empty;
[DllImport("winspool.drv", CharSet=CharSet.Auto, SetLastError=true)] public static extern int DeviceCapabilities(string pDevice, string pPort, short fwCapabilities, IntPtr pOutput, IntPtr pDevMode); public static int[] Get_PaperSizes(string printer) { string text1 = printer; int num1 = FastDeviceCapabilities(0x10, IntPtr.Zero, -1, text1); if (num1 == -1) { return new int[0]; } int num2 = Marshal.SystemDefaultCharSize * 0x40; IntPtr ptr1 = Marshal.AllocCoTaskMem(num2 * num1); FastDeviceCapabilities(0x10, ptr1, -1, text1); IntPtr ptr2 = Marshal.AllocCoTaskMem(2 * num1); FastDeviceCapabilities(2, ptr2, -1, text1); IntPtr ptr3 = Marshal.AllocCoTaskMem(8 * num1); FastDeviceCapabilities(3, ptr3, -1, text1); int[] sizeArray1 = new int[num1]; for (int num3 = 0; num3 < num1; num3++) { string text2 = Marshal.PtrToStringAuto((IntPtr) (((long) ptr1) + (num2 * num3)), 0x40); int num4 = text2.IndexOf('\0'); if (num4 > -1) { text2 = text2.Substring(0, num4); } short num5 = Marshal.ReadInt16((IntPtr) (((long) ptr2) + (num3 * 2))); int num6 = Marshal.ReadInt32((IntPtr) (((long) ptr3) + (num3 * 8))); int num7 = Marshal.ReadInt32((IntPtr) ((((long) ptr3) + (num3 * 8)) + 4)); sizeArray1[num3] = System.Convert.ToInt32(num5); } Marshal.FreeCoTaskMem(ptr1); Marshal.FreeCoTaskMem(ptr2); Marshal.FreeCoTaskMem(ptr3); return sizeArray1; }
private static int FastDeviceCapabilities(short capability, IntPtr pointerToBuffer, int defaultValue, string printerName) { int num1 = DeviceCapabilities(printerName, OutputPort, capability, pointerToBuffer, IntPtr.Zero); if (num1 == -1) { return defaultValue; } return num1; } }
//根据纸型名称在其名称列表中的索引,获取该索引在调用Get_PaperSizes后的size数组中的对应值
int[] sizes = PaperSizeGetter.Get_PaperSizes(printerName); int paperSizeid = sizes[this.listBoxPapers.SelectedIndex];
//将该size赋值给报表对象
report.PrintOptions.PaperSize = (CrystalDecisions.Shared.PaperSize)(paperSizeid);
|
本地机的每种纸型在每个支持的打印机上都对应了个id值,不同的配置顺序,不同的客户机相同纸型名称对都会导致不同的id,怎么获取这个id是关键,例如本机的
Letter 1
Tabloid 3
Legal 5
A3 8
A4 9
A5 11
B4 119
B5 120
11x17 121
25x25 122 //自定义
PostScript 自定义页面大小 32767
从打印机服务器属性中删除25x25,增加26x26,再增加25x25
Letter 1
Tabloid 3
Legal 5
A3 8
A4 9
A5 11
B4 119
B5 120
11x17 121
26x26 122 //自定义
25x25 123 //自定义
PostScript 自定义页面大小 32767
通过reflect水晶报表的PaperSize属性得知水晶报表通过这个id来设置其纸张大小,所以才想出这么个笨方法暂时解决了客户的要求。
Get_PaperSizes方法,以及这个id真实涵义自己还没弄懂,还请高人指点。
来源:http://blog.chinaunix.net/uid-188267-id-91357.html