File: winforms\Managed\System\WinForms\WinFormsUtils.cs
Project: ndp\fx\src\System.Windows.Forms.csproj (System.Windows.Forms)
//------------------------------------------------------------------------------
// <copyright file="WinFormsUtils.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
 
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Scope="member", Target="System.Windows.Forms.WindowsFormsUtils..ctor()")]
 
/*
 */
namespace System.Windows.Forms {
    using System.Runtime.Serialization.Formatters;
    using System.Runtime.Remoting;
    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis;
    using System;
    using System.Security;
    using System.Security.Permissions;
    using System.Globalization;
    using System.Windows.Forms;
    using System.Drawing.Design;
    using System.ComponentModel;
    using System.Windows.Forms.ComponentModel;
    using System.Collections;
    using System.Drawing;
    using System.Windows.Forms.Internal;
    using Microsoft.Win32;
    using System.Text;
    using Util = NativeMethods.Util;
    using System.Runtime.InteropServices;
    using System.Runtime.Versioning;
    using System.Reflection;
    
    // Miscellaneous Windows Forms utilities
    internal sealed class WindowsFormsUtils {
 
        // A better initializer than Size.Empty to force code using uninitialized to noticably fail.
        public static readonly Size UninitializedSize = new Size(-7199369, -5999471);
        private static bool _targetsAtLeast_v4_5 = RunningOnCheck("TargetsAtLeast_Desktop_V4_5");
 
        
        public static readonly ContentAlignment AnyRightAlign   = ContentAlignment.TopRight | ContentAlignment.MiddleRight | ContentAlignment.BottomRight;
        public static readonly ContentAlignment AnyLeftAlign    = ContentAlignment.TopLeft | ContentAlignment.MiddleLeft | ContentAlignment.BottomLeft;
        public static readonly ContentAlignment AnyTopAlign     = ContentAlignment.TopLeft | ContentAlignment.TopCenter | ContentAlignment.TopRight;
        public static readonly ContentAlignment AnyBottomAlign  = ContentAlignment.BottomLeft | ContentAlignment.BottomCenter | ContentAlignment.BottomRight;
        public static readonly ContentAlignment AnyMiddleAlign  = ContentAlignment.MiddleLeft | ContentAlignment.MiddleCenter | ContentAlignment.MiddleRight;
        public static readonly ContentAlignment AnyCenterAlign  = ContentAlignment.TopCenter | ContentAlignment.MiddleCenter | ContentAlignment.BottomCenter;
 
        ///
        /// The GetMessagePos function retrieves the cursor position for the last message 
        /// retrieved by the GetMessage function. 
        ///
        public static Point LastCursorPoint  {
            get {
                int lastXY = SafeNativeMethods.GetMessagePos();
                return new Point(NativeMethods.Util.SignedLOWORD(lastXY),NativeMethods.Util.SignedHIWORD(lastXY)) ;
            }
        }
 
        /// this graphics requires disposal.
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        public static Graphics CreateMeasurementGraphics() {
            return Graphics.FromHdcInternal(WindowsGraphicsCacheManager.MeasurementGraphics.DeviceContext.Hdc);
        }
       
        // If you want to know if a piece of text contains one and only one &
        // this is your function.  If you have a character "t" and want match it to &Text
        // Control.IsMnemonic is a better bet.
        public static bool ContainsMnemonic(string text) {      
            if (text != null) {
                int textLength = text.Length;
                int firstAmpersand = text.IndexOf('&', 0);
                if (firstAmpersand >=0 && firstAmpersand <= /*second to last char=*/textLength -2) {
                    // we found one ampersand and it's either the first character
                    // or the second to last character
                    // or a character in between
 
                    // We're so close!  make sure we don't have a double ampersand now.
                    int secondAmpersand = text.IndexOf('&', firstAmpersand+1);
                    if (secondAmpersand == -1) {
                        // didn't find a second one in the string.
                        return true;
                    }            
                }
            }
            return false;
        }
 
        internal static Rectangle ConstrainToScreenWorkingAreaBounds(Rectangle bounds) {
            return ConstrainToBounds(Screen.GetWorkingArea(bounds), bounds);
        }
 
        ///<devdoc> given a rectangle, constrain it to fit onto the current screen.
        ///</devdoc>
        internal static Rectangle ConstrainToScreenBounds(Rectangle bounds) {
            return ConstrainToBounds(Screen.FromRectangle(bounds).Bounds, bounds);
        }
 
        internal static Rectangle ConstrainToBounds(Rectangle constrainingBounds, Rectangle bounds) {
            // use screen instead of SystemInformation.WorkingArea for better multimon support.
            if (!constrainingBounds.Contains(bounds)) {
                // make sure size does not exceed working area.
                bounds.Size = new Size(Math.Min(constrainingBounds.Width -2, bounds.Width), 
                                       Math.Min(constrainingBounds.Height -2, bounds.Height));
                 
                // X calculations
                //
                // scooch so it will fit on the screen.
                if (bounds.Right > constrainingBounds.Right) {
                    // its too far to the right.
                    bounds.X = constrainingBounds.Right - bounds.Width;
                }
                else if (bounds.Left < constrainingBounds.Left) {
                    // its too far to the left.
                    bounds.X = constrainingBounds.Left;
                }
 
                // Y calculations
                //
                // scooch so it will fit on the screen.
                if (bounds.Bottom > constrainingBounds.Bottom) {
                     // its too far to the bottom.
                     bounds.Y = constrainingBounds.Bottom - 1 - bounds.Height;
                }
                else if (bounds.Top < constrainingBounds.Top) {
                     // its too far to the top.
                     bounds.Y = constrainingBounds.Top;
                }
            }
            return bounds; 
        }
 
#if DEBUG_FOCUS
        /// <devdoc> 
        /// FOCUS debugging code.  This is really handy if you stick it in Application.Idle event.
        /// It will watch when the focus has changed and will print out the new guy who's gotten focus.
        /// If it is an unmanaged window, it will report the window text.  You'll need to #define DEBUG_FOCUS 
        /// or use something like /define:DEBUG_FOCUS in the CSC_FLAGS and either sync the 
        /// Application.Idle event or stick this in Application.FDoIdle.
        ///
        /// This can be used in conjunction with the ControlKeyboardRouting trace switch to debug keyboard
        /// handling problems.  See Control.cs.
        /// </devdoc>
        [ThreadStatic]
        private static IntPtr lastFocusHwnd = IntPtr.Zero;
        internal static DebugFocus() {
            IntPtr focusHwnd = UnsafeNativeMethods.GetFocus();
            if (focusHwnd != lastFocusHwnd) {
                   lastFocusHwnd = focusHwnd;
                   if (focusHwnd != IntPtr.Zero) {
                       Debug.WriteLine("FOCUS watch: new focus: " + focusHwnd.ToString() +GetControlInformation(focusHwnd)  );
                   }
                   else {
                       Debug.WriteLine("FOCUS watch: no one has focus");
                   }
            }
            return false;
        }
#endif
 
        //
        // adds an extra & to to the text so that Fish & Chips can be displayed on a menu item without underlining 
        // anything. This is used in MDIWindowList as we use the MDIChildForm.Text as menu item text. 
        //  Fish & Chips --> Fish && Chips
        internal static string EscapeTextWithAmpersands(string text) {
            if (text == null) {
                return null;
            }
 
            int index = text.IndexOf('&');
    
            if (index == -1) {
                return text;
            }
    
            StringBuilder str = new StringBuilder(text.Substring(0, index));
            for(; index < text.Length; ++index) {
                if (text[index] == '&') {
                    str.Append("&");
                }
                if (index < text.Length) {
                    str.Append(text[index]);
                }
            }
            return str.ToString();
        }
 
        // helper function for generating information about a particular control
        // use AssertControlInformation if sticking in an assert - then the work
        // to figure out the control info will only be done when the assertion is false.
        internal static string GetControlInformation(IntPtr hwnd) {
            if (hwnd == IntPtr.Zero) {
                return "Handle is IntPtr.Zero";
            }
            string ret = ""; // in RETAIL just return empty string
#if DEBUG      
            try {
                 int textLen = SafeNativeMethods.GetWindowTextLength(new HandleRef(null, hwnd));
                 StringBuilder sb = new StringBuilder(textLen+1);
                 UnsafeNativeMethods.GetWindowText(new HandleRef(null, hwnd), sb, sb.Capacity);
          
                 string typeOfControl = "Unknown";
                 string nameOfControl = "Name: ";
                 Control c = Control.FromHandle(hwnd);
                 if (c != null) {
                    typeOfControl = c.GetType().ToString();
                    if (!string.IsNullOrEmpty(c.Name)) {
                        nameOfControl += c.Name;
                    }
                    else {
                        nameOfControl += "Unknown";
                        
                        // some extra debug info for toolstripdropdowns...
                        if (c is ToolStripDropDown) {
                            ToolStripDropDown dd = c as ToolStripDropDown;
                            if (dd.OwnerItem != null) {
                                nameOfControl += "\r\n\tOwnerItem: " + dd.OwnerItem.ToString();
                            }
                        }
                    }
                 }
                 ret =  sb.ToString() + "\r\n\tType: " + typeOfControl + "\r\n\t" + nameOfControl + "\r\n";
            }
            catch (SecurityException) {
                // some suites run under DEBUG - just eat this exception
            }
#endif            
            return ret;
        }
 
        // only fetch the information on a false assertion.
        internal static string AssertControlInformation(bool condition, Control control) {
            if (condition) {
                return string.Empty;
            }
            else {
                return GetControlInformation(control.Handle);
            }
        }
        
        // Algorithm suggested by Damien Morton
        internal static int GetCombinedHashCodes(params int[] args)
        {
            const int k = -1640531535;
            int h = -757577119;
            for (int i = 0; i < args.Length; i++)
            {
                h = (args[i] ^ h) * k;
            }
            return h;
        }
 
        // Retrieves the mnemonic from a given string, or zero if no mnemonic.
        // As used by the Control.Mnemonic to get mnemonic from Control.Text.
        //
        // Boolean argument determines whether returned char is converted to upper
        // case or lower case (always one or the other - case is never preserved).
        public static char GetMnemonic(string text, bool bConvertToUpperCase) {
            char mnemonic = (char)0;
 
            if (text != null) {
                int len = text.Length;
                for (int i = 0; i < len - 1; i++) {
                    if (text[i] == '&') {
                        if (text[i + 1] == '&')
                        {
                            // we have an escaped &, so we need to skip it.
                            //
                            i++;
                            continue;
                        }
                        if (bConvertToUpperCase) {
                            mnemonic = Char.ToUpper(text[i+1], CultureInfo.CurrentCulture);
                        }
                        else {
                            mnemonic = Char.ToLower(text[i+1], CultureInfo.CurrentCulture);
                        }
                        break;
                    }
                }
            }
            return mnemonic;
        }
 
        // for a given handle, finds the toplevel handle
        public static HandleRef GetRootHWnd(HandleRef hwnd) {
            IntPtr rootHwnd = UnsafeNativeMethods.GetAncestor(new HandleRef(hwnd, hwnd.Handle), NativeMethods.GA_ROOT);
            return new HandleRef(hwnd.Wrapper, rootHwnd);                      
        }
 
        // for a given control, finds the toplevel handle
        public static HandleRef GetRootHWnd(Control control) {
            return GetRootHWnd(new HandleRef(control, control.Handle));                      
        }
 
        // Strips all keyboard mnemonic prefixes from a given string, eg. turning "He&lp" into "Help".
        // Note: Be careful not to call this multiple times on the same string, otherwise you'll turn
        // something like "Fi&sh && Chips" into "Fish & Chips" on the first call, and then "Fish Chips"
        // on the second call.
        public static string TextWithoutMnemonics(string text) {
            if (text == null) {
                return null;
            }
 
            int index = text.IndexOf('&');
 
            if (index == -1) {
                return text;
            }
 
            StringBuilder str = new StringBuilder(text.Substring(0, index));
            for(; index < text.Length; ++index) {
                if (text[index] == '&') {
                    index++;    // Skip this & and copy the next character instead
                }
                if (index < text.Length) {
                    str.Append(text[index]);
                }
            }
            return str.ToString();
        }
 
 
        /// Translates a point from one control's coordinate system to the other
        /// same as:
        ///         controlTo.PointToClient(controlFrom.PointToScreen(point))
        /// but slightly more performant.
        public static Point TranslatePoint(Point point, Control fromControl, Control toControl) {
            NativeMethods.POINT pt = new NativeMethods.POINT(point.X, point.Y);
            UnsafeNativeMethods.MapWindowPoints(new HandleRef(fromControl, fromControl.Handle), new HandleRef(toControl, toControl.Handle), pt, 1);
            return new Point(pt.x, pt.y);   
        }
     
 
        // Compares the strings using invariant culture for Turkish-I support.  Returns true if they match.
        // 
        // If your strings are symbolic (returned from APIs, not from user) the following calls
        // are faster than this method:
        // 
        //  String.Equals(s1, s2, StringComparison.Ordinal)
        //  String.Equals(s1, s2, StringComparison.OrdinalIgnoreCase)
        //
        public static bool SafeCompareStrings(string string1, string string2, bool ignoreCase) {
	        if ((string1 == null) || (string2 == null)) {
                 // if either key is null, we should return false
                 return false;
            }
 
            // Because String.Compare returns an ordering, it can not terminate early if lengths are not the same.
            // Also, equivalent characters can be encoded in different byte sequences, so it can not necessarily
            // terminate on the first byte which doesn't match.  Hence this optimization.
            if (string1.Length != string2.Length) {
                return false;
            }
 
            return String.Compare(string1, string2, ignoreCase, CultureInfo.InvariantCulture) == 0;
        }
 
        // RotateLeft(0xFF000000, 4) -> 0xF000000F
        public static int RotateLeft(int value, int nBits) {
            Debug.Assert(Marshal.SizeOf(typeof(int)) == 4, "The impossible has happened.");
            
            nBits = nBits % 32;
            return value << nBits | (value >> (32 - nBits));
        }
 
        public static string GetComponentName(IComponent component, string defaultNameValue) {
            Debug.Assert(component != null, "component passed here cannot be null");
            string result = string.Empty;
            if (string.IsNullOrEmpty(defaultNameValue)) {
                if(component.Site != null) {
                    result = component.Site.Name;
                }
                if(result == null) {
                    result = string.Empty;
                }
            } else {
                result = defaultNameValue;
            }            
            return result;
        }
 
        public static class EnumValidator {
 
            // IsValidContentAlignment
            // Valid values are 0x001,0x002,0x004, 0x010,0x020,0x040, 0x100, 0x200,0x400
            // Method for verifying
            //   Verify that the number passed in has only one bit on
            //   Verify that the bit that is on is a valid bit by bitwise anding it to a mask.
            //
            public static bool IsValidContentAlignment(ContentAlignment contentAlign) {
                if (ClientUtils.GetBitCount((uint)contentAlign) != 1) {
                    return false;
                }
                // to calculate:
                // foreach (int val in Enum.GetValues(typeof(ContentAlignment))) { mask |= val; }
                int contentAlignmentMask = 0x777;
                return ((contentAlignmentMask & (int)contentAlign) != 0);
            }
 
            // IsEnumWithinShiftedRange
            // shifts off the number of bits specified by numBitsToShift 
            //   -  makes sure the bits we've shifted off are just zeros
            //   -  then compares if the resulting value is between minValAfterShift and maxValAfterShift
            //  
            // EXAMPLE:
            //    MessageBoxIcon.  Valid values are 0x0, 0x10, 0x20, 0x30, 0x40
            //    Method for verifying: chop off the last 0 by shifting right 4 bits, verify resulting number is between 0 & 4.
            //
            //  WindowsFormsUtils.EnumValidator.IsEnumWithinShiftedRange(icon, /*numBitsToShift*/4, /*min*/0x0,/*max*/0x4)
            //
            public static bool IsEnumWithinShiftedRange(Enum enumValue, int numBitsToShift, int minValAfterShift, int maxValAfterShift){            
                int iValue = Convert.ToInt32(enumValue, CultureInfo.InvariantCulture);
                int remainder = iValue >> numBitsToShift;
                if (remainder << numBitsToShift != iValue) {
                    // there were bits that we shifted out.
                    return false;
                }
                return (remainder >= minValAfterShift && remainder <= maxValAfterShift);
            }
 
            // IsValidTextImageRelation
            // valid values are 0,1,2,4,8
            // Method for verifying
            //   Verify that the number is between 0 and 8
            //   Verify that the bit that is on - thus forcing it to be a power of two.
            //          
            public static bool IsValidTextImageRelation(TextImageRelation relation) {
                return ClientUtils.IsEnumValid(relation, (int)relation, (int)TextImageRelation.Overlay, (int)TextImageRelation.TextBeforeImage,1);           
            }
 
            public static bool IsValidArrowDirection(ArrowDirection direction) {
                switch (direction) {
                    case ArrowDirection.Up:
                    case ArrowDirection.Down:
                    case ArrowDirection.Left:
                    case ArrowDirection.Right:
                        return true;
                    default:
                        return false;                        
                }
            }
        }
 
        // To enumerate over only part of an array.
        public class ArraySubsetEnumerator : IEnumerator {
            private object[] array; // Perhaps this should really be typed Array, but then we suffer a performance penalty.
            private int total;
            private int current;
 
            public ArraySubsetEnumerator(object[] array, int count) {
                Debug.Assert(count == 0 || array != null, "if array is null, count should be 0");
                Debug.Assert(array == null || count <= array.Length, "Trying to enumerate more than the array contains");
                this.array = array;
                this.total = count;
                current = -1;
            }
 
            public bool MoveNext() {
                if (current < total - 1) {
                    current++;
                    return true;
                }
                else
                    return false;
            }
 
            public void Reset() {
                current = -1;
            }
 
            public object Current {
                get {
                    if (current == -1)
                        return null;
                    else
                        return array[current];
                }
            }
        }
 
        /// <devdoc>
        ///     This is a ControlCollection which can be made readonly.  In readonly mode, this
        ///     ControlCollection throws NotSupportedExceptions for any operation that attempts
        ///     to modify the collection.
        /// </devdoc>
        internal class ReadOnlyControlCollection : Control.ControlCollection {
            
            private readonly bool _isReadOnly;
            
 
            public ReadOnlyControlCollection(Control owner, bool isReadOnly) : base(owner) {
                _isReadOnly = isReadOnly;
            }
 
            public override void Add(Control value) {
                if (IsReadOnly) {
                    throw new NotSupportedException(SR.GetString(SR.ReadonlyControlsCollection));
                }
                AddInternal(value);
            }
 
            internal virtual void AddInternal(Control value) {
                base.Add(value);
            }
 
            public override void Clear() {
                if (IsReadOnly) {
                    throw new NotSupportedException(SR.GetString(SR.ReadonlyControlsCollection));
                }
                base.Clear();
            }
 
            internal virtual void RemoveInternal(Control value) {
                base.Remove(value);
            }
            
            public override void RemoveByKey(string key) {
                if (IsReadOnly) {
                    throw new NotSupportedException(SR.GetString(SR.ReadonlyControlsCollection));
                }
                base.RemoveByKey(key);
            }
 
            public override bool IsReadOnly {
                get { return _isReadOnly; }
            }
        }
        
        /// <devdoc>
        /// This control collection only allows a specific type of control 
        /// into the controls collection.  It optionally supports readonlyness.
        /// </devdoc>
        internal class TypedControlCollection : ReadOnlyControlCollection {
             
            private Type typeOfControl;
            private Control ownerControl;
             
            public TypedControlCollection(Control owner, Type typeOfControl, bool isReadOnly) : base(owner, isReadOnly) {
                this.typeOfControl = typeOfControl;
                this.ownerControl = owner;
            }
 
            public TypedControlCollection(Control owner, Type typeOfControl) : base(owner, /*isReadOnly*/false) {
                this.typeOfControl = typeOfControl;
                this.ownerControl = owner;
            }
        
            public override void Add(Control value) {
                //Check parenting first for consistency
                Control.CheckParentingCycle(ownerControl, value);
 
                if (value == null) {
                    throw new ArgumentNullException("value");
                }
                if (IsReadOnly) {
                    throw new NotSupportedException(SR.GetString(SR.ReadonlyControlsCollection));
                }
                if (!typeOfControl.IsAssignableFrom(value.GetType())) {
                    throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, SR.GetString(SR.TypedControlCollectionShouldBeOfType, typeOfControl.Name)), value.GetType().Name);
                }
                base.Add(value);
            }
        }
 
        /// <devdoc>
        ///     DCMapping is used to change the mapping and clip region of the
        ///     the specified device context to the given bounds.  When the
        ///     DCMapping is disposed, the original mapping and clip rectangle
        ///     are restored.
        ///
        ///     Example:
        ///     
        ///     using(WindowsFormsUtils.DCMapping mapping = new WindowsFormsUtils.DCMapping(hDC, new Rectangle(10,10, 50, 50) {
        ///         // inside here the hDC's mapping of (0,0) is inset by (10,10) and 
        ///         // all painting is clipped at (0,0) - (50,50)
        ///      }
        ///       
        ///      To use with GDI+ you can get the hDC from the Graphics object.  You'd want to do this in a situation where
        ///      you're handing off a graphics object to someone, and you want the world translated some amount X,Y.  This 
        ///      works better than g.TranslateTransform(x,y) - as if someone calls g.GetHdc and does a GDI operation - their
        ///      world is NOT transformed.
        ///   
        ///      HandleRef hDC = new HandleRef(this, originalGraphics.GetHdc());
        ///      try {
        ///        using(WindowsFormsUtils.DCMapping mapping = new WindowsFormsUtils.DCMapping(hDC, new Rectangle(10,10, 50, 50) {
        ///            
        ///            // DO NOT ATTEMPT TO USE originalGraphics here - you'll get an Object Busy error
        ///            // rather ask the mapping object for a graphics object.
        ///            mapping.Graphics.DrawRectangle(Pens.Black, rect);
        ///        }     
        ///      }
        ///      finally { g.ReleaseHdc(hDC.Handle);}
        ///   
        ///      PERF: DCMapping is a structure so that it will allocate on the stack rather than in GC managed
        ///      memory.  This way disposing the object does not force a GC.  Since DCMapping objects aren't 
        ///      likely to be passed between functions rather used and disposed in the same one, this reduces 
        ///      overhead.
        /// </devdoc>     
        internal struct DCMapping : IDisposable {
                
            private DeviceContext dc;
            private Graphics graphics;
            Rectangle translatedBounds;
 
            [ResourceExposure(ResourceScope.Process)]
            [ResourceConsumption(ResourceScope.Process)]
            public DCMapping(HandleRef hDC, Rectangle bounds) {
                if (hDC.Handle == IntPtr.Zero) {
                    throw new ArgumentNullException("hDC");
                }
 
                bool success;
                NativeMethods.POINT viewportOrg              = new NativeMethods.POINT();
                HandleRef hOriginalClippingRegion            = NativeMethods.NullHandleRef;
                NativeMethods.RegionFlags originalRegionType = NativeMethods.RegionFlags.NULLREGION;
                
                this.translatedBounds = bounds;
                this.graphics         = null;
                this.dc               = DeviceContext.FromHdc(hDC.Handle);
 
                this.dc.SaveHdc();
 
                // Retrieve the x-coordinates and y-coordinates of the viewport origin for the specified device context. 
                success = SafeNativeMethods.GetViewportOrgEx(hDC, viewportOrg);
                Debug.Assert(success, "GetViewportOrgEx() failed.");
 
                // Create a new rectangular clipping region based off of the bounds specified, shifted over by the x & y specified in the viewport origin.
                HandleRef hClippingRegion = new HandleRef(null, SafeNativeMethods.CreateRectRgn(viewportOrg.x + bounds.Left, viewportOrg.y + bounds.Top, viewportOrg.x + bounds.Right, viewportOrg.y + bounds.Bottom));
                Debug.Assert(hClippingRegion.Handle != IntPtr.Zero, "CreateRectRgn() failed.");
 
                try
                {
                    // Create an empty region oriented at 0,0 so we can populate it with the original clipping region of the hDC passed in.
                    hOriginalClippingRegion = new HandleRef(this, SafeNativeMethods.CreateRectRgn(0, 0, 0, 0));
                    Debug.Assert(hOriginalClippingRegion.Handle != IntPtr.Zero, "CreateRectRgn() failed.");
 
                    // Get the clipping region from the hDC: result = {-1 = error, 0 = no region, 1 = success} per MSDN
                    int result = SafeNativeMethods.GetClipRgn(hDC, hOriginalClippingRegion);
                    Debug.Assert(result != -1, "GetClipRgn() failed.");
 
                    // Shift the viewpoint origint by coordinates specified in "bounds". 
                    NativeMethods.POINT lastViewPort = new NativeMethods.POINT();
                    success = SafeNativeMethods.SetViewportOrgEx(hDC, viewportOrg.x + bounds.Left, viewportOrg.y + bounds.Top, lastViewPort);
                    Debug.Assert(success, "SetViewportOrgEx() failed.");
 
                    if (result != 0)
                    {
                        // Get the origninal clipping region so we can determine its type (we'll check later if we've restored the region back properly.)
                        NativeMethods.RECT originalClipRect = new NativeMethods.RECT();
                        originalRegionType = (NativeMethods.RegionFlags)SafeNativeMethods.GetRgnBox(hOriginalClippingRegion, ref originalClipRect);
                        Debug.Assert(originalRegionType != NativeMethods.RegionFlags.ERROR, "ERROR returned from SelectClipRgn while selecting the original clipping region..");
 
                        if (originalRegionType == NativeMethods.RegionFlags.SIMPLEREGION)
                        {
                            // Find the intersection of our clipping region and the current clipping region (our parent's)
                            //      Returns a NULLREGION, the two didn't intersect.
                            //      Returns a SIMPLEREGION, the two intersected
                            //      Resulting region (stuff that was in hOriginalClippingRegion AND hClippingRegion is placed in hClippingRegion
                            NativeMethods.RegionFlags combineResult = (NativeMethods.RegionFlags)SafeNativeMethods.CombineRgn(hClippingRegion, hClippingRegion, hOriginalClippingRegion, NativeMethods.RGN_AND);
                            Debug.Assert((combineResult == NativeMethods.RegionFlags.SIMPLEREGION) ||
                                            (combineResult == NativeMethods.RegionFlags.NULLREGION),
                                            "SIMPLEREGION or NULLREGION expected.");
                        }
                    }
                    else
                    {
                        // If there was no clipping region, then the result is a simple region.
                        // We don't need to keep track of the original now, since it is empty.
                        SafeNativeMethods.DeleteObject(hOriginalClippingRegion);
                        hOriginalClippingRegion = new HandleRef(null, IntPtr.Zero);
                        originalRegionType = NativeMethods.RegionFlags.SIMPLEREGION;
                    }
 
                    // Select the new clipping region; make sure it's a SIMPLEREGION or NULLREGION
                    NativeMethods.RegionFlags selectResult = (NativeMethods.RegionFlags)SafeNativeMethods.SelectClipRgn(hDC, hClippingRegion);
                    Debug.Assert((selectResult == NativeMethods.RegionFlags.SIMPLEREGION ||
                                  selectResult == NativeMethods.RegionFlags.NULLREGION),
                                  "SIMPLEREGION or NULLLREGION expected.");
 
                }
                catch (Exception ex)
                {
                    if (ClientUtils.IsSecurityOrCriticalException(ex))
                    {
                        throw;
                    }
 
                    this.dc.RestoreHdc();
                    this.dc.Dispose();
                }
                finally {
                    // Delete the new clipping region, as the clipping region for the HDC is now set 
                    // to this rectangle.  Hold on to hOriginalClippingRegion, as we'll need to restore
                    // it when this object is disposed.
                    success = SafeNativeMethods.DeleteObject(hClippingRegion);
                    Debug.Assert(success, "DeleteObject(hClippingRegion) failed.");
 
                    if (hOriginalClippingRegion.Handle != IntPtr.Zero) {
                        success = SafeNativeMethods.DeleteObject(hOriginalClippingRegion);
                        Debug.Assert(success, "DeleteObject(hOriginalClippingRegion) failed.");
                    }
                }
            }
        
            public void Dispose() {
                if( graphics != null ){
                    // Reset GDI+ if used.
                    // we need to dispose the graphics object first, as it will do 
                    // some restoration to the ViewPort and ClipRectangle to restore the hDC to 
                    // the same state it was created in
                    graphics.Dispose();
                    graphics = null;
                }
 
                if (this.dc != null) {
                    // Now properly reset GDI.
                    this.dc.RestoreHdc();
                    this.dc.Dispose();
                    this.dc = null;
                }
            }
 
            /// <devdoc>
            /// Allows you to get the graphics object based off of the translated HDC.
            /// Note this will be disposed when the DCMapping object is disposed.
            /// </devdoc>
            [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
            public Graphics Graphics {
                [ResourceExposure(ResourceScope.Process)]
                [ResourceConsumption(ResourceScope.Process)]
                get {
                    Debug.Assert(this.dc != null, "unexpected null dc!");
 
                    if (this.graphics == null) {
                        this.graphics = Graphics.FromHdcInternal(dc.Hdc);
                        this.graphics.SetClip(new Rectangle(Point.Empty, translatedBounds.Size));
                    }
                    return this.graphics;
                }
            }
        }
        // All 4.x version of the .NET framework are installed in place. For compatibility reasons, we
        // want to know when an application is targeting netfx 4.5 or later vs 4.0
        internal static bool TargetsAtLeast_v4_5 {
            get {
                return _targetsAtLeast_v4_5;
            }
        }
 
        [SecuritySafeCritical]
        [ReflectionPermission(SecurityAction.Assert, Unrestricted = true)]
        private static bool RunningOnCheck(string propertyName) {
            Type binaryCompatibitlityType;
            try {
                binaryCompatibitlityType = typeof(Object).GetTypeInfo().Assembly.GetType("System.Runtime.Versioning.BinaryCompatibility", false);
            }
            catch (TypeLoadException) {
                return false;
            }
 
            if (binaryCompatibitlityType == null) {
                return false;
            }
 
            PropertyInfo runningOnV4_5_Property = binaryCompatibitlityType.GetProperty(propertyName, Reflection.BindingFlags.Public | Reflection.BindingFlags.NonPublic | Reflection.BindingFlags.Static);
            if (runningOnV4_5_Property == null) {
                return false;
            }
 
            return (bool)runningOnV4_5_Property.GetValue(null);
        }
    }
    
}