Pen.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / CommonUI / System / Drawing / Pen.cs / 1305376 / 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;
    using System.Runtime.Versioning; 

    /// 
    /// 
    ///      
    ///         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 ); 
        } 

 
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        internal Pen(Color color, bool immutable) : this(color) {
            this.immutable = immutable; 
        }
 
        ///  
        /// 
        ///     
        ///       Initializes a new instance of the Pen
        ///       class with the specified .
        ///    
        ///  
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)] 
        public Pen(Color color) : this(color, (float)1.0) { 
        }
 
        /// 
        /// 
        ///    
        ///       Initializes a new instance of the   class with the specified 
        ///        and .
        ///  
        ///  
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)] 
        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 . 
        ///     
        /// 
        [ResourceExposure(ResourceScope.Process)] 
        [ResourceConsumption(ResourceScope.Process)]
        public Pen(Brush brush) : this(brush, (float)1.0) {
        }
 
        /// 
        ///  
        ///     
        ///       Initializes a new instance of the  class with
        ///       the specified  and width. 
        ///    
        /// 
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)] 
        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 
        {
            [System.Runtime.TargetedPatchingOptOutAttribute("Performance critical to inline across NGen image boundaries")] 
            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 .
        ///  
        [ResourceExposure(ResourceScope.Process)] 
        [ResourceConsumption(ResourceScope.Process)]
        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;
    using System.Runtime.Versioning; 

    /// 
    /// 
    ///      
    ///         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 ); 
        } 

 
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        internal Pen(Color color, bool immutable) : this(color) {
            this.immutable = immutable; 
        }
 
        ///  
        /// 
        ///     
        ///       Initializes a new instance of the Pen
        ///       class with the specified .
        ///    
        ///  
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)] 
        public Pen(Color color) : this(color, (float)1.0) { 
        }
 
        /// 
        /// 
        ///    
        ///       Initializes a new instance of the   class with the specified 
        ///        and .
        ///  
        ///  
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)] 
        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 . 
        ///     
        /// 
        [ResourceExposure(ResourceScope.Process)] 
        [ResourceConsumption(ResourceScope.Process)]
        public Pen(Brush brush) : this(brush, (float)1.0) {
        }
 
        /// 
        ///  
        ///     
        ///       Initializes a new instance of the  class with
        ///       the specified  and width. 
        ///    
        /// 
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)] 
        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 
        {
            [System.Runtime.TargetedPatchingOptOutAttribute("Performance critical to inline across NGen image boundaries")] 
            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 .
        ///  
        [ResourceExposure(ResourceScope.Process)] 
        [ResourceConsumption(ResourceScope.Process)]
        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