Pen.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / fx / src / CommonUI / System / Drawing / Pen.cs / 2 / Pen.cs

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

namespace System.Drawing 
{ 
    using System.Runtime.InteropServices;
    using System.Diagnostics; 
    using System.Diagnostics.CodeAnalysis;
    using System;
    using System.Internal;
    using Microsoft.Win32; 
    using System.ComponentModel;
    using System.Drawing.Drawing2D; 
    using System.Drawing.Internal; 
    using System.Globalization;
 
    /// 
    /// 
    ///     
    ///         Defines an object used to draw lines and curves. 
    ///     
    ///  
    public sealed class Pen : MarshalByRefObject, ISystemColorTracker, ICloneable, IDisposable { 
#if FINALIZATION_WATCH
        private string allocationSite = Graphics.GetAllocationStack(); 
#endif

        // handle to native GDI+ pen object.
        private IntPtr nativePen; 

        // GDI+ doesn't understand system colors, so we need to cache the value here 
        private Color color; 
        private bool immutable;
 
        /// 
        ///     Creates a Pen from a native GDI+ object.
        /// 
        private Pen(IntPtr nativePen) { 
            SetNativePen( nativePen );
        } 
 

        internal Pen(Color color, bool immutable) : this(color) { 
            this.immutable = immutable;
        }

        ///  
        /// 
        ///     
        ///       Initializes a new instance of the Pen 
        ///       class with the specified .
        ///     
        /// 
        public Pen(Color color) : this(color, (float)1.0) {
        }
 
        /// 
        ///  
        ///     
        ///       Initializes a new instance of the   class with the specified
        ///        and . 
        /// 
        /// 
        public Pen(Color color, float width) {
            this.color = color; 

            IntPtr pen = IntPtr.Zero; 
            int status = SafeNativeMethods.Gdip.GdipCreatePen1(color.ToArgb(), 
                                                width,
                                                (int)GraphicsUnit.World, 
                                                out pen);

            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status); 

            SetNativePen(pen); 
 
            if (this.color.IsSystemColor) {
                SystemColorTracker.Add(this); 
            }
        }

        ///  
        /// 
        ///     
        ///       Initializes a new instance of the Pen class with the 
        ///       specified .
        ///     
        /// 
        public Pen(Brush brush) : this(brush, (float)1.0) {
        }
 
        /// 
        ///  
        ///     
        ///       Initializes a new instance of the  class with
        ///       the specified  and width. 
        ///    
        /// 
        public Pen(Brush brush, float width) {
            IntPtr pen = IntPtr.Zero; 

            if (brush == null) 
                throw new ArgumentNullException("brush"); 

            int status = SafeNativeMethods.Gdip.GdipCreatePen2(new HandleRef(brush, brush.NativeBrush), 
                width,
                (int)GraphicsUnit.World,
                out pen);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status); 
 
            SetNativePen(pen);
        } 

        internal void SetNativePen(IntPtr nativePen) {
            if (nativePen == IntPtr.Zero) {
                throw new ArgumentNullException("nativePen"); 
            }
 
            this.nativePen = nativePen; 
        }
 
        /// 
        ///    Gets the GDI+ native object.
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 
        internal IntPtr NativePen
        { 
            get 
            {
                //Need to comment this line out to allow for checking this.NativePen == IntPtr.Zero. 
                //Debug.Assert(this.nativePen != IntPtr.Zero, "this.nativePen == null." );
                return this.nativePen;
            }
        } 

        /** 
         * Create a copy of the pen object 
         */
        ///  
        /// 
        ///     Creates an exact copy of this .
        /// 
        public object Clone() 
        {
            IntPtr clonePen = IntPtr.Zero; 
 
            int status = SafeNativeMethods.Gdip.GdipClonePen(new HandleRef(this, this.NativePen), out clonePen);
 
            if (status != SafeNativeMethods.Gdip.Ok) {
                throw SafeNativeMethods.Gdip.StatusException(status);
            }
 
            return new Pen(clonePen);
        } 
 
        /**
         * Dispose of resources associated with the Pen object 
         */
        /// 
        /// 
        ///    Cleans up Windows resources for this . 
        /// 
        public void Dispose() { 
            Dispose(true); 
            GC.SuppressFinalize(this);
        } 

        void Dispose(bool disposing)
        {
#if FINALIZATION_WATCH 
            if (!disposing && nativePen != IntPtr.Zero)
                Debug.WriteLine("**********************\nDisposed through finalization:\n" + allocationSite); 
#endif 

            if (!disposing) 
            {
                // If we are finalizing, then we will be unreachable soon.  Finalize calls dispose to
                // release resources, so we must make sure that during finalization we are
                // not immutable. 
                //
                immutable = false; 
            } 
            else if (immutable)
            { 
                throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Brush"));
            }

            if (this.nativePen != IntPtr.Zero) 
            {
                try{ 
#if DEBUG 
                    int status =
#endif 
                    SafeNativeMethods.Gdip.GdipDeletePen(new HandleRef(this, this.NativePen));
#if DEBUG
                    Debug.Assert(status == SafeNativeMethods.Gdip.Ok, "GDI+ returned an error status: " + status.ToString(CultureInfo.InvariantCulture));
#endif 
                }
                catch( Exception ex ){ 
                    if(ClientUtils.IsSecurityOrCriticalException( ex ) ) { 
                        throw;
                    } 

                    Debug.Fail( "Exception thrown during Dispose: " + ex.ToString() );
                }
                finally{ 
                    this.nativePen = IntPtr.Zero;
                } 
            } 
        }
 
        /// 
        /// 
        ///    Cleans up Windows resources for this .
        ///  
        ~Pen() {
            Dispose(false); 
        } 

        /** 
         * Set/get pen width
         */
        /// 
        ///  
        ///    Gets or sets the width of this .
        ///  
        public float Width 
        {
            get 
            {
                float[] width = new float[] { 0};

                int status = SafeNativeMethods.Gdip.GdipGetPenWidth(new HandleRef(this, this.NativePen), width); 

                if (status != SafeNativeMethods.Gdip.Ok) 
                    throw SafeNativeMethods.Gdip.StatusException(status); 

                return width[0]; 
            }

            set
            { 
                if (immutable)
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen")); 
 
                int status = SafeNativeMethods.Gdip.GdipSetPenWidth(new HandleRef(this, this.NativePen), value);
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status);
            }
        } 

        /** 
         * Set/get line caps: start, end, and dash 
         */
        ///  
        /// 
        ///    
        ///       Sets the values that determine the style of
        ///       cap used to end lines drawn by this . 
        ///    
        ///  
        public void SetLineCap(LineCap startCap, LineCap endCap, DashCap dashCap) { 
            if (immutable)
                throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen")); 
            int status = SafeNativeMethods.Gdip.GdipSetPenLineCap197819(new HandleRef(this, this.NativePen), (int)startCap, (int)endCap, (int)dashCap);

            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status); 
        }
 
        ///  
        /// 
        ///     
        ///       Gets or sets the cap style used at the
        ///       beginning of lines drawn with this .
        ///    
        ///  
        public LineCap StartCap
        { 
            get { 
                int startCap = 0;
                int status = SafeNativeMethods.Gdip.GdipGetPenStartCap(new HandleRef(this, this.NativePen), out startCap); 

                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status);
 
                return(LineCap) startCap;
            } 
            set { 
                //validate the enum value
               switch(value) { 
                   case LineCap.Flat:
                   case LineCap.Square:
                   case LineCap.Round:
                   case LineCap.Triangle: 
                   case LineCap.NoAnchor:
                   case LineCap.SquareAnchor: 
                   case LineCap.RoundAnchor: 
                   case LineCap.DiamondAnchor:
                   case LineCap.ArrowAnchor: 
                   case LineCap.AnchorMask:
                   case LineCap.Custom:
                       break;
                   default: 
                       throw new InvalidEnumArgumentException("value", (int)value, typeof(LineCap));
                } 
                if (immutable) 
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen"));
 
                int status = SafeNativeMethods.Gdip.GdipSetPenStartCap(new HandleRef(this, this.NativePen), (int)value);

                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status); 
            }
        } 
 
        /// 
        ///  
        ///    
        ///       Gets or sets the cap style used at the end of
        ///       lines drawn with this .
        ///     
        /// 
        public LineCap EndCap 
        { 
            get {
                int endCap = 0; 
                int status = SafeNativeMethods.Gdip.GdipGetPenEndCap(new HandleRef(this, this.NativePen), out endCap);

                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status); 

                return(LineCap) endCap; 
            } 
            set {
                //validate the enum value 
               switch(value) {
                   case LineCap.Flat:
                   case LineCap.Square:
                   case LineCap.Round: 
                   case LineCap.Triangle:
                   case LineCap.NoAnchor: 
                   case LineCap.SquareAnchor: 
                   case LineCap.RoundAnchor:
                   case LineCap.DiamondAnchor: 
                   case LineCap.ArrowAnchor:
                   case LineCap.AnchorMask:
                   case LineCap.Custom:
                       break; 
                   default:
                       throw new InvalidEnumArgumentException("value", (int)value, typeof(LineCap)); 
                } 

                if (immutable) 
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen"));

                int status = SafeNativeMethods.Gdip.GdipSetPenEndCap(new HandleRef(this, this.NativePen), (int)value);
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status); 
            } 
        }
 
        /// 
        /// 
        ///    Gets or sets the cap style used at the
        ///    beginning or end of dashed lines drawn with this . 
        /// 
        public DashCap DashCap 
        { 
            get {
                int dashCap = 0; 
                int status = SafeNativeMethods.Gdip.GdipGetPenDashCap197819(new HandleRef(this, this.NativePen), out dashCap);

                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status); 

                return(DashCap)dashCap; 
            } 

            set { 
                //validate the enum value
                if (!ClientUtils.IsEnumValid_NotSequential(value, (int)value,
                                                    (int)DashCap.Flat,
                                                    (int)DashCap.Round, 
                                                    (int)DashCap.Triangle))
                { 
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(DashCap)); 
                }
 
                if (immutable)
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen"));

                int status = SafeNativeMethods.Gdip.GdipSetPenDashCap197819(new HandleRef(this, this.NativePen), (int)value); 

                if (status != SafeNativeMethods.Gdip.Ok) 
                    throw SafeNativeMethods.Gdip.StatusException(status); 
            }
        } 

        /**
        * Set/get line join
        */ 
        /// 
        ///  
        ///    Gets or sets the join style for the ends of 
        ///    two overlapping lines drawn with this .
        ///  
        public LineJoin LineJoin
        {
            get {
                int lineJoin = 0; 
                int status = SafeNativeMethods.Gdip.GdipGetPenLineJoin(new HandleRef(this, this.NativePen), out lineJoin);
 
                if (status != SafeNativeMethods.Gdip.Ok) 
                    throw SafeNativeMethods.Gdip.StatusException(status);
 
                return(LineJoin)lineJoin;
            }

            set { 
                //valid values are 0x0 to 0x3
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)LineJoin.Miter, (int)LineJoin.MiterClipped)) 
                { 
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(LineJoin));
                } 

                if (immutable)
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen"));
 
                int status = SafeNativeMethods.Gdip.GdipSetPenLineJoin(new HandleRef(this, this.NativePen), (int)value);
 
                if (status != SafeNativeMethods.Gdip.Ok) 
                    throw SafeNativeMethods.Gdip.StatusException(status);
            } 
        }

        /**
         * Set/get custom start line cap 
         */
        ///  
        ///  
        ///    
        ///       Gets or sets a custom cap style to use at the beginning of lines 
        ///       drawn with this .
        ///    
        /// 
        public CustomLineCap CustomStartCap 
        {
            get { 
                IntPtr lineCap = IntPtr.Zero; 
                int status = SafeNativeMethods.Gdip.GdipGetPenCustomStartCap(new HandleRef(this, this.NativePen), out lineCap);
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status);

                return CustomLineCap.CreateCustomLineCapObject(lineCap); 
            }
 
            set { 
                if (immutable)
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen")); 

                int status = SafeNativeMethods.Gdip.GdipSetPenCustomStartCap(new HandleRef(this, this.NativePen),
                                                              new HandleRef(value, (value == null) ? IntPtr.Zero : value.nativeCap));
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status); 
            } 
        }
 
        /**
         * Set/get custom end line cap
         */
        ///  
        /// 
        ///     
        ///       Gets or sets a custom cap style to use at the end of lines 
        ///       drawn with this .
        ///     
        /// 
        public CustomLineCap CustomEndCap
        {
            get { 
                IntPtr lineCap = IntPtr.Zero;
                int status = SafeNativeMethods.Gdip.GdipGetPenCustomEndCap(new HandleRef(this, this.NativePen), out lineCap); 
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status); 

                return CustomLineCap.CreateCustomLineCapObject(lineCap);
            }
 
            set {
                if (immutable) 
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen")); 

                int status = SafeNativeMethods.Gdip.GdipSetPenCustomEndCap(new HandleRef(this, this.NativePen), 
                                                            new HandleRef(value, (value == null) ? IntPtr.Zero : value.nativeCap));

                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status); 
            }
        } 
 
        /// 
        ///  
        ///    Gets or sets the limit of the thickness of
        ///    the join on a mitered corner.
        /// 
        public float MiterLimit 
        {
            get { 
                float[] miterLimit = new float[] { 0}; 
                int status = SafeNativeMethods.Gdip.GdipGetPenMiterLimit(new HandleRef(this, this.NativePen), miterLimit);
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status);

                return miterLimit[0]; 
            }
 
            set { 
                if (immutable)
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen")); 

                int status = SafeNativeMethods.Gdip.GdipSetPenMiterLimit(new HandleRef(this, this.NativePen), value);

                if (status != SafeNativeMethods.Gdip.Ok) 
                    throw SafeNativeMethods.Gdip.StatusException(status);
            } 
        } 

        /** 
         * Pen Mode
         */
        /// 
        ///  
        ///    
        ///       Gets or sets 
        ///       the alignment for objects drawn with this . 
        ///    
        ///  
        public PenAlignment Alignment
        {
            get {
                PenAlignment penMode = 0; 

                int status = SafeNativeMethods.Gdip.GdipGetPenMode(new HandleRef(this, this.NativePen), out penMode); 
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status); 

                return(PenAlignment) penMode;
            }
            set { 
                //validate the enum value
                //valid values are 0x0 to 0x4 
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)PenAlignment.Center, (int)PenAlignment.Right)) 
                {
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(PenAlignment)); 
                }

                if (immutable)
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen")); 

                int status = SafeNativeMethods.Gdip.GdipSetPenMode(new HandleRef(this, this.NativePen), value); 
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status); 
            }
        }

        /** 
         * Set/get pen transform
         */ 
        ///  
        /// 
        ///     
        ///       Gets
        ///       or sets the geometrical transform for objects drawn with this .
        ///    
        ///  
        public Matrix Transform
        { 
            get { 
                Matrix matrix = new Matrix();
 
                int status = SafeNativeMethods.Gdip.GdipGetPenTransform(new HandleRef(this, this.NativePen), new HandleRef(matrix, matrix.nativeMatrix));

                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status); 

                return matrix; 
            } 

            set { 
                if (immutable)
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen"));

                if (value == null) { 
                    throw new ArgumentNullException("value");
                } 
 
                int status = SafeNativeMethods.Gdip.GdipSetPenTransform(new HandleRef(this, this.NativePen), new HandleRef(value, value.nativeMatrix));
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status);
            }
        } 

        ///  
        ///  
        ///    Resets the geometric transform for this
        ///  to 
        ///    identity.
        /// 
        public void ResetTransform() {
            int status = SafeNativeMethods.Gdip.GdipResetPenTransform(new HandleRef(this, this.NativePen)); 

            if (status != SafeNativeMethods.Gdip.Ok) 
                throw SafeNativeMethods.Gdip.StatusException(status); 
        }
 
        /// 
        /// 
        ///    
        ///       Multiplies the transform matrix for this 
        ///     by
        ///       the specified . 
        ///     
        /// 
        public void MultiplyTransform(Matrix matrix) { 
            MultiplyTransform(matrix, MatrixOrder.Prepend);
        }

        ///  
        /// 
        ///     
        ///       Multiplies the transform matrix for this 
        ///     by
        ///       the specified  in the specified order. 
        ///    
        /// 
        public void MultiplyTransform(Matrix matrix, MatrixOrder order) {
            int status = SafeNativeMethods.Gdip.GdipMultiplyPenTransform(new HandleRef(this, this.NativePen), 
                                                          new HandleRef(matrix, matrix.nativeMatrix),
                                                          order); 
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status); 
        }

        /// 
        ///  
        ///    
        ///       Translates the local geometrical transform 
        ///       by the specified dimmensions. This method prepends the translation to the 
        ///       transform.
        ///     
        /// 
        public void TranslateTransform(float dx, float dy) {
            TranslateTransform(dx, dy, MatrixOrder.Prepend);
        } 

        ///  
        ///  
        ///    Translates the local geometrical transform
        ///    by the specified dimmensions in the specified order. 
        /// 
        public void TranslateTransform(float dx, float dy, MatrixOrder order) {
            int status = SafeNativeMethods.Gdip.GdipTranslatePenTransform(new HandleRef(this, this.NativePen),
                                                           dx, dy, order); 

            if (status != SafeNativeMethods.Gdip.Ok) 
                throw SafeNativeMethods.Gdip.StatusException(status); 
        }
 
        /// 
        /// 
        ///    Scales the local geometric transform by the
        ///    specified amounts. This method prepends the scaling matrix to the transform. 
        /// 
        public void ScaleTransform(float sx, float sy) { 
            ScaleTransform(sx, sy, MatrixOrder.Prepend); 
        }
 
        /// 
        /// 
        ///    
        ///       Scales the local geometric transform by the 
        ///       specified amounts in the specified order.
        ///     
        ///  
        public void ScaleTransform(float sx, float sy, MatrixOrder order) {
            int status = SafeNativeMethods.Gdip.GdipScalePenTransform(new HandleRef(this, this.NativePen), 
                                                       sx, sy, order);

            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status); 
        }
 
        ///  
        /// 
        ///    Rotates the local geometric transform by the 
        ///    specified amount. This method prepends the rotation to the transform.
        /// 
        public void RotateTransform(float angle) {
            RotateTransform(angle, MatrixOrder.Prepend); 
        }
 
        ///  
        /// 
        ///     
        ///       Rotates the local geometric transform by the specified
        ///       amount in the specified order.
        ///    
        ///  
        public void RotateTransform(float angle, MatrixOrder order) {
            int status = SafeNativeMethods.Gdip.GdipRotatePenTransform(new HandleRef(this, this.NativePen), 
                                                        angle, order); 

            if (status != SafeNativeMethods.Gdip.Ok) 
                throw SafeNativeMethods.Gdip.StatusException(status);
        }

        /** 
         * Set/get pen type (color, line texture, or brush)
         * 
         * @notes GetLineFill returns either a Brush object 
         *  or a LineTexture object.
         */ 

        private void InternalSetColor(Color value) {
            int status = SafeNativeMethods.Gdip.GdipSetPenColor(new HandleRef(this, this.NativePen),
                                                 color.ToArgb()); 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status); 
 
            this.color = value;
        } 

        /// 
        /// 
        ///    Gets the style of lines drawn with this 
        /// .
        ///  
        public PenType PenType 
        {
            get { 
                int type = -1;

                int status = SafeNativeMethods.Gdip.GdipGetPenFillType(new HandleRef(this, this.NativePen), out type);
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status); 
 
                return(PenType)type;
            } 
        }

        /// 
        ///  
        ///    
        ///       Gets or sets the color of this . 
        ///     
        /// 
        public Color Color { 
            get {
                if (color == Color.Empty) {
                    int colorARGB = 0;
                    int status = SafeNativeMethods.Gdip.GdipGetPenColor(new HandleRef(this, this.NativePen), out colorARGB); 

                    if (status != SafeNativeMethods.Gdip.Ok) 
                        throw SafeNativeMethods.Gdip.StatusException(status); 

                    this.color = Color.FromArgb(colorARGB); 
                }

                // GDI+ doesn't understand system colors, so we can't use GdipGetPenColor in the general case
                return this.color; 
            }
 
            set { 
                if (immutable)
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen")); 

                if( value != this.color )
                {
                    Color oldColor = this.color; 
                    this.color = value;
                    InternalSetColor(value); 
 
                    //
 
                    if (value.IsSystemColor && !oldColor.IsSystemColor)
                        SystemColorTracker.Add(this);
                }
            } 
        }
 
        ///  
        /// 
        ///    Gets or sets the  that 
        ///    determines attributes of this .
        /// 
        public Brush Brush {
            get { 
                Brush brush = null;
 
                switch (PenType) { 
                    case PenType.SolidColor:
                        brush = new SolidBrush(GetNativeBrush()); 
                        break;

                    case PenType.HatchFill:
                        brush = new HatchBrush(GetNativeBrush()); 
                        break;
 
                    case PenType.TextureFill: 
                        brush = new TextureBrush(GetNativeBrush());
                        break; 

                    case PenType.PathGradient:
                        brush = new PathGradientBrush(GetNativeBrush());
                        break; 

                    case PenType.LinearGradient: 
                        brush = new LinearGradientBrush(GetNativeBrush()); 
                        break;
 
                    default:
                        break;
                }
 
                return brush;
            } 
 
            set {
                if (immutable) 
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen"));

                if (value == null)
                    throw new ArgumentNullException("value"); 

                int status = SafeNativeMethods.Gdip.GdipSetPenBrushFill(new HandleRef(this, this.NativePen), 
                    new HandleRef(value, value.NativeBrush)); 

                if (status != SafeNativeMethods.Gdip.Ok) 
                    throw SafeNativeMethods.Gdip.StatusException(status);
            }
        }
 
        private IntPtr GetNativeBrush()
        { 
            IntPtr nativeBrush = IntPtr.Zero; 

            int status = SafeNativeMethods.Gdip.GdipGetPenBrushFill(new HandleRef(this, this.NativePen), out nativeBrush); 

            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
 
            return nativeBrush;
        } 
 
        /**
         * Set/get dash attributes 
         */
        /// 
        /// 
        ///    Gets or sets the style used for dashed 
        ///    lines drawn with this .
        ///  
        public DashStyle DashStyle 
        {
            get { 
                int dashstyle = 0;

                int status = SafeNativeMethods.Gdip.GdipGetPenDashStyle(new HandleRef(this, this.NativePen), out dashstyle);
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status); 
 
                return(DashStyle) dashstyle;
            } 

            set {

                //valid values are 0x0 to 0x5 
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)DashStyle.Solid, (int)DashStyle.Custom))
                { 
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(DashStyle)); 
                }
 
                if (immutable)
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen"));

                int status = SafeNativeMethods.Gdip.GdipSetPenDashStyle(new HandleRef(this, this.NativePen), (int)value); 

                if (status != SafeNativeMethods.Gdip.Ok) { 
                    throw SafeNativeMethods.Gdip.StatusException(status); 
                }
 
                //if we just set pen style to "custom" without defining the custom dash pattern,
                //lets make sure we can return a valid value...
                //
                if (value == DashStyle.Custom) { 
                    EnsureValidDashPattern();
                } 
            } 
        }
 
        /// 
        /// 
        ///    This method is called after the user sets the pen's dash style to custom.
        ///    Here, we make sure that there is a default value set for the custom pattern. 
        /// 
        private void EnsureValidDashPattern() { 
            int retval = 0; 
            int status = SafeNativeMethods.Gdip.GdipGetPenDashCount(new HandleRef(this, this.NativePen), out retval);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);

            if (retval == 0) { 
                //just set to a solid pattern
                DashPattern = new float[]{1}; 
            } 
        }
 
        /// 
        /// 
        ///    Gets or sets the distance from the start of
        ///    a line to the beginning of a dash pattern. 
        /// 
        public float DashOffset 
        { 
            get {
                float[] dashoffset = new float[] { 0}; 

                int status = SafeNativeMethods.Gdip.GdipGetPenDashOffset(new HandleRef(this, this.NativePen), dashoffset);

                if (status != SafeNativeMethods.Gdip.Ok) 
                    throw SafeNativeMethods.Gdip.StatusException(status);
 
                return dashoffset[0]; 
            }
            set { 
                if (immutable)
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen"));

                int status = SafeNativeMethods.Gdip.GdipSetPenDashOffset(new HandleRef(this, this.NativePen), value); 

                if (status != SafeNativeMethods.Gdip.Ok) 
                    throw SafeNativeMethods.Gdip.StatusException(status); 
            }
        } 

        /// 
        /// 
        ///     
        ///       Gets or sets an array of cutom dashes and
        ///       spaces. The dashes are made up of line segments. 
        ///     
        /// 
        public float[] DashPattern 
        {
            get {
                float[] dashArray;
 
                // Figure out how many dash elements we have
 
                int retval = 0; 
                int status = SafeNativeMethods.Gdip.GdipGetPenDashCount(new HandleRef(this, this.NativePen), out retval);
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status);

                int count = retval; 

                // Allocate temporary native memory buffer 
                // and pass it to GDI+ to retrieve dash array elements 

                IntPtr buf = Marshal.AllocHGlobal(4 * count); 
                status = SafeNativeMethods.Gdip.GdipGetPenDashArray(new HandleRef(this, this.NativePen), buf, count);

                try {
                    if (status != SafeNativeMethods.Gdip.Ok) { 
                        throw SafeNativeMethods.Gdip.StatusException(status);
                    } 
 
                    dashArray = new float[count];
 
                    Marshal.Copy(buf, dashArray, 0, count);
                }
                finally {
                    Marshal.FreeHGlobal(buf); 
                }
 
                return dashArray; 
            }
 
            set {
                if (immutable)
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen"));
 

                //validate the DashPattern value being set 
                if (value ==  null || value.Length == 0) { 
                    throw new ArgumentException(SR.GetString(SR.InvalidDashPattern));
                } 

                int count = value.Length;

                IntPtr buf = Marshal.AllocHGlobal(4 * count); 

                try { 
                    Marshal.Copy(value, 0, buf, count); 

                    int status = SafeNativeMethods.Gdip.GdipSetPenDashArray(new HandleRef(this, this.NativePen), new HandleRef(buf, buf), count); 

                    if (status != SafeNativeMethods.Gdip.Ok){
                        throw SafeNativeMethods.Gdip.StatusException(status);
                    } 
                }
                finally { 
                    Marshal.FreeHGlobal(buf); 
                }
            } 
        }

        /// 
        ///  
        ///    Gets or sets an array of cutom dashes and
        ///    spaces. The dashes are made up of line segments. 
        ///  
        public float[] CompoundArray
        { 
            get {
                int count = 0;

                int status = SafeNativeMethods.Gdip.GdipGetPenCompoundCount(new HandleRef(this, this.NativePen), out count); 

                if (status != SafeNativeMethods.Gdip.Ok) 
                    throw SafeNativeMethods.Gdip.StatusException(status); 

                float[] array = new float[count]; 

                status = SafeNativeMethods.Gdip.GdipGetPenCompoundArray(new HandleRef(this, this.NativePen), array, count);
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status); 

                return array; 
            } 
            set {
                if (immutable) 
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen"));

                int status = SafeNativeMethods.Gdip.GdipSetPenCompoundArray(new HandleRef(this, this.NativePen), value, value.Length);
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status); 
            } 
        }
 
        /// 
        /// 
        void ISystemColorTracker.OnSystemColorChanged() {
            if (this.NativePen != IntPtr.Zero) 
                InternalSetColor(color);
        } 
    } 
}

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

namespace System.Drawing 
{ 
    using System.Runtime.InteropServices;
    using System.Diagnostics; 
    using System.Diagnostics.CodeAnalysis;
    using System;
    using System.Internal;
    using Microsoft.Win32; 
    using System.ComponentModel;
    using System.Drawing.Drawing2D; 
    using System.Drawing.Internal; 
    using System.Globalization;
 
    /// 
    /// 
    ///     
    ///         Defines an object used to draw lines and curves. 
    ///     
    ///  
    public sealed class Pen : MarshalByRefObject, ISystemColorTracker, ICloneable, IDisposable { 
#if FINALIZATION_WATCH
        private string allocationSite = Graphics.GetAllocationStack(); 
#endif

        // handle to native GDI+ pen object.
        private IntPtr nativePen; 

        // GDI+ doesn't understand system colors, so we need to cache the value here 
        private Color color; 
        private bool immutable;
 
        /// 
        ///     Creates a Pen from a native GDI+ object.
        /// 
        private Pen(IntPtr nativePen) { 
            SetNativePen( nativePen );
        } 
 

        internal Pen(Color color, bool immutable) : this(color) { 
            this.immutable = immutable;
        }

        ///  
        /// 
        ///     
        ///       Initializes a new instance of the Pen 
        ///       class with the specified .
        ///     
        /// 
        public Pen(Color color) : this(color, (float)1.0) {
        }
 
        /// 
        ///  
        ///     
        ///       Initializes a new instance of the   class with the specified
        ///        and . 
        /// 
        /// 
        public Pen(Color color, float width) {
            this.color = color; 

            IntPtr pen = IntPtr.Zero; 
            int status = SafeNativeMethods.Gdip.GdipCreatePen1(color.ToArgb(), 
                                                width,
                                                (int)GraphicsUnit.World, 
                                                out pen);

            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status); 

            SetNativePen(pen); 
 
            if (this.color.IsSystemColor) {
                SystemColorTracker.Add(this); 
            }
        }

        ///  
        /// 
        ///     
        ///       Initializes a new instance of the Pen class with the 
        ///       specified .
        ///     
        /// 
        public Pen(Brush brush) : this(brush, (float)1.0) {
        }
 
        /// 
        ///  
        ///     
        ///       Initializes a new instance of the  class with
        ///       the specified  and width. 
        ///    
        /// 
        public Pen(Brush brush, float width) {
            IntPtr pen = IntPtr.Zero; 

            if (brush == null) 
                throw new ArgumentNullException("brush"); 

            int status = SafeNativeMethods.Gdip.GdipCreatePen2(new HandleRef(brush, brush.NativeBrush), 
                width,
                (int)GraphicsUnit.World,
                out pen);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status); 
 
            SetNativePen(pen);
        } 

        internal void SetNativePen(IntPtr nativePen) {
            if (nativePen == IntPtr.Zero) {
                throw new ArgumentNullException("nativePen"); 
            }
 
            this.nativePen = nativePen; 
        }
 
        /// 
        ///    Gets the GDI+ native object.
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 
        internal IntPtr NativePen
        { 
            get 
            {
                //Need to comment this line out to allow for checking this.NativePen == IntPtr.Zero. 
                //Debug.Assert(this.nativePen != IntPtr.Zero, "this.nativePen == null." );
                return this.nativePen;
            }
        } 

        /** 
         * Create a copy of the pen object 
         */
        ///  
        /// 
        ///     Creates an exact copy of this .
        /// 
        public object Clone() 
        {
            IntPtr clonePen = IntPtr.Zero; 
 
            int status = SafeNativeMethods.Gdip.GdipClonePen(new HandleRef(this, this.NativePen), out clonePen);
 
            if (status != SafeNativeMethods.Gdip.Ok) {
                throw SafeNativeMethods.Gdip.StatusException(status);
            }
 
            return new Pen(clonePen);
        } 
 
        /**
         * Dispose of resources associated with the Pen object 
         */
        /// 
        /// 
        ///    Cleans up Windows resources for this . 
        /// 
        public void Dispose() { 
            Dispose(true); 
            GC.SuppressFinalize(this);
        } 

        void Dispose(bool disposing)
        {
#if FINALIZATION_WATCH 
            if (!disposing && nativePen != IntPtr.Zero)
                Debug.WriteLine("**********************\nDisposed through finalization:\n" + allocationSite); 
#endif 

            if (!disposing) 
            {
                // If we are finalizing, then we will be unreachable soon.  Finalize calls dispose to
                // release resources, so we must make sure that during finalization we are
                // not immutable. 
                //
                immutable = false; 
            } 
            else if (immutable)
            { 
                throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Brush"));
            }

            if (this.nativePen != IntPtr.Zero) 
            {
                try{ 
#if DEBUG 
                    int status =
#endif 
                    SafeNativeMethods.Gdip.GdipDeletePen(new HandleRef(this, this.NativePen));
#if DEBUG
                    Debug.Assert(status == SafeNativeMethods.Gdip.Ok, "GDI+ returned an error status: " + status.ToString(CultureInfo.InvariantCulture));
#endif 
                }
                catch( Exception ex ){ 
                    if(ClientUtils.IsSecurityOrCriticalException( ex ) ) { 
                        throw;
                    } 

                    Debug.Fail( "Exception thrown during Dispose: " + ex.ToString() );
                }
                finally{ 
                    this.nativePen = IntPtr.Zero;
                } 
            } 
        }
 
        /// 
        /// 
        ///    Cleans up Windows resources for this .
        ///  
        ~Pen() {
            Dispose(false); 
        } 

        /** 
         * Set/get pen width
         */
        /// 
        ///  
        ///    Gets or sets the width of this .
        ///  
        public float Width 
        {
            get 
            {
                float[] width = new float[] { 0};

                int status = SafeNativeMethods.Gdip.GdipGetPenWidth(new HandleRef(this, this.NativePen), width); 

                if (status != SafeNativeMethods.Gdip.Ok) 
                    throw SafeNativeMethods.Gdip.StatusException(status); 

                return width[0]; 
            }

            set
            { 
                if (immutable)
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen")); 
 
                int status = SafeNativeMethods.Gdip.GdipSetPenWidth(new HandleRef(this, this.NativePen), value);
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status);
            }
        } 

        /** 
         * Set/get line caps: start, end, and dash 
         */
        ///  
        /// 
        ///    
        ///       Sets the values that determine the style of
        ///       cap used to end lines drawn by this . 
        ///    
        ///  
        public void SetLineCap(LineCap startCap, LineCap endCap, DashCap dashCap) { 
            if (immutable)
                throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen")); 
            int status = SafeNativeMethods.Gdip.GdipSetPenLineCap197819(new HandleRef(this, this.NativePen), (int)startCap, (int)endCap, (int)dashCap);

            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status); 
        }
 
        ///  
        /// 
        ///     
        ///       Gets or sets the cap style used at the
        ///       beginning of lines drawn with this .
        ///    
        ///  
        public LineCap StartCap
        { 
            get { 
                int startCap = 0;
                int status = SafeNativeMethods.Gdip.GdipGetPenStartCap(new HandleRef(this, this.NativePen), out startCap); 

                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status);
 
                return(LineCap) startCap;
            } 
            set { 
                //validate the enum value
               switch(value) { 
                   case LineCap.Flat:
                   case LineCap.Square:
                   case LineCap.Round:
                   case LineCap.Triangle: 
                   case LineCap.NoAnchor:
                   case LineCap.SquareAnchor: 
                   case LineCap.RoundAnchor: 
                   case LineCap.DiamondAnchor:
                   case LineCap.ArrowAnchor: 
                   case LineCap.AnchorMask:
                   case LineCap.Custom:
                       break;
                   default: 
                       throw new InvalidEnumArgumentException("value", (int)value, typeof(LineCap));
                } 
                if (immutable) 
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen"));
 
                int status = SafeNativeMethods.Gdip.GdipSetPenStartCap(new HandleRef(this, this.NativePen), (int)value);

                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status); 
            }
        } 
 
        /// 
        ///  
        ///    
        ///       Gets or sets the cap style used at the end of
        ///       lines drawn with this .
        ///     
        /// 
        public LineCap EndCap 
        { 
            get {
                int endCap = 0; 
                int status = SafeNativeMethods.Gdip.GdipGetPenEndCap(new HandleRef(this, this.NativePen), out endCap);

                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status); 

                return(LineCap) endCap; 
            } 
            set {
                //validate the enum value 
               switch(value) {
                   case LineCap.Flat:
                   case LineCap.Square:
                   case LineCap.Round: 
                   case LineCap.Triangle:
                   case LineCap.NoAnchor: 
                   case LineCap.SquareAnchor: 
                   case LineCap.RoundAnchor:
                   case LineCap.DiamondAnchor: 
                   case LineCap.ArrowAnchor:
                   case LineCap.AnchorMask:
                   case LineCap.Custom:
                       break; 
                   default:
                       throw new InvalidEnumArgumentException("value", (int)value, typeof(LineCap)); 
                } 

                if (immutable) 
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen"));

                int status = SafeNativeMethods.Gdip.GdipSetPenEndCap(new HandleRef(this, this.NativePen), (int)value);
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status); 
            } 
        }
 
        /// 
        /// 
        ///    Gets or sets the cap style used at the
        ///    beginning or end of dashed lines drawn with this . 
        /// 
        public DashCap DashCap 
        { 
            get {
                int dashCap = 0; 
                int status = SafeNativeMethods.Gdip.GdipGetPenDashCap197819(new HandleRef(this, this.NativePen), out dashCap);

                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status); 

                return(DashCap)dashCap; 
            } 

            set { 
                //validate the enum value
                if (!ClientUtils.IsEnumValid_NotSequential(value, (int)value,
                                                    (int)DashCap.Flat,
                                                    (int)DashCap.Round, 
                                                    (int)DashCap.Triangle))
                { 
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(DashCap)); 
                }
 
                if (immutable)
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen"));

                int status = SafeNativeMethods.Gdip.GdipSetPenDashCap197819(new HandleRef(this, this.NativePen), (int)value); 

                if (status != SafeNativeMethods.Gdip.Ok) 
                    throw SafeNativeMethods.Gdip.StatusException(status); 
            }
        } 

        /**
        * Set/get line join
        */ 
        /// 
        ///  
        ///    Gets or sets the join style for the ends of 
        ///    two overlapping lines drawn with this .
        ///  
        public LineJoin LineJoin
        {
            get {
                int lineJoin = 0; 
                int status = SafeNativeMethods.Gdip.GdipGetPenLineJoin(new HandleRef(this, this.NativePen), out lineJoin);
 
                if (status != SafeNativeMethods.Gdip.Ok) 
                    throw SafeNativeMethods.Gdip.StatusException(status);
 
                return(LineJoin)lineJoin;
            }

            set { 
                //valid values are 0x0 to 0x3
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)LineJoin.Miter, (int)LineJoin.MiterClipped)) 
                { 
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(LineJoin));
                } 

                if (immutable)
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen"));
 
                int status = SafeNativeMethods.Gdip.GdipSetPenLineJoin(new HandleRef(this, this.NativePen), (int)value);
 
                if (status != SafeNativeMethods.Gdip.Ok) 
                    throw SafeNativeMethods.Gdip.StatusException(status);
            } 
        }

        /**
         * Set/get custom start line cap 
         */
        ///  
        ///  
        ///    
        ///       Gets or sets a custom cap style to use at the beginning of lines 
        ///       drawn with this .
        ///    
        /// 
        public CustomLineCap CustomStartCap 
        {
            get { 
                IntPtr lineCap = IntPtr.Zero; 
                int status = SafeNativeMethods.Gdip.GdipGetPenCustomStartCap(new HandleRef(this, this.NativePen), out lineCap);
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status);

                return CustomLineCap.CreateCustomLineCapObject(lineCap); 
            }
 
            set { 
                if (immutable)
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen")); 

                int status = SafeNativeMethods.Gdip.GdipSetPenCustomStartCap(new HandleRef(this, this.NativePen),
                                                              new HandleRef(value, (value == null) ? IntPtr.Zero : value.nativeCap));
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status); 
            } 
        }
 
        /**
         * Set/get custom end line cap
         */
        ///  
        /// 
        ///     
        ///       Gets or sets a custom cap style to use at the end of lines 
        ///       drawn with this .
        ///     
        /// 
        public CustomLineCap CustomEndCap
        {
            get { 
                IntPtr lineCap = IntPtr.Zero;
                int status = SafeNativeMethods.Gdip.GdipGetPenCustomEndCap(new HandleRef(this, this.NativePen), out lineCap); 
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status); 

                return CustomLineCap.CreateCustomLineCapObject(lineCap);
            }
 
            set {
                if (immutable) 
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen")); 

                int status = SafeNativeMethods.Gdip.GdipSetPenCustomEndCap(new HandleRef(this, this.NativePen), 
                                                            new HandleRef(value, (value == null) ? IntPtr.Zero : value.nativeCap));

                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status); 
            }
        } 
 
        /// 
        ///  
        ///    Gets or sets the limit of the thickness of
        ///    the join on a mitered corner.
        /// 
        public float MiterLimit 
        {
            get { 
                float[] miterLimit = new float[] { 0}; 
                int status = SafeNativeMethods.Gdip.GdipGetPenMiterLimit(new HandleRef(this, this.NativePen), miterLimit);
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status);

                return miterLimit[0]; 
            }
 
            set { 
                if (immutable)
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen")); 

                int status = SafeNativeMethods.Gdip.GdipSetPenMiterLimit(new HandleRef(this, this.NativePen), value);

                if (status != SafeNativeMethods.Gdip.Ok) 
                    throw SafeNativeMethods.Gdip.StatusException(status);
            } 
        } 

        /** 
         * Pen Mode
         */
        /// 
        ///  
        ///    
        ///       Gets or sets 
        ///       the alignment for objects drawn with this . 
        ///    
        ///  
        public PenAlignment Alignment
        {
            get {
                PenAlignment penMode = 0; 

                int status = SafeNativeMethods.Gdip.GdipGetPenMode(new HandleRef(this, this.NativePen), out penMode); 
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status); 

                return(PenAlignment) penMode;
            }
            set { 
                //validate the enum value
                //valid values are 0x0 to 0x4 
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)PenAlignment.Center, (int)PenAlignment.Right)) 
                {
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(PenAlignment)); 
                }

                if (immutable)
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen")); 

                int status = SafeNativeMethods.Gdip.GdipSetPenMode(new HandleRef(this, this.NativePen), value); 
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status); 
            }
        }

        /** 
         * Set/get pen transform
         */ 
        ///  
        /// 
        ///     
        ///       Gets
        ///       or sets the geometrical transform for objects drawn with this .
        ///    
        ///  
        public Matrix Transform
        { 
            get { 
                Matrix matrix = new Matrix();
 
                int status = SafeNativeMethods.Gdip.GdipGetPenTransform(new HandleRef(this, this.NativePen), new HandleRef(matrix, matrix.nativeMatrix));

                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status); 

                return matrix; 
            } 

            set { 
                if (immutable)
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen"));

                if (value == null) { 
                    throw new ArgumentNullException("value");
                } 
 
                int status = SafeNativeMethods.Gdip.GdipSetPenTransform(new HandleRef(this, this.NativePen), new HandleRef(value, value.nativeMatrix));
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status);
            }
        } 

        ///  
        ///  
        ///    Resets the geometric transform for this
        ///  to 
        ///    identity.
        /// 
        public void ResetTransform() {
            int status = SafeNativeMethods.Gdip.GdipResetPenTransform(new HandleRef(this, this.NativePen)); 

            if (status != SafeNativeMethods.Gdip.Ok) 
                throw SafeNativeMethods.Gdip.StatusException(status); 
        }
 
        /// 
        /// 
        ///    
        ///       Multiplies the transform matrix for this 
        ///     by
        ///       the specified . 
        ///     
        /// 
        public void MultiplyTransform(Matrix matrix) { 
            MultiplyTransform(matrix, MatrixOrder.Prepend);
        }

        ///  
        /// 
        ///     
        ///       Multiplies the transform matrix for this 
        ///     by
        ///       the specified  in the specified order. 
        ///    
        /// 
        public void MultiplyTransform(Matrix matrix, MatrixOrder order) {
            int status = SafeNativeMethods.Gdip.GdipMultiplyPenTransform(new HandleRef(this, this.NativePen), 
                                                          new HandleRef(matrix, matrix.nativeMatrix),
                                                          order); 
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status); 
        }

        /// 
        ///  
        ///    
        ///       Translates the local geometrical transform 
        ///       by the specified dimmensions. This method prepends the translation to the 
        ///       transform.
        ///     
        /// 
        public void TranslateTransform(float dx, float dy) {
            TranslateTransform(dx, dy, MatrixOrder.Prepend);
        } 

        ///  
        ///  
        ///    Translates the local geometrical transform
        ///    by the specified dimmensions in the specified order. 
        /// 
        public void TranslateTransform(float dx, float dy, MatrixOrder order) {
            int status = SafeNativeMethods.Gdip.GdipTranslatePenTransform(new HandleRef(this, this.NativePen),
                                                           dx, dy, order); 

            if (status != SafeNativeMethods.Gdip.Ok) 
                throw SafeNativeMethods.Gdip.StatusException(status); 
        }
 
        /// 
        /// 
        ///    Scales the local geometric transform by the
        ///    specified amounts. This method prepends the scaling matrix to the transform. 
        /// 
        public void ScaleTransform(float sx, float sy) { 
            ScaleTransform(sx, sy, MatrixOrder.Prepend); 
        }
 
        /// 
        /// 
        ///    
        ///       Scales the local geometric transform by the 
        ///       specified amounts in the specified order.
        ///     
        ///  
        public void ScaleTransform(float sx, float sy, MatrixOrder order) {
            int status = SafeNativeMethods.Gdip.GdipScalePenTransform(new HandleRef(this, this.NativePen), 
                                                       sx, sy, order);

            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status); 
        }
 
        ///  
        /// 
        ///    Rotates the local geometric transform by the 
        ///    specified amount. This method prepends the rotation to the transform.
        /// 
        public void RotateTransform(float angle) {
            RotateTransform(angle, MatrixOrder.Prepend); 
        }
 
        ///  
        /// 
        ///     
        ///       Rotates the local geometric transform by the specified
        ///       amount in the specified order.
        ///    
        ///  
        public void RotateTransform(float angle, MatrixOrder order) {
            int status = SafeNativeMethods.Gdip.GdipRotatePenTransform(new HandleRef(this, this.NativePen), 
                                                        angle, order); 

            if (status != SafeNativeMethods.Gdip.Ok) 
                throw SafeNativeMethods.Gdip.StatusException(status);
        }

        /** 
         * Set/get pen type (color, line texture, or brush)
         * 
         * @notes GetLineFill returns either a Brush object 
         *  or a LineTexture object.
         */ 

        private void InternalSetColor(Color value) {
            int status = SafeNativeMethods.Gdip.GdipSetPenColor(new HandleRef(this, this.NativePen),
                                                 color.ToArgb()); 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status); 
 
            this.color = value;
        } 

        /// 
        /// 
        ///    Gets the style of lines drawn with this 
        /// .
        ///  
        public PenType PenType 
        {
            get { 
                int type = -1;

                int status = SafeNativeMethods.Gdip.GdipGetPenFillType(new HandleRef(this, this.NativePen), out type);
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status); 
 
                return(PenType)type;
            } 
        }

        /// 
        ///  
        ///    
        ///       Gets or sets the color of this . 
        ///     
        /// 
        public Color Color { 
            get {
                if (color == Color.Empty) {
                    int colorARGB = 0;
                    int status = SafeNativeMethods.Gdip.GdipGetPenColor(new HandleRef(this, this.NativePen), out colorARGB); 

                    if (status != SafeNativeMethods.Gdip.Ok) 
                        throw SafeNativeMethods.Gdip.StatusException(status); 

                    this.color = Color.FromArgb(colorARGB); 
                }

                // GDI+ doesn't understand system colors, so we can't use GdipGetPenColor in the general case
                return this.color; 
            }
 
            set { 
                if (immutable)
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen")); 

                if( value != this.color )
                {
                    Color oldColor = this.color; 
                    this.color = value;
                    InternalSetColor(value); 
 
                    //
 
                    if (value.IsSystemColor && !oldColor.IsSystemColor)
                        SystemColorTracker.Add(this);
                }
            } 
        }
 
        ///  
        /// 
        ///    Gets or sets the  that 
        ///    determines attributes of this .
        /// 
        public Brush Brush {
            get { 
                Brush brush = null;
 
                switch (PenType) { 
                    case PenType.SolidColor:
                        brush = new SolidBrush(GetNativeBrush()); 
                        break;

                    case PenType.HatchFill:
                        brush = new HatchBrush(GetNativeBrush()); 
                        break;
 
                    case PenType.TextureFill: 
                        brush = new TextureBrush(GetNativeBrush());
                        break; 

                    case PenType.PathGradient:
                        brush = new PathGradientBrush(GetNativeBrush());
                        break; 

                    case PenType.LinearGradient: 
                        brush = new LinearGradientBrush(GetNativeBrush()); 
                        break;
 
                    default:
                        break;
                }
 
                return brush;
            } 
 
            set {
                if (immutable) 
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen"));

                if (value == null)
                    throw new ArgumentNullException("value"); 

                int status = SafeNativeMethods.Gdip.GdipSetPenBrushFill(new HandleRef(this, this.NativePen), 
                    new HandleRef(value, value.NativeBrush)); 

                if (status != SafeNativeMethods.Gdip.Ok) 
                    throw SafeNativeMethods.Gdip.StatusException(status);
            }
        }
 
        private IntPtr GetNativeBrush()
        { 
            IntPtr nativeBrush = IntPtr.Zero; 

            int status = SafeNativeMethods.Gdip.GdipGetPenBrushFill(new HandleRef(this, this.NativePen), out nativeBrush); 

            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
 
            return nativeBrush;
        } 
 
        /**
         * Set/get dash attributes 
         */
        /// 
        /// 
        ///    Gets or sets the style used for dashed 
        ///    lines drawn with this .
        ///  
        public DashStyle DashStyle 
        {
            get { 
                int dashstyle = 0;

                int status = SafeNativeMethods.Gdip.GdipGetPenDashStyle(new HandleRef(this, this.NativePen), out dashstyle);
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status); 
 
                return(DashStyle) dashstyle;
            } 

            set {

                //valid values are 0x0 to 0x5 
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)DashStyle.Solid, (int)DashStyle.Custom))
                { 
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(DashStyle)); 
                }
 
                if (immutable)
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen"));

                int status = SafeNativeMethods.Gdip.GdipSetPenDashStyle(new HandleRef(this, this.NativePen), (int)value); 

                if (status != SafeNativeMethods.Gdip.Ok) { 
                    throw SafeNativeMethods.Gdip.StatusException(status); 
                }
 
                //if we just set pen style to "custom" without defining the custom dash pattern,
                //lets make sure we can return a valid value...
                //
                if (value == DashStyle.Custom) { 
                    EnsureValidDashPattern();
                } 
            } 
        }
 
        /// 
        /// 
        ///    This method is called after the user sets the pen's dash style to custom.
        ///    Here, we make sure that there is a default value set for the custom pattern. 
        /// 
        private void EnsureValidDashPattern() { 
            int retval = 0; 
            int status = SafeNativeMethods.Gdip.GdipGetPenDashCount(new HandleRef(this, this.NativePen), out retval);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);

            if (retval == 0) { 
                //just set to a solid pattern
                DashPattern = new float[]{1}; 
            } 
        }
 
        /// 
        /// 
        ///    Gets or sets the distance from the start of
        ///    a line to the beginning of a dash pattern. 
        /// 
        public float DashOffset 
        { 
            get {
                float[] dashoffset = new float[] { 0}; 

                int status = SafeNativeMethods.Gdip.GdipGetPenDashOffset(new HandleRef(this, this.NativePen), dashoffset);

                if (status != SafeNativeMethods.Gdip.Ok) 
                    throw SafeNativeMethods.Gdip.StatusException(status);
 
                return dashoffset[0]; 
            }
            set { 
                if (immutable)
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen"));

                int status = SafeNativeMethods.Gdip.GdipSetPenDashOffset(new HandleRef(this, this.NativePen), value); 

                if (status != SafeNativeMethods.Gdip.Ok) 
                    throw SafeNativeMethods.Gdip.StatusException(status); 
            }
        } 

        /// 
        /// 
        ///     
        ///       Gets or sets an array of cutom dashes and
        ///       spaces. The dashes are made up of line segments. 
        ///     
        /// 
        public float[] DashPattern 
        {
            get {
                float[] dashArray;
 
                // Figure out how many dash elements we have
 
                int retval = 0; 
                int status = SafeNativeMethods.Gdip.GdipGetPenDashCount(new HandleRef(this, this.NativePen), out retval);
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status);

                int count = retval; 

                // Allocate temporary native memory buffer 
                // and pass it to GDI+ to retrieve dash array elements 

                IntPtr buf = Marshal.AllocHGlobal(4 * count); 
                status = SafeNativeMethods.Gdip.GdipGetPenDashArray(new HandleRef(this, this.NativePen), buf, count);

                try {
                    if (status != SafeNativeMethods.Gdip.Ok) { 
                        throw SafeNativeMethods.Gdip.StatusException(status);
                    } 
 
                    dashArray = new float[count];
 
                    Marshal.Copy(buf, dashArray, 0, count);
                }
                finally {
                    Marshal.FreeHGlobal(buf); 
                }
 
                return dashArray; 
            }
 
            set {
                if (immutable)
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen"));
 

                //validate the DashPattern value being set 
                if (value ==  null || value.Length == 0) { 
                    throw new ArgumentException(SR.GetString(SR.InvalidDashPattern));
                } 

                int count = value.Length;

                IntPtr buf = Marshal.AllocHGlobal(4 * count); 

                try { 
                    Marshal.Copy(value, 0, buf, count); 

                    int status = SafeNativeMethods.Gdip.GdipSetPenDashArray(new HandleRef(this, this.NativePen), new HandleRef(buf, buf), count); 

                    if (status != SafeNativeMethods.Gdip.Ok){
                        throw SafeNativeMethods.Gdip.StatusException(status);
                    } 
                }
                finally { 
                    Marshal.FreeHGlobal(buf); 
                }
            } 
        }

        /// 
        ///  
        ///    Gets or sets an array of cutom dashes and
        ///    spaces. The dashes are made up of line segments. 
        ///  
        public float[] CompoundArray
        { 
            get {
                int count = 0;

                int status = SafeNativeMethods.Gdip.GdipGetPenCompoundCount(new HandleRef(this, this.NativePen), out count); 

                if (status != SafeNativeMethods.Gdip.Ok) 
                    throw SafeNativeMethods.Gdip.StatusException(status); 

                float[] array = new float[count]; 

                status = SafeNativeMethods.Gdip.GdipGetPenCompoundArray(new HandleRef(this, this.NativePen), array, count);
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status); 

                return array; 
            } 
            set {
                if (immutable) 
                    throw new ArgumentException(SR.GetString(SR.CantChangeImmutableObjects, "Pen"));

                int status = SafeNativeMethods.Gdip.GdipSetPenCompoundArray(new HandleRef(this, this.NativePen), value, value.Length);
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status); 
            } 
        }
 
        /// 
        /// 
        void ISystemColorTracker.OnSystemColorChanged() {
            if (this.NativePen != IntPtr.Zero) 
                InternalSetColor(color);
        } 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

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