PrintController
Controls how a document is printed, when printing from a Windows Forms application.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Windows.Win32;
using Windows.Win32.Foundation;
namespace System.Drawing.Printing
{
[NullableContext(1)]
[Nullable(0)]
public abstract class PrintController
{
[Nullable(0)]
internal sealed class SafeDeviceModeHandle : SafeHandle
{
public override bool IsInvalid => handle == (IntPtr)0;
public SafeDeviceModeHandle()
: base(IntPtr.Zero, true)
{
}
internal SafeDeviceModeHandle(IntPtr handle)
: base(IntPtr.Zero, true)
{
SetHandle(handle);
}
protected override bool ReleaseHandle()
{
if (!IsInvalid)
PInvokeCore.GlobalFree((HGLOBAL)handle);
handle = (IntPtr)0;
return true;
}
public static implicit operator IntPtr(SafeDeviceModeHandle handle)
{
return handle?.handle ?? ((IntPtr)0);
}
public static explicit operator SafeDeviceModeHandle(IntPtr handle)
{
return new SafeDeviceModeHandle(handle);
}
public static implicit operator HGLOBAL(SafeDeviceModeHandle handle)
{
if (handle != null)
return (HGLOBAL)handle.handle;
return HGLOBAL.Null;
}
}
[Nullable(2)]
private protected SafeDeviceModeHandle _modeHandle;
public virtual bool IsPreview => false;
[return: Nullable(2)]
public virtual Graphics OnStartPage(PrintDocument document, PrintPageEventArgs e)
{
return null;
}
public virtual void OnEndPage(PrintDocument document, PrintPageEventArgs e)
{
}
internal void Print(PrintDocument document)
{
PrintEventArgs printEventArgs = new PrintEventArgs(IsPreview ? PrintAction.PrintToPreview : ((!document.PrinterSettings.PrintToFile) ? PrintAction.PrintToPrinter : PrintAction.PrintToFile));
document.OnBeginPrint(printEventArgs);
if (printEventArgs.Cancel)
document.OnEndPrint(printEventArgs);
else {
OnStartPrint(document, printEventArgs);
if (printEventArgs.Cancel) {
document.OnEndPrint(printEventArgs);
OnEndPrint(document, printEventArgs);
} else {
bool flag = true;
try {
flag = (System.LocalAppContextSwitches.OptimizePrintPreview ? PrintLoopOptimized(document) : PrintLoop(document));
} finally {
try {
document.OnEndPrint(printEventArgs);
printEventArgs.Cancel = (flag | printEventArgs.Cancel);
} finally {
OnEndPrint(document, printEventArgs);
}
}
}
}
}
private bool PrintLoop(PrintDocument document)
{
QueryPageSettingsEventArgs queryPageSettingsEventArgs = new QueryPageSettingsEventArgs((PageSettings)document.DefaultPageSettings.Clone());
PrintPageEventArgs printPageEventArgs;
do {
document.OnQueryPageSettings(queryPageSettingsEventArgs);
if (queryPageSettingsEventArgs.Cancel)
return true;
printPageEventArgs = CreatePrintPageEvent(queryPageSettingsEventArgs.PageSettings);
Graphics graphics = OnStartPage(document, printPageEventArgs);
printPageEventArgs.SetGraphics(graphics);
try {
document.OnPrintPage(printPageEventArgs);
OnEndPage(document, printPageEventArgs);
} finally {
printPageEventArgs.Dispose();
}
if (printPageEventArgs.Cancel)
return true;
} while (printPageEventArgs.HasMorePages);
return false;
}
private bool PrintLoopOptimized(PrintDocument document)
{
PrintPageEventArgs printPageEventArgs = null;
QueryPageSettingsEventArgs queryPageSettingsEventArgs = new QueryPageSettingsEventArgs((PageSettings)document.DefaultPageSettings.Clone());
do {
queryPageSettingsEventArgs.PageSettingsChanged = false;
document.OnQueryPageSettings(queryPageSettingsEventArgs);
if (queryPageSettingsEventArgs.Cancel)
return true;
if (!queryPageSettingsEventArgs.PageSettingsChanged) {
if (printPageEventArgs == null)
printPageEventArgs = CreatePrintPageEvent(queryPageSettingsEventArgs.PageSettings);
else
printPageEventArgs.CopySettingsToDevMode = false;
Graphics graphics = OnStartPage(document, printPageEventArgs);
printPageEventArgs.SetGraphics(graphics);
} else {
printPageEventArgs = CreatePrintPageEvent(queryPageSettingsEventArgs.PageSettings);
Graphics graphics2 = OnStartPage(document, printPageEventArgs);
printPageEventArgs.SetGraphics(graphics2);
}
try {
document.OnPrintPage(printPageEventArgs);
OnEndPage(document, printPageEventArgs);
} finally {
printPageEventArgs.Graphics?.Dispose();
printPageEventArgs.SetGraphics(null);
}
if (printPageEventArgs.Cancel)
return true;
} while (printPageEventArgs.HasMorePages);
return false;
}
private PrintPageEventArgs CreatePrintPageEvent(PageSettings pageSettings)
{
Rectangle bounds = pageSettings.GetBounds(_modeHandle);
Rectangle marginBounds = new Rectangle(pageSettings.Margins.Left, pageSettings.Margins.Top, bounds.Width - (pageSettings.Margins.Left + pageSettings.Margins.Right), bounds.Height - (pageSettings.Margins.Top + pageSettings.Margins.Bottom));
return new PrintPageEventArgs(null, marginBounds, bounds, pageSettings);
}
public virtual void OnStartPrint(PrintDocument document, PrintEventArgs e)
{
_modeHandle = (SafeDeviceModeHandle)document.PrinterSettings.GetHdevmode(document.DefaultPageSettings);
}
public virtual void OnEndPrint(PrintDocument document, PrintEventArgs e)
{
_modeHandle?.Close();
}
}
}