PrinterSettings.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / whidbey / REDBITS / ndp / fx / src / CommonUI / System / Drawing / Printing / PrinterSettings.cs / 1 / PrinterSettings.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Drawing.Printing { 
    using System.Runtime.Serialization.Formatters; 
    using System.Configuration.Assemblies;
    using System.Runtime.InteropServices; 
    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis;
    using System;
    using System.IO; 
    using System.Security;
    using System.Security.Permissions; 
    using System.Collections; 
    using System.Collections.Specialized;
    using System.Drawing; 
    using System.Drawing.Internal;
    using System.Drawing.Imaging;
    using System.ComponentModel;
    using Microsoft.Win32; 
    using System.Globalization;
 
    ///  
    /// 
    ///    Information about how a document should be printed, including which printer 
    ///    to print it on.
    /// 
    [Serializable]
    public class PrinterSettings : ICloneable { 
        // All read/write data is stored in managed code, and whenever we need to call Win32,
        // we create new DEVMODE and DEVNAMES structures.  We don't store device capabilities, 
        // though. 
        //
        // Also, all properties have hidden tri-state logic -- yes/no/default 
        private const int PADDING_IA64 = 4;

        private string printerName; // default printer.
        private string driverName = ""; 
        private string outputPort = "";
        private bool printToFile; 
 
        // Whether the PrintDialog has been shown (not whether it's currently shown).  This is how we enforce SafePrinting.
        private bool printDialogDisplayed; 

        private short extrabytes;
        private byte[] extrainfo;
 
        private short copies = -1;
        private Duplex duplex = System.Drawing.Printing.Duplex.Default; 
        private TriState collate = TriState.Default; 
        private PageSettings defaultPageSettings;
        private int fromPage; 
        private int toPage;
        private int maxPage = 9999;
        private int minPage;
        private PrintRange printRange; 

        private short  devmodebytes; 
        private byte[] cachedDevmode; 

        ///  
        /// 
        ///    
        ///       Initializes a new instance of the  class.
        ///     
        /// 
        public PrinterSettings() { 
            defaultPageSettings = new PageSettings(this); 
        }
 
        /// 
        /// 
        ///    
        ///       Gets a value indicating whether the printer supports duplex (double-sided) printing. 
        ///    
        ///  
        public bool CanDuplex { 
            get { return DeviceCapabilities(SafeNativeMethods.DC_DUPLEX, IntPtr.Zero, 0) == 1;}
        } 

        /// 
        /// 
        ///     
        ///       Gets or sets the number of copies to print.
        ///     
        ///  
        public short Copies {
            get { 
                if (copies != -1)
                    return copies;
                else
                    return GetModeField(ModeField.Copies, 1); 
            }
            set { 
                if (value < 0) 
                    throw new ArgumentException(SR.GetString(SR.InvalidLowBoundArgumentEx,
                                                             "value", value.ToString(CultureInfo.CurrentCulture), 
                                                             (0).ToString(CultureInfo.CurrentCulture)));
                /*
                We shouldnt allow copies to be set since the copies can be a large number
                and can be reflected in PrintDialog. So for the Copies property, 
                we prefer that for SafePrinting, copied cannot be set programmatically
                but through the print dialog. 
                Any lower security could set copies to anything. Vs Whidbey 93475*/ 
                IntSecurity.SafePrinting.Demand();
                copies = value; 
            }
        }

        ///  
        /// 
        ///     
        ///       Gets or sets 
        ///       a value indicating whether the print out is collated.
        ///     
        /// 
        public bool Collate {
            get {
                if (!collate.IsDefault) 
                    return(bool) collate;
                else 
                    return GetModeField(ModeField.Collate, SafeNativeMethods.DMCOLLATE_FALSE) == SafeNativeMethods.DMCOLLATE_TRUE; 
            }
            set { collate = value;} 
        }

        /// 
        ///  
        ///    
        ///       Gets the default page settings for this printer. 
        ///     
        /// 
        public PageSettings DefaultPageSettings { 
            get { return defaultPageSettings;}
        }

        // As far as I can tell, Windows no longer pays attention to driver names and output ports. 
        // But I'm leaving this code in place in case I'm wrong.
        internal string DriverName { 
            get { return driverName;} 
            // set { driverName = value;}
        } 

        /* // No point in having a driver version if you can't get the driver name
        /// 
        ///     
        ///       Gets the printer driver version number.
        ///     
        ///  
        /// 
        ///     
        ///       The printer driver version number.
        ///    
        /// 
        public int DriverVersion { 
            get { return DeviceCapabilities(SafeNativeMethods.DC_DRIVER, 0, -1);}
        } 
        */ 

        ///  
        /// 
        ///    
        ///       Gets or sets the printer's duplex setting.
        ///     
        /// 
        public Duplex Duplex { 
            get { 
                if (duplex != Duplex.Default)
                    return duplex; 
                else
                    return(Duplex) GetModeField(ModeField.Duplex, SafeNativeMethods.DMDUP_SIMPLEX);
            }
            set { 
                //valid values are 0xffffffff to 0x3
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)Duplex.Default, (int)Duplex.Horizontal)) 
                { 
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(Duplex));
                } 
                duplex = value;
            }
        }
 
        /// 
        ///  
        ///    Gets or sets the first page to print. 
        /// 
        public int FromPage { 
            get { return fromPage;}
            set {
                if (value < 0)
                    throw new ArgumentException(SR.GetString(SR.InvalidLowBoundArgumentEx, 
                                                             "value", value.ToString(CultureInfo.CurrentCulture),
                                                             (0).ToString(CultureInfo.CurrentCulture))); 
                fromPage = value; 
            }
        } 



        ///  
        /// 
        ///     
        ///       Gets the names of all printers installed on the machine. 
        ///    
        ///  
        public static StringCollection InstalledPrinters {
            get {
                IntSecurity.AllPrinting.Demand();
 
                int returnCode;
                int bufferSize; 
                int count; 
                int level, sizeofstruct;
                // Note: Level 5 doesn't seem to work properly on NT platforms 
                // (atleast the call to get the size of the buffer reqd.),
                // and Level 4 doesn't work on Win9x.
                //
                if (Environment.OSVersion.Platform == System.PlatformID.Win32NT) { 
                    level = 4;
                    // PRINTER_INFO_4 are 12 bytes in size 
                    if (IntPtr.Size == 8) { 
                        sizeofstruct = (IntPtr.Size * 2) + (Marshal.SizeOf(typeof(int)) * 1) + PADDING_IA64;
                    } 
                    else {
                        sizeofstruct = (IntPtr.Size * 2) + (Marshal.SizeOf(typeof(int)) * 1);
                    }
                } 
                else {
                    level = 5; 
                    // PRINTER_INFO_5 are 20 bytes in size 
                    sizeofstruct = (IntPtr.Size * 2) + (Marshal.SizeOf(typeof(int)) * 3);
                } 
                string[] array;

                IntSecurity.UnmanagedCode.Assert();
                try { 
                    SafeNativeMethods.EnumPrinters(SafeNativeMethods.PRINTER_ENUM_LOCAL | SafeNativeMethods.PRINTER_ENUM_CONNECTIONS, null, level, IntPtr.Zero, 0, out bufferSize, out count);
 
                    IntPtr buffer = Marshal.AllocCoTaskMem(bufferSize); 
                    returnCode = SafeNativeMethods.EnumPrinters(SafeNativeMethods.PRINTER_ENUM_LOCAL | SafeNativeMethods.PRINTER_ENUM_CONNECTIONS,
                                                            null, level, buffer, 
                                                            bufferSize, out bufferSize, out count);
                    array = new string[count];

                    if (returnCode == 0) { 
                        Marshal.FreeCoTaskMem(buffer);
                        throw new Win32Exception(); 
                    } 

                    for (int i = 0; i < count; i++) { 
                        // The printer name is at offset 0
                        //
                        IntPtr namePointer = (IntPtr) Marshal.ReadIntPtr((IntPtr)((long)buffer + i * sizeofstruct));
                        array[i] = Marshal.PtrToStringAuto(namePointer); 
                    }
 
                    Marshal.FreeCoTaskMem(buffer); 
                }
                finally { 
                    CodeAccessPermission.RevertAssert();
                }

                return new StringCollection(array); 
            }
        } 
 
        /// 
        ///  
        ///    
        ///       Gets a value indicating whether the 
        ///       property designates the default printer.
        ///     
        /// 
        public bool IsDefaultPrinter { 
            get { 
                return (printerName == null || printerName == GetDefaultPrinterName());
            } 
        }

        /// 
        ///  
        ///    
        ///       Gets a value indicating whether the printer is a plotter, as opposed to a raster printer. 
        ///     
        /// 
        public bool IsPlotter { 
            get {
                return GetDeviceCaps(SafeNativeMethods.TECHNOLOGY, SafeNativeMethods.DT_RASPRINTER) == SafeNativeMethods.DT_PLOTTER;
            }
        } 

        ///  
        ///  
        ///    
        ///       Gets a value indicating whether the  
        ///       property designates a valid printer.
        ///    
        /// 
        public bool IsValid { 
            get {
                return DeviceCapabilities(SafeNativeMethods.DC_COPIES, IntPtr.Zero, -1) != -1; 
            } 
        }
 
        /// 
        /// 
        ///    
        ///       Gets the angle, in degrees, which the portrait orientation is rotated 
        ///       to produce the landscape orientation.
        ///     
        ///  
        public int LandscapeAngle {
            get { return DeviceCapabilities(SafeNativeMethods.DC_ORIENTATION, IntPtr.Zero, 0);} 
        }

        /// 
        ///  
        ///    
        ///       Gets the maximum number of copies allowed by the printer. 
        ///     
        /// 
        public int MaximumCopies { 
            get { return DeviceCapabilities(SafeNativeMethods.DC_COPIES, IntPtr.Zero, 1);}
        }

        ///  
        /// 
        ///     
        ///       Gets or sets the highest  or  
        ///       which may be selected in a print dialog box.
        ///     
        /// 
        public int MaximumPage {
            get { return maxPage;}
            set { 
                if (value < 0)
                    throw new ArgumentException(SR.GetString(SR.InvalidLowBoundArgumentEx, 
                                                             "value", value.ToString(CultureInfo.CurrentCulture), 
                                                             (0).ToString(CultureInfo.CurrentCulture)));
                maxPage = value; 
            }

        }
 
        /// 
        ///  
        /// Gets or sets the lowest  or  
        /// which may be selected in a print dialog box.
        ///  
        public int MinimumPage {
            get { return minPage;}
            set {
                if (value < 0) 
                    throw new ArgumentException(SR.GetString(SR.InvalidLowBoundArgumentEx,
                                                             "value", value.ToString(CultureInfo.CurrentCulture), 
                                                             (0).ToString(CultureInfo.CurrentCulture))); 
                minPage = value;
            } 
        }

        internal string OutputPort {
            get { 
                return outputPort;
                } 
            set { 
                outputPort = value;
                } 
        }

        /// 
        ///  
        ///    
        ///       Indicates the name of the printerfile. 
        ///     
        /// 
        public string PrintFileName { 
            get {
                string printFileName = OutputPort;
                if (!string.IsNullOrEmpty(printFileName))
                { 
                	IntSecurity.DemandReadFileIO(printFileName);
                } 
                return printFileName; 
            }
            set { 
                if (string.IsNullOrEmpty(value))
                {
                    throw new ArgumentNullException(value);
                } 
                IntSecurity.DemandWriteFileIO(value);
                OutputPort = value; 
            } 
        }
 
        /// 
        /// 
        ///    
        ///       Gets the paper sizes supported by this printer. 
        ///    
        ///  
        public PaperSizeCollection PaperSizes { 
            get { return new PaperSizeCollection(Get_PaperSizes());}
        } 

        /// 
        /// 
        ///     
        ///       Gets the paper sources available on this printer.
        ///     
        ///  
        public PaperSourceCollection PaperSources {
            get { return new PaperSourceCollection(Get_PaperSources());} 
        }

        /// 
        ///     
        ///        Whether the print dialog has been displayed.  In SafePrinting mode,
        ///        a print dialog is required to print.  After printing, 
        ///        this property is set to false if the program does not have AllPrinting; 
        ///        this guarantees a document is only printed once each time the print dialog is shown.
        ///     
        /// 
        internal bool PrintDialogDisplayed {
            //
 

            get { 
                // no security check 

                return printDialogDisplayed; 
            }

            set {
                IntSecurity.AllPrinting.Demand(); 
                printDialogDisplayed = value;
            } 
        } 

        ///  
        /// 
        ///    
        ///       Gets or sets the pages the user has asked to print.
        ///  
        public PrintRange PrintRange {
            get { return printRange;} 
            [SuppressMessage("Microsoft.Performance", "CA1803:AvoidCostlyCallsWherePossible")] 
            set {
                if (!Enum.IsDefined(typeof(PrintRange), value)) 
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(PrintRange));

                printRange = value;
            } 
        }
 
        ///  
        /// 
        ///       Indicates whether to print to a file instead of a port. 
        /// 
        public bool PrintToFile {
            get {
                return printToFile; 
            }
            set { 
                printToFile = value; 
            }
        } 

        /// 
        /// 
        ///     
        ///       Gets or sets the name of the printer.
        ///     
        ///  
        public string PrinterName {
            get { 
                IntSecurity.AllPrinting.Demand();
                return PrinterNameInternal;
            }
 
            set {
                IntSecurity.AllPrinting.Demand(); 
                PrinterNameInternal = value; 
            }
        } 

        private string PrinterNameInternal {
            get {
                if (printerName == null) 
                    return GetDefaultPrinterName();
                else 
                    return printerName; 
            }
            set { 
                // Reset the DevMode and Extrabytes...
                cachedDevmode = null;
                extrainfo = null;
                printerName = value; 
                // VsWhidbey : 235920: PrinterName can be set through a fulltrusted assembly without using  the PrintDialog.
                // So dont set this variable here. 
                //PrintDialogDisplayed = true; 
            }
        } 

        /// 
        /// 
        ///     
        ///       Gets the resolutions supported by this printer.
        ///     
        ///  
        public PrinterResolutionCollection PrinterResolutions {
            get { return new PrinterResolutionCollection(Get_PrinterResolutions());} 
        }

        /// 
        ///  
        ///     If the image is a JPEG or a PNG (Image.RawFormat) and the printer returns true
        ///     from ExtEscape(CHECKJPEGFORMAT) or ExtEscape(CHECKPNGFORMAT) then this function returns true. 
        ///  
        [SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals")]
        public bool IsDirectPrintingSupported(ImageFormat imageFormat) { 
            bool isDirectPrintingSupported = false;
            if (imageFormat.Equals(ImageFormat.Jpeg) || imageFormat.Equals(ImageFormat.Png)) {
               int nEscape = imageFormat.Equals(ImageFormat.Jpeg) ? SafeNativeMethods.CHECKJPEGFORMAT : SafeNativeMethods.CHECKPNGFORMAT;
               int outData = 0; 
               DeviceContext dc = CreateInformationContext(DefaultPageSettings);
               HandleRef hdc = new HandleRef(dc, dc.Hdc); 
               try { 
                isDirectPrintingSupported = SafeNativeMethods.ExtEscape(hdc, SafeNativeMethods.QUERYESCSUPPORT, Marshal.SizeOf(typeof(int)), ref nEscape, 0, out outData) > 0;
               } 
               finally {
                dc.Dispose();
               }
            } 
            return isDirectPrintingSupported;
 
        } 

        ///  
        /// 
        ///    
        /// This method utilizes the CHECKJPEGFORMAT/CHECKPNGFORMAT printer escape functions
        /// to determine whether the printer can handle a JPEG image. 
        /// See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/prntspol_51ys.asp
        /// for more information on this printer escape function. 
        /// 
        /// If the image is a JPEG or a PNG (Image.RawFormat) and the printer returns true
        /// from ExtEscape(CHECKJPEGFORMAT) or ExtEscape(CHECKPNGFORMAT) then this function returns true. 
        ///    
        /// 
        public bool IsDirectPrintingSupported(Image image) {
            bool isDirectPrintingSupported = false; 
            if (image.RawFormat.Equals(ImageFormat.Jpeg) || image.RawFormat.Equals(ImageFormat.Png)) {
                MemoryStream stream = new MemoryStream(); 
                try { 
                    image.Save(stream, image.RawFormat);
                    stream.Position = 0; 
                    using (BufferedStream inStream = new BufferedStream(stream)) {
                        int pvImageLen = (int)inStream.Length;
                        byte[] pvImage = new byte[pvImageLen];
 
                        int nRead = inStream.Read(pvImage, 0, (int)pvImageLen);
 
                        int nEscape = image.RawFormat.Equals(ImageFormat.Jpeg) ? SafeNativeMethods.CHECKJPEGFORMAT : SafeNativeMethods.CHECKPNGFORMAT; 
                        int outData = 0;
 
                        DeviceContext dc = CreateInformationContext(DefaultPageSettings);
                        HandleRef hdc = new HandleRef(dc, dc.Hdc);
                        try {
                            bool querySupported = SafeNativeMethods.ExtEscape(hdc, SafeNativeMethods.QUERYESCSUPPORT, Marshal.SizeOf(typeof(int)), ref nEscape, 0, out outData) > 0; 
                            if (querySupported) {
                                isDirectPrintingSupported = (SafeNativeMethods.ExtEscape(hdc, nEscape, pvImageLen, pvImage, Marshal.SizeOf(typeof(int)), out outData) > 0) 
                                                            && (outData == 1); 
                            }
                        } 
                        finally {
                            dc.Dispose();
                        }
                    } 
                }
                finally { 
                    stream.Close(); 
                }
            } 
            return isDirectPrintingSupported;
        }

        ///  
        /// 
        ///     
        ///       Gets a 
        ///       value indicating whether the printer supports color printing.
        ///     
        /// 
        public bool SupportsColor {
            get {
                // 

                return GetDeviceCaps(SafeNativeMethods.BITSPIXEL, 1) > 1; 
            } 
        }
 
        /// 
        /// 
        ///    Gets or sets the last page to print.
        ///  
        public int ToPage {
            get { return toPage;} 
            set { 
                if (value < 0)
                    throw new ArgumentException(SR.GetString(SR.InvalidLowBoundArgumentEx, 
                                                             "value", value.ToString(CultureInfo.CurrentCulture),
                                                             (0).ToString(CultureInfo.CurrentCulture)));
                toPage = value;
            } 
        }
 
        ///  
        /// 
        ///     
        ///       Creates an identical copy of this object.
        ///    
        /// 
        public object Clone() { 
            PrinterSettings clone = (PrinterSettings) MemberwiseClone();
            clone.printDialogDisplayed = false; 
            return clone; 
        }
 
        [SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts")] // what is done in copytohdevmode cannot give unwanted access AllPrinting permission
        internal DeviceContext CreateDeviceContext(PageSettings pageSettings) {
            IntPtr modeHandle = GetHdevmodeInternal();
            DeviceContext dc  = null; 

            try { 
                //Copy the PageSettings to the DEVMODE... 
                //Assert permission as CopyToHdevmode() demands...
                IntSecurity.AllPrinting.Assert(); 
                try
                {
                    pageSettings.CopyToHdevmode(modeHandle);
                } 
                finally
                { 
                    CodeAccessPermission.RevertAssert(); 
                }
                dc = CreateDeviceContext(modeHandle); 
            }
            finally {
                SafeNativeMethods.GlobalFree(new HandleRef(null, modeHandle));
            } 
            return dc;
        } 
 
        internal DeviceContext CreateDeviceContext(IntPtr hdevmode) {
            IntPtr modePointer = SafeNativeMethods.GlobalLock(new HandleRef(null, hdevmode)); 
            DeviceContext dc = DeviceContext.CreateDC(DriverName, PrinterNameInternal, (string) null, new HandleRef(null, modePointer));
            SafeNativeMethods.GlobalUnlock(new HandleRef(null, hdevmode));
            return dc;
        } 

        // A read-only DC, which is faster than CreateHdc 
        [SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts")] // what is done in copytohdevmode cannot give unwanted access AllPrinting permission 
        internal DeviceContext CreateInformationContext(PageSettings pageSettings) {
            IntPtr modeHandle = GetHdevmodeInternal(); 
            DeviceContext dc;

            try {
                //Copy the PageSettings to the DEVMODE... 
                //Assert permission as CopyToHdevmode() demands...
                IntSecurity.AllPrinting.Assert(); 
                try 
                {
                    pageSettings.CopyToHdevmode(modeHandle); 
                }
                finally
                {
                    CodeAccessPermission.RevertAssert(); 
                }
                dc = CreateInformationContext(modeHandle); 
            } 
            finally {
                SafeNativeMethods.GlobalFree(new HandleRef(null, 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)); 
            DeviceContext dc = DeviceContext.CreateIC(DriverName, PrinterNameInternal, (string) null, new HandleRef(null, modePointer));
            SafeNativeMethods.GlobalUnlock(new HandleRef(null, hdevmode)); 
            return dc;
        }

        ///  
        public Graphics CreateMeasurementGraphics() {
            return CreateMeasurementGraphics(DefaultPageSettings); 
        } 

        ///  
        [SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts")] //whatever the call stack calling HardMarginX and HardMarginY here is safe
        public Graphics CreateMeasurementGraphics(bool honorOriginAtMargins) {
            Graphics g = CreateMeasurementGraphics();
            if (g != null && honorOriginAtMargins) { 
                IntSecurity.AllPrintingAndUnmanagedCode.Assert();
                try 
                { 
                    g.TranslateTransform(-defaultPageSettings.HardMarginX, -defaultPageSettings.HardMarginY);
                } 
                finally
                {
                    CodeAccessPermission.RevertAssert();
                } 
                g.TranslateTransform(defaultPageSettings.Margins.Left, defaultPageSettings.Margins.Top);
            } 
            return g; 
        }
 
        /// 
        public Graphics CreateMeasurementGraphics(PageSettings pageSettings) {
            // returns the Graphics object for the printer
            DeviceContext dc = CreateDeviceContext(pageSettings); 
            Graphics g = Graphics.FromHdcInternal(dc.Hdc);
            g.PrintingHelper = dc; // Graphics will dispose of the DeviceContext. 
            return g; 
        }
 
        /// 
        [SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts")] //whatever the call stack calling HardMarginX and HardMarginY here is safe
        public Graphics CreateMeasurementGraphics(PageSettings pageSettings, bool honorOriginAtMargins) {
            Graphics g = CreateMeasurementGraphics(); 
            if (g != null && honorOriginAtMargins) {
                IntSecurity.AllPrintingAndUnmanagedCode.Assert(); 
                try 
                {
                    g.TranslateTransform(-pageSettings.HardMarginX, -pageSettings.HardMarginY); 
                }
                finally
                {
                    CodeAccessPermission.RevertAssert(); 
                }
                g.TranslateTransform(pageSettings.Margins.Left, pageSettings.Margins.Top); 
            } 
            return g;
        } 


        // Create a PRINTDLG with a few useful defaults.
        // Try to keep this consistent with PrintDialog.CreatePRINTDLG. 
        private static SafeNativeMethods.PRINTDLGX86 CreatePRINTDLGX86() {
                SafeNativeMethods.PRINTDLGX86 data = new SafeNativeMethods.PRINTDLGX86(); 
                data.lStructSize = Marshal.SizeOf(typeof(SafeNativeMethods.PRINTDLGX86)); 
                data.hwndOwner = IntPtr.Zero;
                data.hDevMode = IntPtr.Zero; 
                data.hDevNames = IntPtr.Zero;
                data.Flags = 0;
                data.hwndOwner = IntPtr.Zero;
                data.hDC = IntPtr.Zero; 
                data.nFromPage = 1;
                data.nToPage = 1; 
                data.nMinPage = 0; 
                data.nMaxPage = 9999;
                data.nCopies = 1; 
                data.hInstance = IntPtr.Zero;
                data.lCustData = IntPtr.Zero;
                data.lpfnPrintHook = IntPtr.Zero;
                data.lpfnSetupHook = IntPtr.Zero; 
                data.lpPrintTemplateName = null;
                data.lpSetupTemplateName = null; 
                data.hPrintTemplate = IntPtr.Zero; 
                data.hSetupTemplate = IntPtr.Zero;
                return data; 
        }


        // Create a PRINTDLG with a few useful defaults. 
        // Try to keep this consistent with PrintDialog.CreatePRINTDLG.
        private static SafeNativeMethods.PRINTDLG CreatePRINTDLG() { 
                SafeNativeMethods.PRINTDLG data = new SafeNativeMethods.PRINTDLG(); 
                data.lStructSize = Marshal.SizeOf(typeof(SafeNativeMethods.PRINTDLG));
                data.hwndOwner = IntPtr.Zero; 
                data.hDevMode = IntPtr.Zero;
                data.hDevNames = IntPtr.Zero;
                data.Flags = 0;
                data.hwndOwner = IntPtr.Zero; 
                data.hDC = IntPtr.Zero;
                data.nFromPage = 1; 
                data.nToPage = 1; 
                data.nMinPage = 0;
                data.nMaxPage = 9999; 
                data.nCopies = 1;
                data.hInstance = IntPtr.Zero;
                data.lCustData = IntPtr.Zero;
                data.lpfnPrintHook = IntPtr.Zero; 
                data.lpfnSetupHook = IntPtr.Zero;
                data.lpPrintTemplateName = null; 
                data.lpSetupTemplateName = null; 
                data.hPrintTemplate = IntPtr.Zero;
                data.hSetupTemplate = IntPtr.Zero; 
                return data;
        }

        //  Use FastDeviceCapabilities where possible -- computing PrinterName is quite slow 
        private int DeviceCapabilities(short capability, IntPtr pointerToBuffer, int defaultValue) {
            IntSecurity.AllPrinting.Assert(); 
            string printerName = PrinterName; 
            CodeAccessPermission.RevertAssert();
 
            IntSecurity.UnmanagedCode.Assert();

            return FastDeviceCapabilities(capability, pointerToBuffer, defaultValue, printerName);
        } 

        // We pass PrinterName in as a parameter rather than computing it ourselves because it's expensive to compute. 
        // We need to pass IntPtr.Zero since passing HDevMode is non-performant. 
        private static int FastDeviceCapabilities(short capability, IntPtr pointerToBuffer, int defaultValue, string printerName) {
            int result = SafeNativeMethods.DeviceCapabilities(printerName, GetOutputPort(), 
                                                          capability, pointerToBuffer, IntPtr.Zero);
            if (result == -1)
                return defaultValue;
            return result; 
        }
 
        // Called by get_PrinterName 
        private static string GetDefaultPrinterName() {
            IntSecurity.UnmanagedCode.Assert(); 
            if (IntPtr.Size == 8)
            {
                SafeNativeMethods.PRINTDLG data = CreatePRINTDLG();
                data.Flags = SafeNativeMethods.PD_RETURNDEFAULT; 
                bool status = SafeNativeMethods.PrintDlg(data);
 
                if (!status) 
                    return SR.GetString(SR.NoDefaultPrinter);
 
                IntPtr handle = data.hDevNames;
                IntPtr names = SafeNativeMethods.GlobalLock(new HandleRef(data, handle));
                if (names == IntPtr.Zero)
                    throw new Win32Exception(); 

                string name = ReadOneDEVNAME(names, 1); 
                SafeNativeMethods.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));
 
                return name;
            } 
            else { 
                SafeNativeMethods.PRINTDLGX86 data = CreatePRINTDLGX86();
                data.Flags = SafeNativeMethods.PD_RETURNDEFAULT; 
                bool status = SafeNativeMethods.PrintDlg(data);

                if (!status)
                return SR.GetString(SR.NoDefaultPrinter); 

                IntPtr handle = data.hDevNames; 
                IntPtr names = SafeNativeMethods.GlobalLock(new HandleRef(data, handle)); 
                if (names == IntPtr.Zero)
                    throw new Win32Exception(); 

                string name = ReadOneDEVNAME(names, 1);
                SafeNativeMethods.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));
 
                return name;
            }
        }
 

        // Called by get_OutputPort 
        private static string GetOutputPort() { 
            IntSecurity.UnmanagedCode.Assert();
 
            if (IntPtr.Size == 8)
            {
                SafeNativeMethods.PRINTDLG data = CreatePRINTDLG();
                data.Flags = SafeNativeMethods.PD_RETURNDEFAULT; 
                bool status = SafeNativeMethods.PrintDlg(data);
                if (!status) 
                    return SR.GetString(SR.NoDefaultPrinter); 

                IntPtr handle = data.hDevNames; 
                IntPtr names = SafeNativeMethods.GlobalLock(new HandleRef(data, handle));
                if (names == IntPtr.Zero)
                    throw new Win32Exception();
 
                string name = ReadOneDEVNAME(names, 2);
 
                SafeNativeMethods.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));
 
                return name;
            } 
            else { 
                SafeNativeMethods.PRINTDLGX86 data = CreatePRINTDLGX86();
                data.Flags = SafeNativeMethods.PD_RETURNDEFAULT; 
                bool status = SafeNativeMethods.PrintDlg(data);

                if (!status)
                    return SR.GetString(SR.NoDefaultPrinter); 

                IntPtr handle = data.hDevNames; 
                IntPtr names = SafeNativeMethods.GlobalLock(new HandleRef(data, handle)); 
                if (names == IntPtr.Zero)
                    throw new Win32Exception(); 

                string name = ReadOneDEVNAME(names, 2);

                SafeNativeMethods.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)); 

                return name;
            }
 
        }
 
        private int GetDeviceCaps(int capability, int defaultValue) { 
            DeviceContext dc = CreateInformationContext(DefaultPageSettings);
            int result = defaultValue; 

            try {
                result = UnsafeNativeMethods.GetDeviceCaps(new HandleRef(dc, dc.Hdc), capability);
            } 
            catch (InvalidPrinterException) {
                // do nothing, will return defaultValue. 
            } 
            finally{
                dc.Dispose(); 
            }

            return result;
        } 

        ///  
        ///  
        ///    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);
        ///       Where "handle" is the return value from this method.
        /// 
        public IntPtr GetHdevmode() { 
            IntSecurity.AllPrintingAndUnmanagedCode.Demand();
            // Don't assert unmanaged code -- anyone using handles should have unmanaged code permission 
            IntPtr modeHandle =  GetHdevmodeInternal(); 
            defaultPageSettings.CopyToHdevmode(modeHandle);
            return modeHandle; 
        }

        internal IntPtr GetHdevmodeInternal() {
            // getting the printer name is quite expensive if PrinterName is left default, 
            // because it needs to figure out what the default printer is
            string printerName = PrinterNameInternal; 
 
            // Create DEVMODE
            int modeSize = SafeNativeMethods.DocumentProperties(NativeMethods.NullHandleRef, NativeMethods.NullHandleRef, printerName, IntPtr.Zero, NativeMethods.NullHandleRef, 0); 
            if (modeSize < 1) {
                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));
 
            //Get the DevMode only if its not cached.... 
            if (cachedDevmode != null) {
                Marshal.Copy(cachedDevmode, 0, pointer, devmodebytes); 
            }
            else {
                int returnCode = SafeNativeMethods.DocumentProperties(NativeMethods.NullHandleRef, NativeMethods.NullHandleRef, printerName, pointer, NativeMethods.NullHandleRef, SafeNativeMethods.DM_OUT_BUFFER);
                if (returnCode < 0) { 
                    throw new Win32Exception();
                } 
            } 

            SafeNativeMethods.DEVMODE mode = (SafeNativeMethods.DEVMODE) UnsafeNativeMethods.PtrToStructure(pointer, typeof(SafeNativeMethods.DEVMODE)); 

            IntPtr pointeroffset = (IntPtr)((long)pointer + (long)mode.dmSize);
            if (extrainfo != null)
                Marshal.Copy(extrainfo,0, pointeroffset, extrabytes); 
            if ((mode.dmFields & SafeNativeMethods.DM_COPIES) == SafeNativeMethods.DM_COPIES)
            { 
                if (copies != -1) mode.dmCopies = copies; 
            }
 
            if ((mode.dmFields & SafeNativeMethods.DM_DUPLEX) == SafeNativeMethods.DM_DUPLEX)
            {
                if ((int)duplex != -1) mode.dmDuplex = (short) duplex;
            } 

            if ((mode.dmFields & SafeNativeMethods.DM_COLLATE) == SafeNativeMethods.DM_COLLATE) 
            { 
                if (collate.IsNotDefault)
                    mode.dmCollate = (short) (((bool) collate) ? SafeNativeMethods.DMCOLLATE_TRUE : SafeNativeMethods.DMCOLLATE_FALSE); 
            }

            Marshal.StructureToPtr(mode, pointer, false);
 
            int retCode = SafeNativeMethods.DocumentProperties(NativeMethods.NullHandleRef, NativeMethods.NullHandleRef, printerName, 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));
                return IntPtr.Zero; 
            }


            SafeNativeMethods.GlobalUnlock(new HandleRef(null, handle)); 
            return handle;
        } 
 
        /// 
        ///  
        ///    
        ///       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);
        ///       Where "handle" is the return value from this method. 
        ///     
        /// 
        public IntPtr GetHdevmode(PageSettings pageSettings) { 
            IntSecurity.AllPrintingAndUnmanagedCode.Demand();
            // Don't assert unmanaged code -- anyone using handles should have unmanaged code permission
            IntPtr handle = GetHdevmodeInternal();
            pageSettings.CopyToHdevmode(handle); 
            return handle;
        } 
 
        /// 
        ///  
        ///    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);
        ///    Where "handle" is the return value from this method. 
        /// 
        public IntPtr GetHdevnames() { 
            IntSecurity.AllPrintingAndUnmanagedCode.Demand(); 
            // Don't assert unmanaged code -- anyone using handles should have unmanaged code permission
 
            string printerName = PrinterName; // the PrinterName property is slow when using the default printer

            // Create DEVNAMES structure
            // +4 for null terminator 
            int namesCharacters = 4 + printerName.Length + DriverName.Length + OutputPort.Length;
 
            // 8 = size of fixed portion of DEVNAMES 
            short offset = (short) (8 / Marshal.SystemDefaultCharSize); // Offsets are in characters, not bytes
            uint namesSize = (uint)(Marshal.SystemDefaultCharSize * (offset + namesCharacters)); // always >0 
            IntPtr handle = SafeNativeMethods.GlobalAlloc(SafeNativeMethods.GMEM_MOVEABLE, namesSize);
            IntPtr namesPointer = SafeNativeMethods.GlobalLock(new HandleRef(null, handle));

            Marshal.WriteInt16(namesPointer, offset); // wDriverOffset 
            offset += WriteOneDEVNAME(DriverName, namesPointer, offset);
            Marshal.WriteInt16((IntPtr)((long)namesPointer + 2), offset); // wDeviceOffset 
            offset += WriteOneDEVNAME(printerName, namesPointer, offset); 
            Marshal.WriteInt16((IntPtr)((long)namesPointer + 4), offset); // wOutputOffset
            offset += WriteOneDEVNAME(OutputPort, namesPointer, offset); 
            Marshal.WriteInt16((IntPtr)((long)namesPointer + 6), offset); // wDefault

            SafeNativeMethods.GlobalUnlock(new HandleRef(null, handle));
            return handle; 
        }
 
        // Handles creating then disposing a default DEVMODE 
        internal short GetModeField(ModeField field, short defaultValue) {
            return GetModeField(field, defaultValue, IntPtr.Zero); 
        }

        internal short GetModeField(ModeField field, short defaultValue, IntPtr modeHandle) {
            bool ownHandle = false; 
            short result;
            try { 
 
                if (modeHandle == IntPtr.Zero) {
                    try { 
                        modeHandle = GetHdevmodeInternal();
                        ownHandle = true;
                    }
                    catch (InvalidPrinterException) { 
                        return defaultValue;
                    } 
                } 

                IntPtr modePointer = SafeNativeMethods.GlobalLock(new HandleRef(this, modeHandle)); 
                SafeNativeMethods.DEVMODE mode = (SafeNativeMethods.DEVMODE) UnsafeNativeMethods.PtrToStructure(modePointer, typeof(SafeNativeMethods.DEVMODE));
                switch (field) {
                    case ModeField.Orientation: result = mode.dmOrientation; break;
                    case ModeField.PaperSize: result = mode.dmPaperSize; break; 
                    case ModeField.PaperLength: result = mode.dmPaperLength; break;
                    case ModeField.PaperWidth: result = mode.dmPaperWidth; break; 
                    case ModeField.Copies: result = mode.dmCopies; break; 
                    case ModeField.DefaultSource: result = mode.dmDefaultSource; break;
                    case ModeField.PrintQuality: result = mode.dmPrintQuality; break; 
                    case ModeField.Color: result = mode.dmColor; break;
                    case ModeField.Duplex: result = mode.dmDuplex; break;
                    case ModeField.YResolution: result = mode.dmYResolution; break;
                    case ModeField.TTOption: result = mode.dmTTOption; break; 
                    case ModeField.Collate: result = mode.dmCollate; break;
                    default: 
                        Debug.Fail("Invalid field in GetModeField"); 
                        result = defaultValue;
                        break; 
                }
                SafeNativeMethods.GlobalUnlock(new HandleRef(this, modeHandle));
            }
            finally 
            {
                if (ownHandle) { 
                    SafeNativeMethods.GlobalFree(new HandleRef(this, modeHandle)); 
                }
 
            }
            return result;
        }
 
        internal PaperSize[] Get_PaperSizes() {
            IntSecurity.AllPrintingAndUnmanagedCode.Assert(); 
 
            string printerName = PrinterName; //  this is quite expensive if PrinterName is left default
 
            int count = FastDeviceCapabilities(SafeNativeMethods.DC_PAPERNAMES, IntPtr.Zero, -1, printerName);
            if (count == -1)
                return new PaperSize[0];
            int stringSize = Marshal.SystemDefaultCharSize * 64; 
            IntPtr namesBuffer = Marshal.AllocCoTaskMem(stringSize * count);
            FastDeviceCapabilities(SafeNativeMethods.DC_PAPERNAMES, namesBuffer, -1, printerName); 
 
            Debug.Assert(FastDeviceCapabilities(SafeNativeMethods.DC_PAPERS, IntPtr.Zero, -1, printerName) == count,
                         "Not the same number of paper kinds as paper names?"); 
            IntPtr kindsBuffer = Marshal.AllocCoTaskMem(2 * count);
            FastDeviceCapabilities(SafeNativeMethods.DC_PAPERS, kindsBuffer, -1, printerName);

            Debug.Assert(FastDeviceCapabilities(SafeNativeMethods.DC_PAPERSIZE, IntPtr.Zero, -1, printerName) == count, 
                         "Not the same number of paper kinds as paper names?");
            IntPtr dimensionsBuffer = Marshal.AllocCoTaskMem(8 * count); 
            FastDeviceCapabilities(SafeNativeMethods.DC_PAPERSIZE, dimensionsBuffer, -1, printerName); 

            PaperSize[] result = new PaperSize[count]; 
            for (int i = 0; i < count; i++) {
                string name = Marshal.PtrToStringAuto((IntPtr)((long)namesBuffer + stringSize * i), 64);
                int index = name.IndexOf('\0');
                if (index > -1) { 
                    name = name.Substring(0, index);
                } 
                short kind = Marshal.ReadInt16((IntPtr)((long)kindsBuffer + i*2)); 
                int width = Marshal.ReadInt32((IntPtr)((long)dimensionsBuffer + i * 8));
                int height = Marshal.ReadInt32((IntPtr)((long)dimensionsBuffer + i * 8 + 4)); 
                result[i] = new PaperSize((PaperKind) kind, name,
                                          PrinterUnitConvert.Convert(width, PrinterUnit.TenthsOfAMillimeter, PrinterUnit.Display),
                                          PrinterUnitConvert.Convert(height, PrinterUnit.TenthsOfAMillimeter, PrinterUnit.Display));
            } 

            Marshal.FreeCoTaskMem(namesBuffer); 
            Marshal.FreeCoTaskMem(kindsBuffer); 
            Marshal.FreeCoTaskMem(dimensionsBuffer);
            return result; 
        }

        internal PaperSource[] Get_PaperSources() {
            IntSecurity.AllPrintingAndUnmanagedCode.Assert(); 

            string printerName = PrinterName; //  this is quite expensive if PrinterName is left default 
 
            int count = FastDeviceCapabilities(SafeNativeMethods.DC_BINNAMES, IntPtr.Zero, -1, printerName);
            if (count == -1) 
                return new PaperSource[0];

            // Contrary to documentation, DeviceCapabilities returns char[count, 24],
            // not char[count][24] 
            int stringSize = Marshal.SystemDefaultCharSize * 24;
            IntPtr namesBuffer = Marshal.AllocCoTaskMem(stringSize * count); 
            FastDeviceCapabilities(SafeNativeMethods.DC_BINNAMES, namesBuffer, -1, printerName); 

            Debug.Assert(FastDeviceCapabilities(SafeNativeMethods.DC_BINS, IntPtr.Zero, -1, printerName) == count, 
                         "Not the same number of bin kinds as bin names?");
            IntPtr kindsBuffer = Marshal.AllocCoTaskMem(2 * count);
            FastDeviceCapabilities(SafeNativeMethods.DC_BINS, kindsBuffer, -1, printerName);
 
            PaperSource[] result = new PaperSource[count];
            for (int i = 0; i < count; i++) { 
                string name = Marshal.PtrToStringAuto((IntPtr)((long)namesBuffer + stringSize * i)); 
                short kind = Marshal.ReadInt16((IntPtr)((long)kindsBuffer + 2*i));
                result[i] = new PaperSource((PaperSourceKind) kind, name); 
            }

            Marshal.FreeCoTaskMem(namesBuffer);
            Marshal.FreeCoTaskMem(kindsBuffer); 
            return result;
        } 
 
        internal PrinterResolution[] Get_PrinterResolutions() {
            IntSecurity.AllPrintingAndUnmanagedCode.Assert(); 

            string printerName = PrinterName; //  this is quite expensive if PrinterName is left default
            PrinterResolution[] result;
 
            int count = FastDeviceCapabilities(SafeNativeMethods.DC_ENUMRESOLUTIONS, IntPtr.Zero, -1, printerName);
            if (count == -1) { 
                //Just return the standrard values if custom resolutions absemt .... 
                result = new PrinterResolution[4];
                result[0] = new PrinterResolution(PrinterResolutionKind.High, -4, -1); 
                result[1] = new PrinterResolution(PrinterResolutionKind.Medium, -3, -1);
                result[2] = new PrinterResolution(PrinterResolutionKind.Low, -2, -1);
                result[3] = new PrinterResolution(PrinterResolutionKind.Draft, -1, -1);
 
                return result;
            } 
 
            result = new PrinterResolution[count + 4];
            result[0] = new PrinterResolution(PrinterResolutionKind.High, -4, -1); 
            result[1] = new PrinterResolution(PrinterResolutionKind.Medium, -3, -1);
            result[2] = new PrinterResolution(PrinterResolutionKind.Low, -2, -1);
            result[3] = new PrinterResolution(PrinterResolutionKind.Draft, -1, -1);
 
            IntPtr buffer = Marshal.AllocCoTaskMem(8 * count);
            FastDeviceCapabilities(SafeNativeMethods.DC_ENUMRESOLUTIONS, buffer, -1, printerName); 
 
            for (int i = 0; i < count; i++) {
                int x = Marshal.ReadInt32((IntPtr)((long)buffer + i*8)); 
                int y = Marshal.ReadInt32((IntPtr)((long)buffer + i*8 + 4));
                result[i + 4] = new PrinterResolution(PrinterResolutionKind.Custom, x, y);
            }
 
            Marshal.FreeCoTaskMem(buffer);
            return result; 
        } 

        // names is pointer to DEVNAMES 
        private static String ReadOneDEVNAME(IntPtr pDevnames, int slot) {
            int offset = Marshal.SystemDefaultCharSize * Marshal.ReadInt16((IntPtr)((long)pDevnames + slot * 2));
            string result = Marshal.PtrToStringAuto((IntPtr)((long)pDevnames + offset));
            return result; 
        }
 
        ///  
        /// 
        ///     
        ///       Copies the relevant information out of the handle and into the PrinterSettings.
        ///    
        /// 
        public void SetHdevmode(IntPtr hdevmode) { 
            IntSecurity.AllPrintingAndUnmanagedCode.Demand();
            // Don't assert unmanaged code -- anyone using handles should have unmanaged code permission 
 
            if (hdevmode == IntPtr.Zero)
                throw new ArgumentException(SR.GetString(SR.InvalidPrinterHandle, hdevmode)); 

            IntPtr pointer = SafeNativeMethods.GlobalLock(new HandleRef(null, hdevmode));
            SafeNativeMethods.DEVMODE mode = (SafeNativeMethods.DEVMODE) UnsafeNativeMethods.PtrToStructure(pointer, typeof(SafeNativeMethods.DEVMODE));
 
            //Copy entire public devmode as a byte array...
            devmodebytes = mode.dmSize; 
            if (devmodebytes > 0)  { 
                cachedDevmode = new byte[devmodebytes];
                Marshal.Copy(pointer, cachedDevmode, 0, devmodebytes); 
            }

            //Copy private devmode as a byte array..
            extrabytes = mode.dmDriverExtra; 
            if (extrabytes > 0)  {
                extrainfo = new byte[extrabytes]; 
                Marshal.Copy((IntPtr)((long)pointer + (long)mode.dmSize), extrainfo, 0, extrabytes); 
            }
 
            if ((mode.dmFields & SafeNativeMethods.DM_COPIES) == SafeNativeMethods.DM_COPIES) {
                copies = mode.dmCopies;
            }
 
            if ((mode.dmFields & SafeNativeMethods.DM_DUPLEX) == SafeNativeMethods.DM_DUPLEX ) {
                duplex = (Duplex) mode.dmDuplex; 
            } 

            if ((mode.dmFields & SafeNativeMethods.DM_COLLATE) == SafeNativeMethods.DM_COLLATE) { 
                collate = (mode.dmCollate == SafeNativeMethods.DMCOLLATE_TRUE);
            }

            SafeNativeMethods.GlobalUnlock(new HandleRef(null, hdevmode)); 
        }
 
        ///  
        /// 
        ///    Copies the relevant information out of the handle and into the PrinterSettings. 
        /// 
        public void SetHdevnames(IntPtr hdevnames) {
            IntSecurity.AllPrintingAndUnmanagedCode.Demand();
 
            if (hdevnames == IntPtr.Zero)
                throw new ArgumentException(SR.GetString(SR.InvalidPrinterHandle, hdevnames)); 
 
            IntPtr namesPointer = SafeNativeMethods.GlobalLock(new HandleRef(null, hdevnames));
 
            driverName = ReadOneDEVNAME(namesPointer, 0);
            printerName = ReadOneDEVNAME(namesPointer, 1);
            outputPort = ReadOneDEVNAME(namesPointer, 2);
 
            PrintDialogDisplayed = true;
 
            SafeNativeMethods.GlobalUnlock(new HandleRef(null, hdevnames)); 
        }
 
        /// 
        /// 
        /// 
        ///     
        ///       Provides some interesting information about the PrinterSettings in
        ///       String form. 
        ///     
        /// 
        public override string ToString() { 
            string printerName = (IntSecurity.HasPermission(IntSecurity.AllPrinting)) ? PrinterName : "";
            return "[PrinterSettings "
            + printerName
            + " Copies=" + Copies.ToString(CultureInfo.InvariantCulture) 
            + " Collate=" + Collate.ToString(CultureInfo.InvariantCulture)
            //            + " DriverName=" + DriverName.ToString(CultureInfo.InvariantCulture) 
            //            + " DriverVersion=" + DriverVersion.ToString(CultureInfo.InvariantCulture) 
            + " Duplex=" + TypeDescriptor.GetConverter(typeof(Duplex)).ConvertToString((int) Duplex)
            + " FromPage=" + FromPage.ToString(CultureInfo.InvariantCulture) 
            + " LandscapeAngle=" + LandscapeAngle.ToString(CultureInfo.InvariantCulture)
            + " MaximumCopies=" + MaximumCopies.ToString(CultureInfo.InvariantCulture)
            + " OutputPort=" + OutputPort.ToString(CultureInfo.InvariantCulture)
            + " ToPage=" + ToPage.ToString(CultureInfo.InvariantCulture) 
            + "]";
        } 
 
        // Write null terminated string, return length of string in characters (including null)
        private short WriteOneDEVNAME(string str, IntPtr bufferStart, int index) { 
            if (str == null) str = "";
            IntPtr address = (IntPtr)((long)bufferStart + index * Marshal.SystemDefaultCharSize);

            if (Marshal.SystemDefaultCharSize == 1) { 
                byte[] bytes = System.Text.Encoding.Default.GetBytes(str);
                Marshal.Copy(bytes, 0, address, bytes.Length); 
                Marshal.WriteByte((IntPtr)((long)address + bytes.Length), 0); 
            }
            else { 
                char[] data = str.ToCharArray();
                Marshal.Copy(data, 0, address, data.Length);
                Marshal.WriteInt16((IntPtr)((long)address + data.Length*2), 0);
            } 

            return(short) (str.Length + 1); 
        } 

        ///  
        /// 
        ///    
        ///       Collection of PaperSize's...
        ///     
        /// 
        public class PaperSizeCollection : ICollection { 
            private PaperSize[] array; 

            ///  
            /// 
            ///    
            ///       Initializes a new instance of the  class.
            ///     
            /// 
            public PaperSizeCollection(PaperSize[] array) { 
                this.array = array; 
            }
 
            /// 
            /// 
            ///    
            ///       Gets a value indicating the number of paper sizes. 
            ///    
            ///  
            public int Count { 
                get {
                    return array.Length; 
                }
            }

            ///  
            /// 
            ///     
            ///       Retrieves the PaperSize with the specified index. 
            ///    
            ///  
            public virtual PaperSize this[int index] {
                get {
                    return array[index];
                } 
            }
 
            ///  
            /// 
            ///  
            public IEnumerator GetEnumerator() {
                return new ArrayEnumerator(array, 0, Count);
            }
 
            /// 
            ///  
            ///    ICollection private interface implementation. 
            /// 
            ///  
            int ICollection.Count {
                get {
                    return this.Count;
                } 
            }
 
 
            /// 
            ///  
            ///    ICollection private interface implementation.
            /// 
            /// 
            bool ICollection.IsSynchronized { 
                get {
                    return false; 
                } 
            }
 
            /// 
            /// 
            ///    ICollection private interface implementation.
            ///  
            /// 
            object ICollection.SyncRoot { 
                get { 
                    return this;
                } 
            }

            /// 
            ///  
            /// ICollection private interface implementation.
            ///  
            ///  
            void ICollection.CopyTo(Array array, int index) {
                Array.Copy(this.array, index, array, 0, this.array.Length); 
            }

            public void CopyTo(PaperSize[] paperSizes, int index) {
                  Array.Copy(this.array, index, paperSizes, 0, this.array.Length); 
            }
 
            ///  
            /// 
            ///    IEnumerable private interface implementation. 
            /// 
            /// 
            IEnumerator IEnumerable.GetEnumerator() {
                return GetEnumerator(); 
            }
 
            ///  
            /// 
            /// Empty implementation required for serialization of PrinterSettings object. 
            /// 
            /// 
            [
                EditorBrowsable(EditorBrowsableState.Never) 
            ]
            public Int32 Add(PaperSize paperSize) 
            { 
                PaperSize[] newArray = new PaperSize[this.Count + 1];
                ((ICollection) this).CopyTo(newArray, 0); 
                newArray[this.Count] = paperSize;
                this.array = newArray;
                return this.Count;
            } 
        }
 
        ///  
        /// 
        ///     
        ///       Collection of PaperSource's...
        ///    
        /// 
        public class PaperSourceCollection : ICollection { 
            private PaperSource[] array;
 
            ///  
            /// 
            ///     
            ///       Initializes a new instance of the  class.
            ///    
            /// 
            public PaperSourceCollection(PaperSource[] array) { 
                this.array = array;
            } 
 
            /// 
            ///  
            ///    
            ///       Gets a value indicating the number of paper sources.
            ///    
            ///  
            public int Count {
                get { 
                    return array.Length; 
                }
            } 

            /// 
            /// 
            ///     
            ///       Gets the PaperSource with the specified index.
            ///     
            ///  
            public virtual PaperSource this[int index] {
                get { 
                    return array[index];
                }
            }
 
            /// 
            ///  
            ///  
            /// 
            ///  
            /// 
            /// 
            public IEnumerator GetEnumerator() {
                return new ArrayEnumerator(array, 0, Count); 
            }
 
            ///  
            /// 
            ///    ICollection private interface implementation. 
            /// 
            /// 
            int ICollection.Count {
                get { 
                    return this.Count;
                } 
            } 

 
            /// 
            /// 
            ///    ICollection private interface implementation.
            ///  
            /// 
            bool ICollection.IsSynchronized { 
                get { 
                    return false;
                } 
            }

            /// 
            ///  
            ///    ICollection private interface implementation.
            ///  
            ///  
            object ICollection.SyncRoot {
                get { 
                    return this;
                }
            }
 
            /// 
            ///  
            /// ICollection private interface implementation. 
            /// 
            ///  
            void ICollection.CopyTo(Array array, int index) {
                Array.Copy(this.array, index, array, 0, this.array.Length);
            }
 
            public void CopyTo(PaperSource[] paperSources, int index) {
                  Array.Copy(this.array, index, paperSources, 0, this.array.Length); 
            } 

            ///  
            /// 
            ///    IEnumerable private interface implementation.
            /// 
            ///  
            IEnumerator IEnumerable.GetEnumerator() {
                return GetEnumerator(); 
            } 

            ///  
            /// 
            /// Empty implementation required for serialization of PrinterSettings object.
            /// 
            ///  
            [
                EditorBrowsable(EditorBrowsableState.Never) 
            ] 
            public Int32 Add(PaperSource paperSource)
            { 
                PaperSource[] newArray = new PaperSource[this.Count + 1];
                ((ICollection) this).CopyTo(newArray, 0);
                newArray[this.Count] = paperSource;
                this.array = newArray; 
                return this.Count;
            } 
        } 

        ///  
        /// 
        ///    
        ///       Collection of PrinterResolution's...
        ///     
        /// 
        public class PrinterResolutionCollection : ICollection { 
            private PrinterResolution[] array; 

            ///  
            /// 
            ///    
            ///       Initializes a new instance of the  class.
            ///     
            /// 
            public PrinterResolutionCollection(PrinterResolution[] array) { 
                this.array = array; 
            }
 
            /// 
            /// 
            ///    
            ///       Gets a 
            ///       value indicating the number of available printer resolutions.
            ///     
            ///  
            public int Count {
                get { 
                    return array.Length;
                }
            }
 
            /// 
            ///  
            ///     
            ///       Retrieves the PrinterResolution with the specified index.
            ///     
            /// 
            public virtual PrinterResolution this[int index] {
                get {
                    return array[index]; 
                }
            } 
 
            /// 
            ///  
            /// 
            /// 
            /// 
            ///  
            /// 
            public IEnumerator GetEnumerator() { 
                return new ArrayEnumerator(array, 0, Count); 
            }
 
            /// 
            /// 
            ///    ICollection private interface implementation.
            ///  
            /// 
            int ICollection.Count { 
                get { 
                    return this.Count;
                } 
            }


            ///  
            /// 
            ///    ICollection private interface implementation. 
            ///  
            /// 
            bool ICollection.IsSynchronized { 
                get {
                    return false;
                }
            } 

            ///  
            ///  
            ///    ICollection private interface implementation.
            ///  
            /// 
            object ICollection.SyncRoot {
                get {
                    return this; 
                }
            } 
 
            /// 
            ///  
            /// ICollection private interface implementation.
            /// 
            /// 
            void ICollection.CopyTo(Array array, int index) { 
                Array.Copy(this.array, index, array, 0, this.array.Length);
            } 
 
            public void CopyTo(PrinterResolution[] printerResolutions, int index) {
                Array.Copy(this.array, index, printerResolutions, 0, this.array.Length); 
            }

            /// 
            ///  
            ///    IEnumerable private interface implementation.
            ///  
            ///  
            IEnumerator IEnumerable.GetEnumerator() {
                return GetEnumerator(); 
            }

            /// 
            ///  
            /// Empty implementation required for serialization of PrinterSettings object.
            ///  
            ///  
            [
                EditorBrowsable(EditorBrowsableState.Never) 
            ]
            public Int32 Add(PrinterResolution printerResolution)
            {
                PrinterResolution[] newArray = new PrinterResolution[this.Count + 1]; 
                ((ICollection) this).CopyTo(newArray, 0);
                newArray[this.Count] = printerResolution; 
                this.array = newArray; 
                return this.Count;
            } 
        }

        /// 
        ///  
        ///    
        ///       Collection of String's... 
        ///     
        /// 
        ///  
        public class StringCollection : ICollection {
            private String[] array;

            ///  
            /// 
            ///     
            ///       Initializes a new instance of the  class. 
            ///    
            ///  
            public StringCollection(String[] array) {
                this.array = array;
            }
 
            /// 
            ///  
            ///     
            ///       Gets a value indicating the number of strings.
            ///     
            /// 
            public int Count {
                get {
                    return array.Length; 
                }
            } 
 
            /// 
            ///  
            ///    
            ///       Gets the string with the specified index.
            ///    
            ///  
            public virtual String this[int index] {
                get { 
                    return array[index]; 
                }
            } 

            /// 
            /// 
            ///  
            /// 
            ///  
            ///  
            /// 
            public IEnumerator GetEnumerator() { 
                return new ArrayEnumerator(array, 0, Count);
            }

            ///  
            /// 
            ///    ICollection private interface implementation. 
            ///  
            /// 
            int ICollection.Count { 
                get {
                    return this.Count;
                }
            } 

 
            ///  
            /// 
            ///    ICollection private interface implementation. 
            /// 
            /// 
            bool ICollection.IsSynchronized {
                get { 
                    return false;
                } 
            } 

            ///  
            /// 
            ///    ICollection private interface implementation.
            /// 
            ///  
            object ICollection.SyncRoot {
                get { 
                    return this; 
                }
            } 

            /// 
            /// 
            /// ICollection private interface implementation. 
            /// 
            ///  
            void ICollection.CopyTo(Array array, int index) { 
                Array.Copy(this.array, index, array, 0, this.array.Length);
            } 


            public void CopyTo(string[] strings, int index) {
                Array.Copy(this.array, index, strings, 0, this.array.Length); 
            }
 
 

            ///  
            /// 
            /// IEnumerable private interface implementation.
            /// 
            ///  
            IEnumerator IEnumerable.GetEnumerator() {
                return GetEnumerator(); 
            } 

            ///  
            /// 
            /// Empty implementation required for serialization of PrinterSettings object.
            /// 
            ///  
            [
                EditorBrowsable(EditorBrowsableState.Never) 
            ] 
            public Int32 Add(String value)
            { 
                String[] newArray = new String[this.Count + 1];
                ((ICollection) this).CopyTo(newArray, 0);
                newArray[this.Count] = value;
                this.array = newArray; 
                return this.Count;
            } 
        } 

        private class ArrayEnumerator : IEnumerator { 
            private object[] array;
            private object item;
            private int index;
            private int startIndex; 
            private int endIndex;
 
            public ArrayEnumerator(object[] array, int startIndex, int count) { 
                this.array = array;
                this.startIndex = startIndex; 
                endIndex = index + count;

                index = this.startIndex;
            } 

            public object Current { 
                get { 
                    return item;
                } 
            }


            public bool MoveNext() { 
                if (index >= endIndex) return false;
                item = array[index++]; 
                return true; 
            }
 
            public void Reset() {

                // Position enumerator before first item
 
                index = startIndex;
                item = null; 
            } 
        }
    } 
}


 
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK