水晶报表

来源:互联网 发布:从数据库读取图片软件 编辑:程序博客网 时间:2024/05/01 23:12

因为水晶报表的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真实涵义自己还没弄懂,还请高人指点。