--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal static partial class Interop
+{
+ internal static partial class Kernel32
+ {
+ [DllImport(Libraries.Kernel32, ExactSpelling = true, SetLastError = true)]
+ public static extern IntPtr GlobalFree(IntPtr handle);
+
+ public static IntPtr GlobalFree(HandleRef handle)
+ {
+ IntPtr result = GlobalFree(handle.Handle);
+ GC.KeepAlive(handle.Wrapper);
+ return result;
+ }
+ }
+}
{
internal partial class Kernel32
{
- [DllImport(Libraries.Kernel32, PreserveSig = true)]
- internal static extern IntPtr GlobalLock(IntPtr hMem);
+ [DllImport(Libraries.Kernel32, ExactSpelling = true, SetLastError = true)]
+ public static extern IntPtr GlobalLock(IntPtr hMem);
- [DllImport(Libraries.Kernel32, PreserveSig = true)]
- internal static extern int GlobalUnlock(IntPtr hMem);
+ public static IntPtr GlobalLock(HandleRef hMem)
+ {
+ IntPtr result = GlobalLock(hMem.Handle);
+ GC.KeepAlive(hMem.Wrapper);
+ return result;
+ }
+
+ [DllImport(Libraries.Kernel32, ExactSpelling = true)]
+ public static extern IntPtr GlobalUnlock(IntPtr hMem);
+
+ public static IntPtr GlobalUnlock(HandleRef hMem)
+ {
+ IntPtr result = GlobalUnlock(hMem.Handle);
+ GC.KeepAlive(hMem.Wrapper);
+ return result;
+ }
}
}
<Compile Include="System\Drawing\Imaging\Metafile.cs" />
<Compile Include="System\Drawing\Printing\PrinterUnit.cs" />
<Compile Include="System\Drawing\Printing\PreviewPageInfo.cs" />
+ <Compile Include="System\Drawing\Printing\PreviewPrintController.cs" />
<Compile Include="System\Drawing\Printing\PrintEventHandler.cs" />
<Compile Include="System\Drawing\Printing\PrintAction.cs" />
+ <Compile Include="System\Drawing\Printing\PrintController.cs" />
<Compile Include="System\Drawing\Printing\PrintPageEventHandler.cs" />
<Compile Include="System\Drawing\Printing\QueryPageSettingsEventArgs.cs" />
<Compile Include="System\Drawing\Printing\QueryPageSettingsEventHandler.cs" />
<Compile Include="$(CommonPath)\Interop\Windows\Kernel32\Interop.FreeLibrary.cs">
<Link>Common\Interop\Windows\Kernel32\Interop.FreeLibrary.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\Kernel32\Interop.GlobalFree.cs">
+ <Link>Common\Interop\Windows\Kernel32\Interop.GlobalFree.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\Kernel32\Interop.GlobalLock.cs">
+ <Link>Common\Interop\Windows\Kernel32\Interop.GlobalLock.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\Interop\Windows\Kernel32\Interop.LoadLibraryEx.cs">
<Link>Common\Interop\Windows\Kernel32\Interop.LoadLibraryEx.cs</Link>
</Compile>
[DllImport(ExternDll.Gdi32, SetLastError = true, ExactSpelling = true)]
public static extern IntPtr CreateDIBSection(HandleRef hdc, ref NativeMethods.BITMAPINFO_FLAT bmi, int iUsage, ref IntPtr ppvBits, IntPtr hSection, int dwOffset);
- [DllImport(ExternDll.Kernel32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto)]
- public static extern IntPtr GlobalFree(HandleRef handle);
-
[DllImport(ExternDll.Gdi32, SetLastError = true, CharSet = CharSet.Auto)]
public static extern int StartDoc(HandleRef hDC, DOCINFO lpDocInfo);
public static extern int EnumPrinters(int flags, string name, int level, IntPtr pPrinterEnum/*buffer*/,
int cbBuf, out int pcbNeeded, out int pcReturned);
- [DllImport(ExternDll.Kernel32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto)]
- public static extern IntPtr GlobalLock(HandleRef handle);
-
[DllImport(ExternDll.Gdi32, SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr /*HDC*/ ResetDC(HandleRef hDC, HandleRef /*DEVMODE*/ lpDevMode);
- [DllImport(ExternDll.Kernel32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto)]
- public static extern bool GlobalUnlock(HandleRef handle);
-
[DllImport(ExternDll.Gdi32, SetLastError = true, ExactSpelling = true)]
public static extern IntPtr CreateRectRgn(int x1, int y1, int x2, int y2);
if (!document.PrinterSettings.IsValid)
throw new InvalidPrinterException(document.PrinterSettings);
- _dc = document.PrinterSettings.CreateDeviceContext(modeHandle);
+ _dc = document.PrinterSettings.CreateDeviceContext(_modeHandle);
SafeNativeMethods.DOCINFO info = new SafeNativeMethods.DOCINFO();
info.lpszDocName = document.DocumentName;
if (document.PrinterSettings.PrintToFile)
Debug.Assert(_dc != null && _graphics == null, "PrintController methods called in the wrong order?");
base.OnStartPage(document, e);
- e.PageSettings.CopyToHdevmode(modeHandle);
- IntPtr modePointer = SafeNativeMethods.GlobalLock(new HandleRef(this, modeHandle));
+ e.PageSettings.CopyToHdevmode(_modeHandle);
+ IntPtr modePointer = Interop.Kernel32.GlobalLock(new HandleRef(this, _modeHandle));
try
{
IntPtr result = SafeNativeMethods.ResetDC(new HandleRef(_dc, _dc.Hdc), new HandleRef(null, modePointer));
}
finally
{
- SafeNativeMethods.GlobalUnlock(new HandleRef(this, modeHandle));
+ Interop.Kernel32.GlobalUnlock(new HandleRef(this, _modeHandle));
}
// int horizontalResolution = Windows.GetDeviceCaps(dc.Hdc, SafeNativeMethods.HORZRES);
get
{
IntPtr modeHandle = printerSettings.GetHdevmode();
-
Rectangle pageBounds = GetBounds(modeHandle);
- SafeNativeMethods.GlobalFree(new HandleRef(this, modeHandle));
+ Interop.Kernel32.GlobalFree(new HandleRef(this, modeHandle));
return pageBounds;
}
}
if (_paperSource == null)
{
IntPtr modeHandle = printerSettings.GetHdevmode();
- IntPtr modePointer = SafeNativeMethods.GlobalLock(new HandleRef(this, modeHandle));
+ IntPtr modePointer = Interop.Kernel32.GlobalLock(new HandleRef(this, modeHandle));
SafeNativeMethods.DEVMODE mode = (SafeNativeMethods.DEVMODE)Marshal.PtrToStructure(modePointer, typeof(SafeNativeMethods.DEVMODE));
PaperSource result = PaperSourceFromMode(mode);
- SafeNativeMethods.GlobalUnlock(new HandleRef(this, modeHandle));
- SafeNativeMethods.GlobalFree(new HandleRef(this, modeHandle));
+ Interop.Kernel32.GlobalUnlock(new HandleRef(this, modeHandle));
+ Interop.Kernel32.GlobalFree(new HandleRef(this, modeHandle));
return result;
}
if (_printerResolution == null)
{
IntPtr modeHandle = printerSettings.GetHdevmode();
- IntPtr modePointer = SafeNativeMethods.GlobalLock(new HandleRef(this, modeHandle));
+ IntPtr modePointer = Interop.Kernel32.GlobalLock(new HandleRef(this, modeHandle));
SafeNativeMethods.DEVMODE mode = (SafeNativeMethods.DEVMODE)Marshal.PtrToStructure(modePointer, typeof(SafeNativeMethods.DEVMODE));
PrinterResolution result = PrinterResolutionFromMode(mode);
- SafeNativeMethods.GlobalUnlock(new HandleRef(this, modeHandle));
- SafeNativeMethods.GlobalFree(new HandleRef(this, modeHandle));
+ Interop.Kernel32.GlobalUnlock(new HandleRef(this, modeHandle));
+ Interop.Kernel32.GlobalFree(new HandleRef(this, modeHandle));
return result;
}
/// </summary>
public void CopyToHdevmode(IntPtr hdevmode)
{
- IntPtr modePointer = SafeNativeMethods.GlobalLock(new HandleRef(null, hdevmode));
+ IntPtr modePointer = Interop.Kernel32.GlobalLock(hdevmode);
SafeNativeMethods.DEVMODE mode = (SafeNativeMethods.DEVMODE)Marshal.PtrToStructure(modePointer, typeof(SafeNativeMethods.DEVMODE));
if (_color.IsNotDefault && ((mode.dmFields & SafeNativeMethods.DM_COLOR) == SafeNativeMethods.DM_COLOR))
int retCode = SafeNativeMethods.DocumentProperties(NativeMethods.NullHandleRef, NativeMethods.NullHandleRef, printerSettings.PrinterName, modePointer, modePointer, SafeNativeMethods.DM_IN_BUFFER | SafeNativeMethods.DM_OUT_BUFFER);
if (retCode < 0)
{
- SafeNativeMethods.GlobalFree(new HandleRef(null, modePointer));
+ Interop.Kernel32.GlobalFree(modePointer);
}
}
- SafeNativeMethods.GlobalUnlock(new HandleRef(null, hdevmode));
+ Interop.Kernel32.GlobalUnlock(hdevmode);
}
private short ExtraBytes
get
{
IntPtr modeHandle = printerSettings.GetHdevmodeInternal();
- IntPtr modePointer = SafeNativeMethods.GlobalLock(new HandleRef(this, modeHandle));
+ IntPtr modePointer = Interop.Kernel32.GlobalLock(new HandleRef(this, modeHandle));
SafeNativeMethods.DEVMODE mode = (SafeNativeMethods.DEVMODE)Marshal.PtrToStructure(modePointer, typeof(SafeNativeMethods.DEVMODE));
short result = mode?.dmDriverExtra ?? 0;
- SafeNativeMethods.GlobalUnlock(new HandleRef(this, modeHandle));
- SafeNativeMethods.GlobalFree(new HandleRef(this, modeHandle));
+ Interop.Kernel32.GlobalUnlock(new HandleRef(this, modeHandle));
+ Interop.Kernel32.GlobalFree(new HandleRef(this, modeHandle));
return result;
}
ownHandle = true;
}
- IntPtr modePointer = SafeNativeMethods.GlobalLock(new HandleRef(null, modeHandle));
+ IntPtr modePointer = Interop.Kernel32.GlobalLock(modeHandle);
SafeNativeMethods.DEVMODE mode = (SafeNativeMethods.DEVMODE)Marshal.PtrToStructure(modePointer, typeof(SafeNativeMethods.DEVMODE));
PaperSize result = PaperSizeFromMode(mode);
- SafeNativeMethods.GlobalUnlock(new HandleRef(null, modeHandle));
+ Interop.Kernel32.GlobalUnlock(modeHandle);
if (ownHandle)
- SafeNativeMethods.GlobalFree(new HandleRef(null, modeHandle));
+ {
+ Interop.Kernel32.GlobalFree(modeHandle);
+ }
return result;
}
public void SetHdevmode(IntPtr hdevmode)
{
if (hdevmode == IntPtr.Zero)
+ {
throw new ArgumentException(SR.Format(SR.InvalidPrinterHandle, hdevmode));
+ }
- IntPtr pointer = SafeNativeMethods.GlobalLock(new HandleRef(null, hdevmode));
+ IntPtr pointer = Interop.Kernel32.GlobalLock(hdevmode);
SafeNativeMethods.DEVMODE mode = (SafeNativeMethods.DEVMODE)Marshal.PtrToStructure(pointer, typeof(SafeNativeMethods.DEVMODE));
if ((mode.dmFields & SafeNativeMethods.DM_COLOR) == SafeNativeMethods.DM_COLOR)
_paperSource = PaperSourceFromMode(mode);
_printerResolution = PrinterResolutionFromMode(mode);
- SafeNativeMethods.GlobalUnlock(new HandleRef(null, hdevmode));
+ Interop.Kernel32.GlobalUnlock(hdevmode);
}
/// <summary>
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-using System;
-using System.Collections;
-using System.Drawing.Imaging;
-
namespace System.Drawing.Printing
{
- public class PreviewPrintController : PrintController
+ public partial class PreviewPrintController : PrintController
{
- private bool useantialias;
- private ArrayList pageInfoList;
-
- public PreviewPrintController()
- {
- pageInfoList = new ArrayList();
- }
- public override bool IsPreview
- {
- get { return true; }
- }
-
public override void OnEndPage(PrintDocument document, PrintPageEventArgs e)
{
}
public override void OnStartPrint(PrintDocument document, PrintEventArgs e)
{
if (!document.PrinterSettings.IsValid)
+ {
throw new InvalidPrinterException(document.PrinterSettings);
+ }
- /* maybe we should reuse the images, and clear them? */
- foreach (PreviewPageInfo pi in pageInfoList)
+ foreach (PreviewPageInfo pi in _list)
+ {
pi.Image.Dispose();
+ }
- pageInfoList.Clear();
+ _list.Clear();
}
public override void OnEndPrint(PrintDocument document, PrintEventArgs e)
PreviewPageInfo info = new PreviewPageInfo(image, new Size(e.PageSettings.PaperSize.Width,
e.PageSettings.PaperSize.Height));
- pageInfoList.Add(info);
+ _list.Add(info);
Graphics g = Graphics.FromImage(info.Image);
g.FillRectangle(new SolidBrush(Color.White), new Rectangle(new Point(0, 0), new Size(image.Width, image.Height)));
return g;
}
-
- public virtual bool UseAntiAlias
- {
- get { return useantialias; }
- set { useantialias = value; }
- }
-
- public PreviewPageInfo[] GetPreviewPageInfo()
- {
- PreviewPageInfo[] pi = new PreviewPageInfo[pageInfoList.Count];
- pageInfoList.CopyTo(pi);
- return pi;
- }
-
}
}
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.Collections;
-using System.Diagnostics;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Drawing.Internal;
/// <summary>
/// A PrintController which "prints" to a series of images.
/// </summary>
- public class PreviewPrintController : PrintController
+ public partial class PreviewPrintController : PrintController
{
- private readonly IList _list = new ArrayList(); // list of PreviewPageInfo
- private System.Drawing.Graphics _graphics;
+ private Graphics _graphics;
private DeviceContext _dc;
- private bool _antiAlias;
-
- private void CheckSecurity()
- {
- }
-
- /// <summary>
- /// This is new public property which notifies if this controller is used for PrintPreview.
- /// </summary>
- public override bool IsPreview
- {
- get
- {
- return true;
- }
- }
/// <summary>
/// Implements StartPrint for generating print preview information.
/// </summary>
public override void OnStartPrint(PrintDocument document, PrintEventArgs e)
{
- Debug.Assert(_dc == null && _graphics == null, "PrintController methods called in the wrong order?");
-
- // For security purposes, don't assume our public methods are called in any particular order
- CheckSecurity();
-
base.OnStartPrint(document, e);
if (!document.PrinterSettings.IsValid)
+ {
throw new InvalidPrinterException(document.PrinterSettings);
+ }
// We need a DC as a reference; we don't actually draw on it.
// We make sure to reuse the same one to improve performance.
- _dc = document.PrinterSettings.CreateInformationContext(modeHandle);
+ _dc = document.PrinterSettings.CreateInformationContext(_modeHandle);
}
/// <summary>
/// </summary>
public override Graphics OnStartPage(PrintDocument document, PrintPageEventArgs e)
{
- Debug.Assert(_dc != null && _graphics == null, "PrintController methods called in the wrong order?");
-
- // For security purposes, don't assume our public methods are called in any particular order
- CheckSecurity();
-
base.OnStartPage(document, e);
if (e.CopySettingsToDevMode)
{
- e.PageSettings.CopyToHdevmode(modeHandle);
+ e.PageSettings.CopyToHdevmode(_modeHandle);
}
Size size = e.PageBounds.Size;
{
// Adjust the origin of the graphics object to be at the
// user-specified margin location
- //
int dpiX = UnsafeNativeMethods.GetDeviceCaps(new HandleRef(_dc, _dc.Hdc), SafeNativeMethods.LOGPIXELSX);
int dpiY = UnsafeNativeMethods.GetDeviceCaps(new HandleRef(_dc, _dc.Hdc), SafeNativeMethods.LOGPIXELSY);
int hardMarginX_DU = UnsafeNativeMethods.GetDeviceCaps(new HandleRef(_dc, _dc.Hdc), SafeNativeMethods.PHYSICALOFFSETX);
_graphics.TranslateTransform(document.DefaultPageSettings.Margins.Left, document.DefaultPageSettings.Margins.Top);
}
-
_graphics.PrintingHelper = printGraphics;
-
- if (_antiAlias)
+ if (UseAntiAlias)
{
_graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
_graphics.SmoothingMode = SmoothingMode.AntiAlias;
/// </summary>
public override void OnEndPage(PrintDocument document, PrintPageEventArgs e)
{
- Debug.Assert(_dc != null && _graphics != null, "PrintController methods called in the wrong order?");
-
- // For security purposes, don't assume our public methods are called in any particular order
- CheckSecurity();
-
- _graphics.Dispose();
- _graphics = null;
+ if (_graphics != null)
+ {
+ _graphics.Dispose();
+ _graphics = null;
+ }
base.OnEndPage(document, e);
}
/// </summary>
public override void OnEndPrint(PrintDocument document, PrintEventArgs e)
{
- Debug.Assert(_dc != null && _graphics == null, "PrintController methods called in the wrong order?");
-
- // For security purposes, don't assume our public methods are called in any particular order
- CheckSecurity();
-
- _dc.Dispose();
- _dc = null;
-
- base.OnEndPrint(document, e);
- }
-
- public PreviewPageInfo[] GetPreviewPageInfo()
- {
- // For security purposes, don't assume our public methods are called in any particular order
- CheckSecurity();
-
- PreviewPageInfo[] temp = new PreviewPageInfo[_list.Count];
- _list.CopyTo(temp, 0);
- return temp;
- }
-
- public virtual bool UseAntiAlias
- {
- get
+ if (_dc != null)
{
- return _antiAlias;
- }
- set
- {
- _antiAlias = value;
+ _dc.Dispose();
+ _dc = null;
}
+
+ base.OnEndPrint(document, e);
}
}
}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections;
+using System.Drawing.Imaging;
+
+namespace System.Drawing.Printing
+{
+ public partial class PreviewPrintController : PrintController
+ {
+ private readonly IList _list = new ArrayList();
+
+ public override bool IsPreview => true;
+
+ public virtual bool UseAntiAlias { get; set; }
+
+ public PreviewPageInfo[] GetPreviewPageInfo()
+ {
+ var temp = new PreviewPageInfo[_list.Count];
+ _list.CopyTo(temp, 0);
+ return temp;
+ }
+ }
+}
namespace System.Drawing.Printing
{
-
- public abstract class PrintController
+ public abstract partial class PrintController
{
-
- public virtual bool IsPreview
- {
- get { return false; }
- }
- public virtual void OnEndPage(PrintDocument document, PrintPageEventArgs e)
- {
- }
-
public virtual void OnStartPrint(PrintDocument document, PrintEventArgs e)
{
}
public virtual void OnEndPrint(PrintDocument document, PrintEventArgs e)
{
}
-
- public virtual Graphics OnStartPage(PrintDocument document, PrintPageEventArgs e)
- {
- return null;
- }
}
}
/// <summary>
/// Controls how a document is printed.
/// </summary>
- public abstract class PrintController
+ public abstract partial class PrintController
{
- // DEVMODEs are pretty expensive, so we cache one here and share it with the
- // Standard and Preview print controllers. If it weren't for all the rules about API changes,
- // I'd consider making this protected.
-
- #region SafeDeviceModeHandle Class
-
/// <summary>
/// Represents a SafeHandle for a Printer's Device Mode struct handle (DEVMODE)
/// </summary>
+ /// <remarks>
+ /// DEVMODEs are pretty expensive, so we cache one here and share it
+ /// with the Standard and Preview print controllers.
+ /// </remarks>
internal sealed class SafeDeviceModeHandle : SafeHandle
{
- // This constructor is used by the P/Invoke marshaling layer
- // to allocate a SafeHandle instance. P/Invoke then does the
- // appropriate method call, storing the handle in this class.
- private SafeDeviceModeHandle() : base(IntPtr.Zero, true) { return; }
-
- internal SafeDeviceModeHandle(IntPtr handle)
- : base(IntPtr.Zero, true) // "true" means "owns the handle"
+ /// <summary>
+ /// This constructor is used by the P/Invoke marshaling layer
+ /// to allocate a SafeHandle instance. P/Invoke then does the
+ /// appropriate method call, storing the handle in this class.
+ /// </summary>
+ private SafeDeviceModeHandle() : base(IntPtr.Zero, ownsHandle: true)
{
- SetHandle(handle);
}
- public override bool IsInvalid
+ internal SafeDeviceModeHandle(IntPtr handle) : base(IntPtr.Zero, ownsHandle: true)
{
- get { return handle == IntPtr.Zero; }
+ SetHandle(handle);
}
- // Specifies how to free the handle.
- // The boolean returned should be true for success and false if the runtime
- // should fire a SafeHandleCriticalFailure MDA (CustomerDebugProbe) if that
- // MDA is enabled.
+ public override bool IsInvalid => handle == IntPtr.Zero;
+
+ /// <summary>
+ /// Specifies how to free the handle.
+ /// The boolean returned should be true for success and false if the runtime
+ /// should fire a SafeHandleCriticalFailure MDA (CustomerDebugProbe) if that
+ /// MDA is enabled.
+ /// </summary>
protected override bool ReleaseHandle()
{
if (!IsInvalid)
{
- SafeNativeMethods.GlobalFree(new HandleRef(this, handle));
+ Interop.Kernel32.GlobalFree(new HandleRef(this, handle));
}
- handle = IntPtr.Zero;
+ handle = IntPtr.Zero;
return true;
}
}
}
- #endregion
-
- internal SafeDeviceModeHandle modeHandle = null;
-
- /// <summary>
- /// Initializes a new instance of the <see cref='PrintController'/> class.
- /// </summary>
- protected PrintController()
- {
- }
-
-
- /// <summary>
- /// This is new public property which notifies if this controller is used for PrintPreview.
- /// </summary>
- public virtual bool IsPreview
- {
- get
- {
- return false;
- }
- }
+ private protected SafeDeviceModeHandle _modeHandle = null;
- // WARNING: if you have nested PrintControllers, this method won't get called on the inner one.
- // Add initialization code to StartPrint or StartPage instead.
+ /// <remarks>
+ /// If you have nested PrintControllers, this method won't get called on the inner one.
+ /// Add initialization code to StartPrint or StartPage instead.
+ /// </remarks>
internal void Print(PrintDocument document)
{
- //
// Get the PrintAction for this event
PrintAction printAction;
if (IsPreview)
// Check that user has permission to print to this particular printer
PrintEventArgs printEvent = new PrintEventArgs(printAction);
- document._OnBeginPrint(printEvent);
+ document.OnBeginPrint(printEvent);
if (printEvent.Cancel)
{
- document._OnEndPrint(printEvent);
+ document.OnEndPrint(printEvent);
return;
}
OnStartPrint(document, printEvent);
if (printEvent.Cancel)
{
- document._OnEndPrint(printEvent);
+ document.OnEndPrint(printEvent);
OnEndPrint(document, printEvent);
return;
}
{
try
{
- document._OnEndPrint(printEvent);
+ document.OnEndPrint(printEvent);
printEvent.Cancel = canceled | printEvent.Cancel;
}
finally
}
}
- // Returns true if print was aborted.
- // WARNING: if you have nested PrintControllers, this method won't get called on the inner one
- // Add initialization code to StartPrint or StartPage instead.
+ /// <summary>
+ /// Returns true if print was aborted.
+ /// </summary>
+ /// <remarks>
+ /// If you have nested PrintControllers, this method won't get called on the inner one
+ /// Add initialization code to StartPrint or StartPage instead.
+ /// </remarks>
private bool PrintLoop(PrintDocument document)
{
QueryPageSettingsEventArgs queryEvent = new QueryPageSettingsEventArgs((PageSettings)document.DefaultPageSettings.Clone());
while (true)
{
- document._OnQueryPageSettings(queryEvent);
+ document.OnQueryPageSettings(queryEvent);
if (queryEvent.Cancel)
{
return true;
try
{
- document._OnPrintPage(pageEvent);
+ document.OnPrintPage(pageEvent);
OnEndPage(document, pageEvent);
}
finally
{
return false;
}
- else
- {
- // loop
- }
}
}
while (true)
{
queryEvent.PageSettingsChanged = false;
- document._OnQueryPageSettings(queryEvent);
+ document.OnQueryPageSettings(queryEvent);
if (queryEvent.Cancel)
{
return true;
try
{
- document._OnPrintPage(pageEvent);
+ document.OnPrintPage(pageEvent);
OnEndPage(document, pageEvent);
}
finally
private PrintPageEventArgs CreatePrintPageEvent(PageSettings pageSettings)
{
- Debug.Assert((modeHandle != null), "modeHandle is null. Someone must have forgot to call base.StartPrint");
+ Debug.Assert((_modeHandle != null), "modeHandle is null. Someone must have forgot to call base.StartPrint");
- Rectangle pageBounds = pageSettings.GetBounds(modeHandle);
+ Rectangle pageBounds = pageSettings.GetBounds(_modeHandle);
Rectangle marginBounds = new Rectangle(pageSettings.Margins.Left,
pageSettings.Margins.Top,
pageBounds.Width - (pageSettings.Margins.Left + pageSettings.Margins.Right),
return pageEvent;
}
-
/// <summary>
/// When overridden in a derived class, begins the control sequence of when and how to print a document.
/// </summary>
public virtual void OnStartPrint(PrintDocument document, PrintEventArgs e)
{
- modeHandle = (SafeDeviceModeHandle)document.PrinterSettings.GetHdevmode(document.DefaultPageSettings);
- }
-
- /// <summary>
- /// When overridden in a derived class, begins the control sequence of when and how to print a page in a document.
- /// </summary>
- public virtual Graphics OnStartPage(PrintDocument document, PrintPageEventArgs e)
- {
- return null;
- }
-
- /// <summary>
- /// When overridden in a derived class, completes the control sequence of when and how to print a page in a document.
- /// </summary>
- public virtual void OnEndPage(PrintDocument document, PrintPageEventArgs e)
- {
+ _modeHandle = (SafeDeviceModeHandle)document.PrinterSettings.GetHdevmode(document.DefaultPageSettings);
}
/// <summary>
/// </summary>
public virtual void OnEndPrint(PrintDocument document, PrintEventArgs e)
{
- Debug.Assert((modeHandle != null), "modeHandle is null. Someone must have forgot to call base.StartPrint");
- if (modeHandle != null)
- {
- modeHandle.Close();
- }
+ _modeHandle?.Close();
}
}
}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Drawing.Printing
+{
+ public abstract partial class PrintController
+ {
+ protected PrintController()
+ {
+ }
+
+ public virtual bool IsPreview => false;
+
+ /// <summary>
+ /// When overridden in a derived class, begins the control sequence of when and how to print a page in a document.
+ /// </summary>
+ public virtual Graphics OnStartPage(PrintDocument document, PrintPageEventArgs e)
+ {
+ return null;
+ }
+
+ /// <summary>
+ /// When overridden in a derived class, completes the control sequence of when and how to print a page in a document.
+ /// </summary>
+ public virtual void OnEndPage(PrintDocument document, PrintPageEventArgs e)
+ {
+ }
+ }
+}
}
}
- internal void _OnBeginPrint(PrintEventArgs e)
- {
- OnBeginPrint(e);
- }
-
/// <summary>
/// Raises the <see cref='BeginPrint'/> event.
/// </summary>
- protected virtual void OnBeginPrint(PrintEventArgs e)
- {
- if (_beginPrintHandler != null)
- _beginPrintHandler(this, e);
- }
-
- internal void _OnEndPrint(PrintEventArgs e)
+ protected internal virtual void OnBeginPrint(PrintEventArgs e)
{
- OnEndPrint(e);
+ _beginPrintHandler?.Invoke(this, e);
}
/// <summary>
/// Raises the <see cref='EndPrint'/> event.
/// </summary>
- protected virtual void OnEndPrint(PrintEventArgs e)
+ protected internal virtual void OnEndPrint(PrintEventArgs e)
{
- if (_endPrintHandler != null)
- _endPrintHandler(this, e);
- }
-
- internal void _OnPrintPage(PrintPageEventArgs e)
- {
- OnPrintPage(e);
+ _endPrintHandler?.Invoke(this, e);
}
/// <summary>
/// Raises the <see cref='PrintPage'/> event.
/// </summary>
- protected virtual void OnPrintPage(PrintPageEventArgs e)
- {
- if (_printPageHandler != null)
- _printPageHandler(this, e);
- }
-
- internal void _OnQueryPageSettings(QueryPageSettingsEventArgs e)
+ protected internal virtual void OnPrintPage(PrintPageEventArgs e)
{
- OnQueryPageSettings(e);
+ _printPageHandler?.Invoke(this, e);
}
/// <summary>
/// Raises the <see cref='QueryPageSettings'/> event.
/// </summary>
- protected virtual void OnQueryPageSettings(QueryPageSettingsEventArgs e)
+ protected internal virtual void OnQueryPageSettings(QueryPageSettingsEventArgs e)
{
- if (_queryHandler != null)
- _queryHandler(this, e);
+ _queryHandler?.Invoke(this, e);
}
/// <summary>
}
finally
{
- SafeNativeMethods.GlobalFree(new HandleRef(null, modeHandle));
+ Interop.Kernel32.GlobalFree(modeHandle);
}
return dc;
}
internal DeviceContext CreateDeviceContext(IntPtr hdevmode)
{
- IntPtr modePointer = SafeNativeMethods.GlobalLock(new HandleRef(null, hdevmode));
+ IntPtr modePointer = Interop.Kernel32.GlobalLock(hdevmode);
DeviceContext dc = DeviceContext.CreateDC(DriverName, PrinterNameInternal, (string)null, new HandleRef(null, modePointer));
- SafeNativeMethods.GlobalUnlock(new HandleRef(null, hdevmode));
+ Interop.Kernel32.GlobalUnlock(hdevmode);
return dc;
}
}
finally
{
- SafeNativeMethods.GlobalFree(new HandleRef(null, modeHandle));
+ Interop.Kernel32.GlobalFree(modeHandle);
}
return dc;
}
// A read-only DC, which is faster than CreateHdc
internal DeviceContext CreateInformationContext(IntPtr hdevmode)
{
- IntPtr modePointer = SafeNativeMethods.GlobalLock(new HandleRef(null, hdevmode));
+ IntPtr modePointer = Interop.Kernel32.GlobalLock(hdevmode);
DeviceContext dc = DeviceContext.CreateIC(DriverName, PrinterNameInternal, (string)null, new HandleRef(null, modePointer));
- SafeNativeMethods.GlobalUnlock(new HandleRef(null, hdevmode));
+ Interop.Kernel32.GlobalUnlock(hdevmode);
return dc;
}
return SR.NoDefaultPrinter;
IntPtr handle = data.hDevNames;
- IntPtr names = SafeNativeMethods.GlobalLock(new HandleRef(data, handle));
+ IntPtr names = Interop.Kernel32.GlobalLock(new HandleRef(data, handle));
if (names == IntPtr.Zero)
throw new Win32Exception();
string name = ReadOneDEVNAME(names, 1);
- SafeNativeMethods.GlobalUnlock(new HandleRef(data, handle));
+ Interop.Kernel32.GlobalUnlock(new HandleRef(data, handle));
names = IntPtr.Zero;
// Windows allocates them, but we have to free them
- SafeNativeMethods.GlobalFree(new HandleRef(data, data.hDevNames));
- SafeNativeMethods.GlobalFree(new HandleRef(data, data.hDevMode));
+ Interop.Kernel32.GlobalFree(new HandleRef(data, data.hDevNames));
+ Interop.Kernel32.GlobalFree(new HandleRef(data, data.hDevMode));
return name;
}
return SR.NoDefaultPrinter;
IntPtr handle = data.hDevNames;
- IntPtr names = SafeNativeMethods.GlobalLock(new HandleRef(data, handle));
+ IntPtr names = Interop.Kernel32.GlobalLock(new HandleRef(data, handle));
if (names == IntPtr.Zero)
throw new Win32Exception();
string name = ReadOneDEVNAME(names, 1);
- SafeNativeMethods.GlobalUnlock(new HandleRef(data, handle));
+ Interop.Kernel32.GlobalUnlock(new HandleRef(data, handle));
names = IntPtr.Zero;
// Windows allocates them, but we have to free them
- SafeNativeMethods.GlobalFree(new HandleRef(data, data.hDevNames));
- SafeNativeMethods.GlobalFree(new HandleRef(data, data.hDevMode));
+ Interop.Kernel32.GlobalFree(new HandleRef(data, data.hDevNames));
+ Interop.Kernel32.GlobalFree(new HandleRef(data, data.hDevMode));
return name;
}
return SR.NoDefaultPrinter;
IntPtr handle = data.hDevNames;
- IntPtr names = SafeNativeMethods.GlobalLock(new HandleRef(data, handle));
+ IntPtr names = Interop.Kernel32.GlobalLock(new HandleRef(data, handle));
if (names == IntPtr.Zero)
throw new Win32Exception();
string name = ReadOneDEVNAME(names, 2);
- SafeNativeMethods.GlobalUnlock(new HandleRef(data, handle));
+ Interop.Kernel32.GlobalUnlock(new HandleRef(data, handle));
names = IntPtr.Zero;
// Windows allocates them, but we have to free them
- SafeNativeMethods.GlobalFree(new HandleRef(data, data.hDevNames));
- SafeNativeMethods.GlobalFree(new HandleRef(data, data.hDevMode));
+ Interop.Kernel32.GlobalFree(new HandleRef(data, data.hDevNames));
+ Interop.Kernel32.GlobalFree(new HandleRef(data, data.hDevMode));
return name;
}
return SR.NoDefaultPrinter;
IntPtr handle = data.hDevNames;
- IntPtr names = SafeNativeMethods.GlobalLock(new HandleRef(data, handle));
+ IntPtr names = Interop.Kernel32.GlobalLock(new HandleRef(data, handle));
if (names == IntPtr.Zero)
throw new Win32Exception();
string name = ReadOneDEVNAME(names, 2);
- SafeNativeMethods.GlobalUnlock(new HandleRef(data, handle));
+ Interop.Kernel32.GlobalUnlock(new HandleRef(data, handle));
names = IntPtr.Zero;
// Windows allocates them, but we have to free them
- SafeNativeMethods.GlobalFree(new HandleRef(data, data.hDevNames));
- SafeNativeMethods.GlobalFree(new HandleRef(data, data.hDevMode));
+ Interop.Kernel32.GlobalFree(new HandleRef(data, data.hDevNames));
+ Interop.Kernel32.GlobalFree(new HandleRef(data, data.hDevMode));
return name;
}
/// <summary>
/// Creates a handle to a DEVMODE structure which correspond too the printer settings.When you are done with the
/// handle, you must deallocate it yourself:
- /// Windows.GlobalFree(handle);
+ /// Interop.Kernel32.GlobalFree(handle);
/// Where "handle" is the return value from this method.
/// </summary>
public IntPtr GetHdevmode()
{
- // Don't assert unmanaged code -- anyone using handles should have unmanaged code permission
IntPtr modeHandle = GetHdevmodeInternal();
_defaultPageSettings.CopyToHdevmode(modeHandle);
return modeHandle;
throw new InvalidPrinterException(this);
}
IntPtr handle = SafeNativeMethods.GlobalAlloc(SafeNativeMethods.GMEM_MOVEABLE, (uint)modeSize); // cannot be <0 anyway
- IntPtr pointer = SafeNativeMethods.GlobalLock(new HandleRef(null, handle));
+ IntPtr pointer = Interop.Kernel32.GlobalLock(handle);
//Get the DevMode only if its not cached....
if (_cachedDevmode != null)
int retCode = SafeNativeMethods.DocumentProperties(NativeMethods.NullHandleRef, NativeMethods.NullHandleRef, printer, pointer, pointer, SafeNativeMethods.DM_IN_BUFFER | SafeNativeMethods.DM_OUT_BUFFER);
if (retCode < 0)
{
- SafeNativeMethods.GlobalFree(new HandleRef(null, handle));
- SafeNativeMethods.GlobalUnlock(new HandleRef(null, handle));
+ Interop.Kernel32.GlobalFree(handle);
+ Interop.Kernel32.GlobalUnlock(handle);
return IntPtr.Zero;
}
- SafeNativeMethods.GlobalUnlock(new HandleRef(null, handle));
+ Interop.Kernel32.GlobalUnlock(handle);
return handle;
}
/// <summary>
/// Creates a handle to a DEVMODE structure which correspond to the printer and page settings.
/// When you are done with the handle, you must deallocate it yourself:
- /// Windows.GlobalFree(handle);
+ /// Interop.Kernel32.GlobalFree(handle);
/// Where "handle" is the return value from this method.
/// </summary>
public IntPtr GetHdevmode(PageSettings pageSettings)
/// <summary>
/// Creates a handle to a DEVNAMES structure which correspond to the printer settings.
/// When you are done with the handle, you must deallocate it yourself:
- /// Windows.GlobalFree(handle);
+ /// Interop.Kernel32.GlobalFree(handle);
/// Where "handle" is the return value from this method.
/// </summary>
public IntPtr GetHdevnames()
short offset = (short)(8 / Marshal.SystemDefaultCharSize); // Offsets are in characters, not bytes
uint namesSize = (uint)checked(Marshal.SystemDefaultCharSize * (offset + namesCharacters)); // always >0
IntPtr handle = SafeNativeMethods.GlobalAlloc(SafeNativeMethods.GMEM_MOVEABLE | SafeNativeMethods.GMEM_ZEROINIT, namesSize);
- IntPtr namesPointer = SafeNativeMethods.GlobalLock(new HandleRef(null, handle));
+ IntPtr namesPointer = Interop.Kernel32.GlobalLock(handle);
Marshal.WriteInt16(namesPointer, offset); // wDriverOffset
offset += WriteOneDEVNAME(driver, namesPointer, offset);
offset += WriteOneDEVNAME(outPort, namesPointer, offset);
Marshal.WriteInt16((IntPtr)(checked((long)namesPointer + 6)), offset); // wDefault
- SafeNativeMethods.GlobalUnlock(new HandleRef(null, handle));
+ Interop.Kernel32.GlobalUnlock(handle);
return handle;
}
}
}
- IntPtr modePointer = SafeNativeMethods.GlobalLock(new HandleRef(this, modeHandle));
+ IntPtr modePointer = Interop.Kernel32.GlobalLock(new HandleRef(this, modeHandle));
SafeNativeMethods.DEVMODE mode = (SafeNativeMethods.DEVMODE)Marshal.PtrToStructure(modePointer, typeof(SafeNativeMethods.DEVMODE));
switch (field)
{
result = defaultValue;
break;
}
- SafeNativeMethods.GlobalUnlock(new HandleRef(this, modeHandle));
+ Interop.Kernel32.GlobalUnlock(new HandleRef(this, modeHandle));
}
finally
{
if (ownHandle)
{
- SafeNativeMethods.GlobalFree(new HandleRef(this, modeHandle));
+ Interop.Kernel32.GlobalFree(new HandleRef(this, modeHandle));
}
}
return result;
if (hdevmode == IntPtr.Zero)
throw new ArgumentException(SR.Format(SR.InvalidPrinterHandle, hdevmode));
- IntPtr pointer = SafeNativeMethods.GlobalLock(new HandleRef(null, hdevmode));
+ IntPtr pointer = Interop.Kernel32.GlobalLock(hdevmode);
SafeNativeMethods.DEVMODE mode = (SafeNativeMethods.DEVMODE)Marshal.PtrToStructure(pointer, typeof(SafeNativeMethods.DEVMODE));
//Copy entire public devmode as a byte array...
_collate = (mode.dmCollate == SafeNativeMethods.DMCOLLATE_TRUE);
}
- SafeNativeMethods.GlobalUnlock(new HandleRef(null, hdevmode));
+ Interop.Kernel32.GlobalUnlock(hdevmode);
}
/// <summary>
public void SetHdevnames(IntPtr hdevnames)
{
if (hdevnames == IntPtr.Zero)
+ {
throw new ArgumentException(SR.Format(SR.InvalidPrinterHandle, hdevnames));
+ }
- IntPtr namesPointer = SafeNativeMethods.GlobalLock(new HandleRef(null, hdevnames));
+ IntPtr namesPointer = Interop.Kernel32.GlobalLock(hdevnames);
_driverName = ReadOneDEVNAME(namesPointer, 0);
_printerName = ReadOneDEVNAME(namesPointer, 1);
PrintDialogDisplayed = true;
- SafeNativeMethods.GlobalUnlock(new HandleRef(null, hdevnames));
+ Interop.Kernel32.GlobalUnlock(hdevnames);
}
/// <summary>
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using Xunit;
+
+namespace System.Drawing.Printing.Tests
+{
+ public class PreviewPrintControllerTests
+ {
+ [Fact]
+ public void Ctor_Default()
+ {
+ var controller = new PreviewPrintController();
+ Assert.True(controller.IsPreview);
+ }
+
+ [ConditionalFact(Helpers.AnyInstalledPrinters, Helpers.IsDrawingSupported)]
+ public void OnStartPage_InvokeWithPrint_ReturnsNull()
+ {
+ using (var document = new PrintDocument())
+ {
+ var controller = new PreviewPrintController();
+ controller.OnStartPrint(document, new PrintEventArgs());
+
+ var printEventArgs = new PrintPageEventArgs(null, Rectangle.Empty, Rectangle.Empty, new PageSettings());
+ Assert.NotNull(controller.OnStartPage(document, printEventArgs));
+
+ // Call OnEndPage.
+ controller.OnEndPage(document, printEventArgs);
+
+ // Call EndPrint.
+ controller.OnEndPrint(document, new PrintEventArgs());
+ }
+ }
+
+ [Fact]
+ public void OnStartPage_InvokeNullDocument_ThrowsNullReferenceException()
+ {
+ var controller = new PreviewPrintController();
+ var e = new PrintPageEventArgs(null, Rectangle.Empty, Rectangle.Empty, null);
+ Assert.Throws<NullReferenceException>(() => controller.OnStartPage(null, e));
+ }
+
+ [Fact]
+ public void OnStartPage_InvokeNullEventArgs_ThrowsNullReferenceException()
+ {
+ using (var document = new PrintDocument())
+ {
+ var controller = new PreviewPrintController();
+ Assert.Throws<NullReferenceException>(() => controller.OnStartPage(document, null));
+ }
+ }
+
+ [ConditionalFact(Helpers.AnyInstalledPrinters, Helpers.IsDrawingSupported)]
+ public void OnStartPage_InvokeNullEventArgsPageSettings_ReturnsNull()
+ {
+ using (var document = new PrintDocument())
+ {
+ var controller = new PreviewPrintController();
+ controller.OnStartPrint(document, new PrintEventArgs());
+
+ var printEventArgs = new PrintPageEventArgs(null, Rectangle.Empty, Rectangle.Empty, null);
+ Assert.Throws<NullReferenceException>(() => controller.OnStartPage(document, printEventArgs));
+ }
+ }
+
+ [Fact]
+ public void OnStartPage_PrintNotStarted_ThrowsNullReferenceException()
+ {
+ using (var document = new PrintDocument())
+ {
+ var controller = new PreviewPrintController();
+ var e = new PrintPageEventArgs(null, Rectangle.Empty, Rectangle.Empty, null);
+ Assert.Throws<NullReferenceException>(() => controller.OnStartPage(document, e));
+ }
+ }
+
+ [ConditionalFact(Helpers.IsDrawingSupported)]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Fixed a NullReferenceException")]
+ public void OnEndPage_InvokeWithoutStarting_Nop()
+ {
+ using (var document = new PrintDocument())
+ {
+ var controller = new PreviewPrintController();
+ controller.OnEndPage(document, new PrintPageEventArgs(null, Rectangle.Empty, Rectangle.Empty, null));
+ controller.OnEndPage(null, null);
+ }
+ }
+
+ public static IEnumerable<object[]> PrintEventArgs_TestData()
+ {
+ yield return new object[] { null };
+ yield return new object[] { new PrintEventArgs() };
+ }
+
+ [ConditionalTheory(Helpers.AnyInstalledPrinters, Helpers.IsDrawingSupported)]
+ [MemberData(nameof(PrintEventArgs_TestData))]
+ public void OnStartPrint_InvokeWithDocument_Success(PrintEventArgs e)
+ {
+ using (var document = new PrintDocument())
+ {
+ var controller = new PreviewPrintController();
+ controller.OnStartPrint(document, e);
+
+ // Call OnEndPrint
+ controller.OnEndPrint(document, e);
+ }
+ }
+
+ [ConditionalFact(Helpers.AnyInstalledPrinters, Helpers.IsDrawingSupported)]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ public void OnStartPrint_InvokeMultipleTimes_Success()
+ {
+ using (var document = new PrintDocument())
+ {
+ var controller = new PreviewPrintController();
+ controller.OnStartPrint(document, new PrintEventArgs());
+ controller.OnStartPrint(document, new PrintEventArgs());
+
+ // Call OnEndPrint
+ controller.OnEndPrint(document, new PrintEventArgs());
+ }
+ }
+
+ [Fact]
+ public void OnStartPrint_InvokeNullDocument_ThrowsNullReferenceException()
+ {
+ var controller = new PreviewPrintController();
+ Assert.Throws<NullReferenceException>(() => controller.OnStartPrint(null, new PrintEventArgs()));
+ }
+
+ [Theory]
+ [MemberData(nameof(PrintEventArgs_TestData))]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Fixed a NullReferenceException")]
+ public void OnEndPrint_InvokeWithoutStarting_Nop(PrintEventArgs e)
+ {
+ using (var document = new PrintDocument())
+ {
+ var controller = new PreviewPrintController();
+ controller.OnEndPrint(document, e);
+ controller.OnEndPrint(null, e);
+ }
+ }
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using Xunit;
+
+namespace System.Drawing.Printing.Tests
+{
+ public class PrintControllerTests
+ {
+ [Fact]
+ public void Ctor_Default()
+ {
+ var controller = new SubPrintController();
+ Assert.False(controller.IsPreview);
+ }
+
+ [ConditionalFact(Helpers.AnyInstalledPrinters, Helpers.IsDrawingSupported)]
+ public void OnStartPage_InvokeWithPrint_ReturnsNull()
+ {
+ using (var document = new PrintDocument())
+ {
+ var controller = new SubPrintController();
+ controller.OnStartPrint(document, new PrintEventArgs());
+
+ var printEventArgs = new PrintPageEventArgs(null, Rectangle.Empty, Rectangle.Empty, null);
+ Assert.Null(controller.OnStartPage(document, printEventArgs));
+
+ // Call OnEndPage.
+ controller.OnEndPage(document, printEventArgs);
+
+ // Call EndPrint.
+ controller.OnEndPrint(document, new PrintEventArgs());
+ }
+ }
+
+ [Fact]
+ public void OnStartPage_Invoke_ReturnsNull()
+ {
+ using (var document = new PrintDocument())
+ {
+ var controller = new SubPrintController();
+ Assert.Null(controller.OnStartPage(document, new PrintPageEventArgs(null, Rectangle.Empty, Rectangle.Empty, null)));
+ Assert.Null(controller.OnStartPage(null, null));
+ }
+ }
+
+ [Fact]
+ public void OnEndPage_InvokeWithoutStarting_Nop()
+ {
+ using (var document = new PrintDocument())
+ {
+ var controller = new SubPrintController();
+ controller.OnEndPage(document, new PrintPageEventArgs(null, Rectangle.Empty, Rectangle.Empty, null));
+ controller.OnEndPage(null, null);
+ }
+ }
+
+ public static IEnumerable<object[]> PrintEventArgs_TestData()
+ {
+ yield return new object[] { null };
+ yield return new object[] { new PrintEventArgs() };
+ }
+
+ [ConditionalTheory(Helpers.IsDrawingSupported)]
+ [MemberData(nameof(PrintEventArgs_TestData))]
+ public void OnStartPrint_InvokeWithDocument_Success(PrintEventArgs e)
+ {
+ using (var document = new PrintDocument())
+ {
+ var controller = new SubPrintController();
+ controller.OnStartPrint(document, e);
+
+ // Call OnEndPrint
+ controller.OnEndPrint(document, e);
+ }
+ }
+
+ [ConditionalTheory(Helpers.IsDrawingSupported)]
+ [MemberData(nameof(PrintEventArgs_TestData))]
+ public void OnStartPrint_InvokeWithDocumentSeveralTimes_Success(PrintEventArgs e)
+ {
+ using (var document = new PrintDocument())
+ {
+ var controller = new SubPrintController();
+ controller.OnStartPrint(document, e);
+ controller.OnStartPrint(document, e);
+
+ // Call OnEndPrint
+ controller.OnEndPrint(document, e);
+ }
+ }
+
+ [Fact]
+ [PlatformSpecific(TestPlatforms.Windows)] // In Unix is a no-op
+ public void OnStartPrint_InvokeNullDocument_ThrowsNullReferenceException()
+ {
+ var controller = new SubPrintController();
+ Assert.Throws<NullReferenceException>(() => controller.OnStartPrint(null, new PrintEventArgs()));
+ }
+
+ [Theory]
+ [MemberData(nameof(PrintEventArgs_TestData))]
+ public void OnEndPrint_InvokeWithoutStarting_Nop(PrintEventArgs e)
+ {
+ using (var document = new PrintDocument())
+ {
+ var controller = new SubPrintController();
+ controller.OnEndPrint(document, e);
+ controller.OnEndPrint(null, e);
+ }
+ }
+
+ private class SubPrintController : PrintController
+ {
+ }
+ }
+}
<Compile Include="Imaging\ImageFormatTests.cs" />
<Compile Include="Imaging\MetaHeaderTests.cs" />
<Compile Include="Imaging\WmfPlaceableFileHeaderTests.cs" />
+ <Compile Include="Printing\PrintControllerTests.cs" />
<Compile Include="Printing\PrintDocumentTests.cs" />
<Compile Include="Printing\PrinterSettingsTests.cs" />
+ <Compile Include="Printing\PreviewPrintControllerTests.cs" />
<Compile Include="RegionTests.cs" />
<Compile Include="SolidBrushTests.cs" />
<Compile Include="StringFormatTests.cs" />