无预览打印本地报告 - 超出流大小或GDI + C#中发生一般错误

问题描述 投票:8回答:2

我正在使用this文章将我的rdlc直接打印到打印机但是当我试图通过传递Metafile来创建stream对象时它给了我错误。 (GDI +中发生一般错误)

码:

 using System;
    using System.IO;
    using System.Data;
    using System.Text;
    using System.Drawing.Imaging;
    using System.Drawing.Printing;
    using System.Collections.Generic;
    using System.Windows.Forms;
    using Microsoft.Reporting.WinForms;

    public class Demo : IDisposable
    {
        private int m_currentPageIndex;
        private IList<Stream> m_streams;

        // Routine to provide to the report renderer, in order to
        //    save an image for each page of the report.
 private Stream CreateStream(string name, string fileNameExtension, Encoding encoding, string mimeType, bool willSeek)
        {
            DataSet ds = new DataSet();
            ds.Tables.Add(dsData.Tables[0].Copy());
            using (MemoryStream stream = new MemoryStream())
            {
                IFormatter bf = new BinaryFormatter();
                ds.RemotingFormat = SerializationFormat.Binary;
                bf.Serialize(stream, ds);
                data = stream.ToArray();
            }

            Stream stream1 = new MemoryStream(data);
            m_streams.Add(stream1);
            return stream1;
        }
        // Export the given report as an EMF (Enhanced Metafile) file.
        private void Export(LocalReport report)
        {
            string deviceInfo =
              @"<DeviceInfo>
                    <OutputFormat>EMF</OutputFormat>
                    <PageWidth>8.5in</PageWidth>
                    <PageHeight>11in</PageHeight>
                    <MarginTop>0.25in</MarginTop>
                    <MarginLeft>0.25in</MarginLeft>
                    <MarginRight>0.25in</MarginRight>
                    <MarginBottom>0.25in</MarginBottom>
                </DeviceInfo>";
            Warning[] warnings;
            m_streams = new List<Stream>();
            report.Render("Image", deviceInfo, CreateStream,
               out warnings);
            foreach (Stream stream in m_streams)
                stream.Position = 0;
        }
        // Handler for PrintPageEvents
        private void PrintPage(object sender, PrintPageEventArgs ev)
        {
            Metafile pageImage = new
               Metafile(m_streams[m_currentPageIndex]);

            // Adjust rectangular area with printer margins.
            Rectangle adjustedRect = new Rectangle(
                ev.PageBounds.Left - (int)ev.PageSettings.HardMarginX,
                ev.PageBounds.Top - (int)ev.PageSettings.HardMarginY,
                ev.PageBounds.Width,
                ev.PageBounds.Height);

            // Draw a white background for the report
            ev.Graphics.FillRectangle(Brushes.White, adjustedRect);

            // Draw the report content
            ev.Graphics.DrawImage(pageImage, adjustedRect);

            // Prepare for the next page. Make sure we haven't hit the end.
            m_currentPageIndex++;
            ev.HasMorePages = (m_currentPageIndex < m_streams.Count);
        }

        private void Print()
        {
            if (m_streams == null || m_streams.Count == 0)
                throw new Exception("Error: no stream to print.");
            PrintDocument printDoc = new PrintDocument();
            if (!printDoc.PrinterSettings.IsValid)
            {
                throw new Exception("Error: cannot find the default printer.");
            }
            else
            {
                printDoc.PrintPage += new PrintPageEventHandler(PrintPage);
                m_currentPageIndex = 0;
                printDoc.Print();
            }
        }
        // Create a local report for Report.rdlc, load the data,
        //    export the report to an .emf file, and print it.
        private void Run()
        {
            LocalReport report = new LocalReport();
           LocalReport report = new LocalReport();
            report.ReportPath = @"Reports\InvoiceReportTest.rdlc";
            report.DataSources.Add(
               new ReportDataSource("DataSet1", dsPrintDetails));
            Export(report);
            Print();
        }

        public void Dispose()
        {
            if (m_streams != null)
            {
                foreach (Stream stream in m_streams)
                    stream.Close();
                m_streams = null;
            }
        }

        public static void Main(string[] args)
        {
            using (Demo demo = new Demo())
            {
                demo.Run();
            }
        }
    }

当流大小超过或rdlc静态内容更多时,它会给我错误。

我用来创建它的流的数据集是:enter image description here

我不知道静态内容是否不应该影响流大小但是如果我从rdlc中删除一些内容但是当我添加它再次抛出错误(GDI +中发生一般错误)时它不会给我任何错误

c# printing stream rdlc metafile
2个回答
1
投票

在我的最后使用与你使用相同的功能并得到相同的问题不知道为什么我使用提供的功能,但它在我的运行,所以使用此功能可以解决您的问题:

private Stream CreateStream(string name, string fileNameExtension, Encoding encoding, string mimeType, bool willSeek)
        {
            Stream stream = new MemoryStream();
            m_streams.Add(stream);
            return stream;
        }

4
投票

一般错误异常是一个非常糟糕的诊断异常。它传达了“它没有用”之外的一些信息。只要Graphics类在使用绘图对象或将绘图命令渲染到底层设备上下文时遇到问题,就会引发异常。在这段代码中,有一个明显而明显的原因,以及你为解决它而做的事情:程序内存不足。

Graphics类将其底层设备上下文视为非托管资源,这是您没有获得更明显的OutOfMemoryException的基本原因。通常情况下,就像你用它来渲染到屏幕或打印机一样,只是因为它渲染到MemoryStream而不是这种情况。您可以在VS输出窗口中看到它的第一次机会通知的几率。在任务管理器中添加“提交大小”列可以提供额外的诊断,当它超过千兆字节时会出现故障。

这个代码特别值得注意的是程序将始终因此异常而失败。给它一个包含太多页面的报告或一个记录太多的数据表,它注定要失败。它将不可避免地总是需要太多的内存来将元文件记录存储在内存流中。您可以做的唯一事情是使程序更节省内存,以便它可以处理生产需求。这里有很多机会。

首先观察到你从MSDN代码示例中继承了一些邋iness。这是常见的,一般要注意的是,这些样本侧重于演示编码技术。使代码防弹会妨碍任务,未经测试并留给读者作为练习。值得注意的是它忽略了对Dispose()的过多需要。提供的Dispose()方法实际上并没有完成任何事情,处理内存流只是将其标记为不可读。它没有做的是正确处理Metafile,LocalReport和PrintDocument对象。使用using语句来纠正这些遗漏。

第二个观察是CreateStream()方法的添加非常浪费。还有那种糟糕的浪费,它在大型物体堆上非常粗糙。没有必要Copy()DataTable,报告不会写入它。没有必要将MemoryStream转换为数组并再次从数组创建MemoryStream,第一个MemoryStream已经很好了。不要使用,将其位置设置为0.这很可能足以解决问题。

如果仍有问题,则应考虑使用FileStream而不是MemoryStream。它将同样有效,操作系统确保它,必须为文件选择一个名称是唯一的额外负担。这里不是一个真正的问题,请使用Path.GetTempFileName()。请注意Dispose()方法现在如何变得有用和必要,您还需要再次删除该文件。或者更好的是,在打开文件时使用FileOptions.DeleteOnClose选项,因此它是自动的。

最后但并非最不重要的是,您将希望利用操作系统功能,现代机器可以提供数TB的地址空间,而LOH碎片绝不是问题。项目>属性>构建选项卡>取消选中“首选32位”复选框。重复发布配置。当你遇到内存不足的问题时,你永远不会喜欢它。

© www.soinside.com 2019 - 2024. All rights reserved.