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
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
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:
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.
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
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");
}
}
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.