Click here to Skip to main content
14,880,436 members
Articles / Programming Languages / C#
Tip/Trick
Posted 18 May 2012

Tagged as

Stats

71.6K views
4.7K downloads
18 bookmarked

How to print using Microsoft ReportViewer without showing it

Rate me:
Please Sign up or sign in to vote.
4.56/5 (8 votes)
21 May 2012CPL
How to print documents using the ReportViewer without showing it.

Introduction

Sometimes we need to print documents using report viewer without showing it.  After a thorough research, I found that the available code has problems especially in margins.

Finally I have decided to use reportviewer functions. As you know, the viewer doesn't show public functions, so we need to use  reverse engineer.

First Function, OnPrint

C#
use reflection technology to execute it as shown here:  
internal static object ExecuteFunction(object obj, object[] parms, string fnName)
{
    Type t = obj.GetType();
    MethodInfo[] infos = t.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
    var c = from pe in infos where pe.Name == fnName select pe;
    foreach (MethodInfo info in c)
    {
        return info.Invoke(obj, parms);
    }
    return null;
              
}
-------------------------------------------------
{
  object[] parms = { viewer, RoutedEventArgs.Empty };
  ExecuteFunction(viewer, parms, "OnPrint");
}

Using OnPrint shows the printer dialog every time I use it. If I have already decided to use a particular printer, I can spare showing the mentioned dialog box by rewriting a code in OnPrint.

We must define two functions in the window class which contain the viewer

C#
void OnRenderingCompletePrintOnly(object sender, System.ComponentModel.AsyncCompletedEventArgs args)
{
    object objviewer = viewer;
    object[] prms = { sender, args };
    PrintReportViewer.ExecuteFunction(objviewer, prms, "OnRenderingCompletePrintOnly");
}

Stream CreateStreamEMFPrintOnly(string name, string extension, Encoding encoding, 
       string mimeType, bool useChunking, Microsoft.ReportingServices.Interfaces.StreamOper operation)
{
    object objviewer = viewer;
    object[] prms = { name, extension, encoding, mimeType, useChunking, operation };
    Stream str = (Stream)PrintReportViewer.ExecuteFunction(
                  objviewer, prms, "CreateStreamEMFPrintOnly");
    return str;
}

If we using the rest of code in another class we must define two properties:

C#
public Microsoft.ReportingServices.Interfaces.CreateAndRegisterStream CreateAndRegisterStream
{
    get
    {
        return new Microsoft.ReportingServices.Interfaces.CreateAndRegisterStream(CreateStreamEMFPrintOnly);
    }
}
public System.ComponentModel.AsyncCompletedEventHandler AsyncCompletedEventHandler
{
    get
    {
        return new System.ComponentModel.AsyncCompletedEventHandler(this.OnRenderingCompletePrintOnly);
    }
}

I've defined other functions for reading and writing nonpublic properties.

C#
static object GetPropertyVal(object obj, string properityName)
{
    Type t = obj.GetType();
    PropertyInfo info = t.GetProperty(properityName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
    return info.GetValue(obj, null);
}

public static void WriteProperityVal(object srcobj, object val, string properityName)
{
    var infos = from inf in srcobj.GetType().GetProperties() where inf.Name == properityName select inf;
    foreach (PropertyInfo inf in infos)
    {
        inf.SetValue(srcobj, val, null);
    }
}

Finally this function instances classes  and executes functions to print

C#
public static void PrintByPriner(Report report,
       Microsoft.Reporting.WinForms.ReportViewer viewer,string Printername)
{
    viewer.RefreshReport();
    viewer.SetDisplayMode(Microsoft.Reporting.WinForms.DisplayMode.PrintLayout);
    PageSettings pagesettings = viewer.GetPageSettings();
    object objviewer = viewer;
    FieldInfo info = viewer.GetType().GetField("m_lastUIState",
       BindingFlags.FlattenHierarchy| BindingFlags.IgnoreCase |
       BindingFlags.Instance|BindingFlags.NonPublic);
    object m_lastUIState = info.GetValue(objviewer);
    object PostRenderArgs = null;
    var variables=from nn in viewer.GetType().Assembly.GetTypes() 
         where nn.Name.Contains("ReportViewerStatus")||
         nn.Name.Contains("PostRenderArgs") select nn;
    foreach (Type type in variables)
    {
        if (type.Name.Contains("ReportViewerStatus"))
        {
            object[] prms = { m_lastUIState };
            ExecuteFunction(type, prms, "DoesStateAllowPrinting");
        }
        if (type.Name.Contains("PostRenderArgs"))
        {
            object[] ooo = { false, false };
            PostRenderArgs = Activator.CreateInstance(type, ooo);
        }
    }
    object pr = ExecuteFunction(objviewer, null, "CreateDefaultPrintSettings");
    (pr as System.Drawing.Printing.PrinterSettings).Copies = 1;
          {
        object[] prms = { objviewer, pr };
        ExecuteFunction(objviewer, prms, "OnPrintingBegin");
    }
    object[] processprms = { 0, 0 };
    string deviceInfo = ExecuteFunction(objviewer, processprms, "CreateEMFDeviceInfo").ToString();
    ExecuteFunction(objviewer, null, "ProcessAsyncInvokes");
    WriteProperityVal(objviewer, true, "PrintDialogDisplayed");
    object[] parms = { "IMAGE", true, deviceInfo, 
      Microsoft.Reporting.WinForms.PageCountMode.Estimate, 
      report.CreateAndRegisterStream, report.AsyncCompletedEventHandler, PostRenderArgs, false };

    ExecuteFunction(objviewer, parms, "BeginAsyncRender");
    object currentReport = GetPropertyVal(objviewer, "CurrentReport");
    object fileManager = GetPropertyVal(currentReport, "FileManager");
    object ReportPrintDocument = null;
    var variables2 = from nn in viewer.GetType().Assembly.GetTypes() 
       where nn.Name.Contains("ReportPrintDocument") select nn;
    foreach (Type type in variables2) 
    {
        object[] parms2 = { fileManager, pagesettings.Clone() };
        ConstructorInfo ci = type.GetConstructor(BindingFlags.NonPublic|
          BindingFlags.Instance,null,new Type[]{fileManager.GetType(), typeof(PageSettings) }, null);
        ReportPrintDocument = ci.Invoke(parms2);
        WriteProperityVal(ReportPrintDocument, pr, "PrinterSettings");
        WriteProperityVal(ReportPrintDocument, report.Title , "DocumentName");
        ExecuteFunction(ReportPrintDocument, null, "Print");
    }
}

License

This article, along with any associated source code and files, is licensed under The Common Public License Version 1.0 (CPL)

Share

About the Author

Samer Hatem
Software Developer (Senior)
Syrian Arab Republic Syrian Arab Republic
No Biography provided

Comments and Discussions

 
QuestionPROBLEM WITH OPTION Print by default Pin
Member 1341650511-Mar-20 13:56
MemberMember 1341650511-Mar-20 13:56 
QuestionPrint only one time, second time exception Pin
Member 44573223-Sep-16 2:23
MemberMember 44573223-Sep-16 2:23 
AnswerRe: Print only one time, second time exception Pin
4pinsGigabit18-Nov-16 2:28
Member4pinsGigabit18-Nov-16 2:28 
QuestionPrint multiple times Pin
gjijon14-Oct-15 10:24
Membergjijon14-Oct-15 10:24 
QuestionSame issue as others reported - Only Prints Once Pin
GerryHayes12-Jul-15 8:21
MemberGerryHayes12-Jul-15 8:21 
QuestionPROBLEM WITH OPTION Print by default Pin
Member 1167342812-May-15 6:50
MemberMember 1167342812-May-15 6:50 
QuestionBUG: Only print one times with default printer ??? Pin
Ngô Quốc Hùng (hungnq)8-Jul-14 17:50
MemberNgô Quốc Hùng (hungnq)8-Jul-14 17:50 
AnswerRe: BUG: Only print one times with default printer ??? Pin
Samer Hatem8-Jul-14 21:45
MemberSamer Hatem8-Jul-14 21:45 
QuestionERROR Pin
ahug91z5-Jul-14 13:35
Memberahug91z5-Jul-14 13:35 
AnswerRe: ERROR Pin
Samer Hatem8-Jul-14 21:47
MemberSamer Hatem8-Jul-14 21:47 
QuestionI can not understand what use Namespace. Pin
AVOIMAN8-Jan-14 4:31
MemberAVOIMAN8-Jan-14 4:31 
AnswerRe: I can not understand what use Namespace. Pin
Samer Hatem8-Jan-14 22:30
MemberSamer Hatem8-Jan-14 22:30 
QuestionPrint multitime Pin
ngohoangminh9-May-13 19:14
Memberngohoangminh9-May-13 19:14 
AnswerRe: Print multitime Pin
Samer Hatem10-May-13 0:57
MemberSamer Hatem10-May-13 0:57 
GeneralRewrite code for more reusable and simple use PinPopular
Misha Safonov1-Nov-12 3:03
MemberMisha Safonov1-Nov-12 3:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.