2017-07-29 19 views
8

this私のrdlcをプリンタに直接印刷するのですが、streamを渡してMetafileオブジェクトを作成しようとしています。 (一般的なエラーがGDI +で発生した)プレビューなしでローカルレポートを印刷する - ストリームサイズが超過した、またはGDI + Cで一般的なエラーが発生しました

コード:ストリームサイズを超えまたはRDLC静的なコンテンツが多い場合

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(); 
      } 
     } 
    } 

それは私にエラーを与えます。私はそれのストリームを作成するために使用

私のデータセットは次のとおりです。 enter image description here

私はいくつかのコンテンツを削除した場合、私は、静的コンテンツはストリームサイズかどうかに影響を与えるべきではないかどうか知らないが、それは私にエラーを与えていませんRDLCからしかし、私はそれが再びエラーをスローすることを追加したとき(一般的なエラーがGDI +で発生した)

+0

コードはXMLファイルからhtmlを生成しています。 xmlには特殊文字(https://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references)が含まれている可能性がありますので、System.Net.WebUtility.HtmlEncode()を使用する必要があります – jdweng

+0

@jdwengストリームのリストを渡したとしたらバイト配列からストリームへと、あなたがあなたが言ったように私はする必要がありますか、印刷イベントハンドラでメタファイルを作成するよりも?私が更新した質問をご覧ください。 CreateStream関数を参照してください。 –

+0

実際にはこのコードは動作しますが、さらに多くのコンテンツを追加した場合は静的であるかrdlcのデータセットからエラーが発生しますGDI + Cで一般的なエラーが発生しました。 –

答えて

1

あなたは同じ問題を使用して取得しているとは知りませんが、ので、この機能はあなたの問題を解決することがあり使用私の最後で実行している:

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

これはうまく動作していますが、関数内にブランクストリームを作成するだけで、この関数を使用しないよりも返すよりも混乱します。 –

+0

@ 3rules私はまた、正確な理由を知らないが、report.Render( "Image"、deviceInfo、CreateStream、out warnings)を呼び出すときに、ここでコールバック関数を定義しなければなりません。コールバック関数は実行して実行しています。しかし、理由を知るように私は確かに答えを更新するでしょう。 –

+0

答えは –

3

一般的なエラー例外は診断にはかなりお粗末な例外です。それは "それはうまくいかなかった"という情報を伝えていません。 Graphicsクラスが描画オブジェクトを使用して問題に陥ったり、描画コマンドを基底のデバイスコンテキストに描画したりすると例外が発生します。このコードとそれをトラブルシューティングしたことから明らかな理由があります。プログラムのメモリが不足しています

Graphicsクラスは、基本的なデバイスコンテキストを管理されていないリソースとして扱います。なぜなら、より明白なOutOfMemoryExceptionが得られない基本的な理由です。通常は、スクリーンやプリンタにレンダリングするときと同じように、MemoryStreamにレンダリングされるため、この場合はそうではありません。 VS出力ウィンドウに最初のチャンス通知が表示されることがあります。タスクマネージャーにコミットサイズの列を追加すると追加の診断が可能になり、ギガバイトの北に向かうとトラブルが起きます。

このコードで特に注目すべき点は、プログラムがの場合は常にがこの例外で失敗する点です。あまりにも多くのページを持つレポートやあまりにも多くのレコードを持つデータテーブルを与えると、それは運命にある。必然的に、メタファイルレコードをメモリストリームに格納するには、あまりにも多くのメモリが必要になります。あなたがそれについて行うことができる唯一のことは、プログラムをよりメモリ効率の良いものにして、生産要求に対応できるようにすることです。ここにはたくさんの機会があります。

最初の観察では、MSDNコードサンプルからいくつかの不調を受け継いだということです。このようなサンプルは、一般的であり、一般的に注意すべきことですが、コーディングテクニックのデモンストレーションに焦点を当てています。コードを弾丸にすることは、ミッションの道に入り、未テストであり、読者に運動として残されます。注目すべきは、Dispose()の必要性をあまり無視していることです。提供されたDispose()メソッドは実際には何も実行しません。メモリストリームを破棄すると、読み取り不能とマークされます。 Metafile、LocalReport、およびPrintDocumentオブジェクトを適切に処理することはできません。これらの省略を修正するにはusingステートメントを使用してください。

第2の観察は、CreateStream()メソッドへの追加が非常に無駄であることです。また、悪い種類の廃棄物、それはラージオブジェクトヒープで非常に粗いです。 DataTableをCopy()する必要はなく、レポートには書き込まれません。 MemoryStreamを配列に変換して配列からMemoryStreamを作成する必要はありません。最初のMemoryStreamはすでにそのまま存在します。 を使用して使用しないでください。位置を0に設定してください。これは問題を解決するのに十分可能です。

問題が解決しない場合は、MemoryStreamではなくFileStreamの使用を検討する必要があります。それは効率と同様に、OSはそれが確実であり、ファイルの名前を選ぶ必要はありません。実際の問題ではなく、Path.GetTempFileName()を使用してください。 Dispose()メソッドがどのように役立ち、必要になったのかに注意してください。また、ファイルを再度削除する必要があります。または、ファイルを開くときにFileOptions.DeleteOnCloseオプションを使用して、自動化されているようにしてください。

最後に、OSの機能を活用したいと思うでしょう。現代のマシンはテラバイトのアドレス空間を提供することができ、LOHの断片化は決して問題にはなりません。プロジェクト>プロパティ>ビルドタブ> "32ビット優先"チェックボックスをオフにします。リリース構成に対してこの手順を繰り返します。あなたは、メモリ不足の問題と戦うときに決してそれを好むことはありません。私が提供する機能を使用する理由と同じ機能を使用して、私の終わりに

+0

答えはありがたいですが、それをはっきりと理解できませんでした。私は簡単な説明をしてください。私の質問ごとにはまだそれがなぜ起こるか知りたい! –

+0

プログラムのメモリが不足しています。より多くのメモリを提供します。 –

+0

オハイ、どうですか? –

関連する問題