DeviceContext.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / fx / src / Misc / GDI / DeviceContext.cs / 5 / DeviceContext.cs

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

//#define TRACK_HDC 
//#define GDI_FINALIZATION_WATCH 

#if WINFORMS_NAMESPACE 
namespace System.Windows.Forms.Internal
#elif DRAWING_NAMESPACE
namespace System.Drawing.Internal
#else 
namespace System.Experimental.Gdi
#endif 
{ 
    using System;
    using System.Collections; 
    using System.Internal;
    using System.Security;
    using System.Runtime.InteropServices;
    using System.Diagnostics; 
    using System.ComponentModel;
    using System.Drawing; 
    using System.Diagnostics.CodeAnalysis; 
    using System.Globalization;
 
    /// 
    /// 
    ///     Represents a Win32 device context.  Provides operations for setting some of the properties
    ///     of a device context.  It's the managed wrapper for an HDC. 
    ///
    ///     This class is divided into two files separating the code that needs to be compiled into 
    ///     reatail builds and debugging code. 
    /// 
#if WINFORMS_PUBLIC_GRAPHICS_LIBRARY 
    public
#else
    internal
#endif 
    sealed partial class DeviceContext : MarshalByRefObject, IDeviceContext, IDisposable
    { 
        ///  
        ///     This class is a wrapper to a Win32 device context, and the Hdc property is the way to get a
        ///     handle to it. 
        ///
        ///     The hDc is released/deleted only when owned by the object, meaning it was created internally;
        ///     in this case, the object is responsible for releasing/deleting it.
        ///     In the case the object is created from an exisiting hdc, it is not released; this is consistent 
        ///     with the Win32 guideline that says if you call GetDC/CreateDC/CreatIC/CreateEnhMetafile, you are
        ///     responsible for calling ReleaseDC/DeleteDC/DeleteEnhMetafile respectivelly. 
        /// 
        ///     This class implements some of the operations commonly performed on the properties of a dc  in WinForms,
        ///     specially for interacting with GDI+, like clipping and coordinate transformation. 
        ///     Several properties are not persisted in the dc but instead they are set/reset during a more comprehensive
        ///     operation like text rendering or painting; for instance text alignment is set and reset during DrawText (GDI),
        ///     DrawString (GDI+).
        /// 
        ///     Other properties are persisted from operation to operation until they are reset, like clipping,
        ///     one can make several calls to Graphics or WindowsGraphics obect after setting the dc clip area and 
        ///     before resetting it; these kinds of properties are the ones implemented in this class. 
        ///     This kind of properties place an extra chanllenge in the scenario where a DeviceContext is obtained
        ///     from a Graphics object that has been used with GDI+, because GDI+ saves the hdc internally, rendering the 
        ///     DeviceContext underlying hdc out of [....].  DeviceContext needs to support these kind of properties to
        ///     be able to keep the GDI+ and GDI HDCs in [....].
        ///
        ///     A few other persisting properties have been implemented in DeviceContext2, among them: 
        ///     1. Window origin.
        ///     2. Bounding rectangle. 
        ///     3. DC origin. 
        ///     4. View port extent.
        ///     5. View port origin. 
        ///     6. Window extent
        ///
        ///     Other non-persisted properties just for information: Background/Forground color, Palette, Color adjustment,
        ///     Color space, ICM mode and profile, Current pen position, Binary raster op (not supported by GDI+), 
        ///     Background mode, Logical Pen, DC pen color, ARc direction, Miter limit, Logical brush, DC brush color,
        ///     Brush origin, Polygon filling mode, Bitmap stretching mode, Logical font, Intercharacter spacing, 
        ///     Font mapper flags, Text alignment, Test justification, Layout, Path, Meta region. 
        ///     See book "Windows Graphics Programming - Feng Yuang", P315 - Device Context Attributes.
        ///  

        [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
        IntPtr hDC;
        DeviceContextType dcType; 

        public event EventHandler Disposing; 
 
        bool disposed;
 
        // We cache the hWnd when creating the dc from one, to provide support forIDeviceContext.GetHdc/ReleaseHdc.
        // This hWnd could be null, in such case it is referring to the screen.
        [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
        IntPtr hWnd = (IntPtr) (-1); // Unlikely to be a valid hWnd. 

        IntPtr hInitialPen; 
        IntPtr hInitialBrush; 
        IntPtr hInitialBmp;
        IntPtr hInitialFont; 

        IntPtr hCurrentPen;
        IntPtr hCurrentBrush;
        IntPtr hCurrentBmp; 
        IntPtr hCurrentFont;
 
        Stack  contextStack; 

#if GDI_FINALIZATION_WATCH 
        private string AllocationSite = DbgUtil.StackTrace;
        private string DeAllocationSite = "";
#endif
 
        ///
        /// Class properties... 
        /// 

        ///  
        ///     Specifies whether a modification has been applied to the dc, like setting the clipping area or a coordinate transform.
        /// 

        ///  
        ///     The device type the context refers to.
        ///  
        public DeviceContextType DeviceContextType 
        {
            get 
            {
                return this.dcType;
            }
        } 

        ///  
        ///     This object's hdc.  If this property is called, then the object will be used as an HDC wrapper, 
        ///     so the hdc is cached and calls to GetHdc/ReleaseHdc won't PInvoke into GDI.
        ///     Call Dispose to properly release the hdc. 
        /// 
        public IntPtr Hdc
        {
            get 
            {
                if( this.hDC == IntPtr.Zero ) 
                { 
                    if( this.dcType == DeviceContextType.Display )
                    { 
                        Debug.Assert(!this.disposed, "Accessing a disposed DC, forcing recreation of HDC - this will generate a Handle leak!");

                        // Note: ReleaseDC must be called from the same thread. This applies only to HDC obtained
                        // from calling GetDC. This means Display DeviceContext objects should never be finalized. 
                        this.hDC = ((IDeviceContext)this).GetHdc();  // this.hDC will be released on call to Dispose.
                        CacheInitialState(); 
                    } 
#if GDI_FINALIZATION_WATCH
                    else 
                    {
                        try { Debug.WriteLine(string.Format("Allocation stack:\r\n{0}\r\nDeallocation stack:\r\n{1}", AllocationSite, DeAllocationSite)); } catch  {}
                    }
#endif 
                }
 
                Debug.Assert( this.hDC != IntPtr.Zero, "Attempt to use deleted HDC - DC type: " + this.dcType ); 

                return this.hDC; 
            }
        }

        // VSWhidbey 536325 
        // Due to a problem with calling DeleteObject() on currently selected GDI objects,
        // we now track the initial set of objects when a DeviceContext is created.  Then, 
        // we also track which objects are currently selected in the DeviceContext.  When 
        // a currently selected object is disposed, it is first replaced in the DC and then
        // deleted. 

        private void CacheInitialState()
        {
            Debug.Assert(this.hDC != IntPtr.Zero, "Cannot get initial state without a valid HDC"); 
            hCurrentPen   = hInitialPen   = IntUnsafeNativeMethods.GetCurrentObject(new HandleRef(this, hDC), IntNativeMethods.OBJ_PEN);
            hCurrentBrush = hInitialBrush = IntUnsafeNativeMethods.GetCurrentObject(new HandleRef(this, hDC), IntNativeMethods.OBJ_BRUSH); 
            hCurrentBmp   = hInitialBmp   = IntUnsafeNativeMethods.GetCurrentObject(new HandleRef(this, hDC), IntNativeMethods.OBJ_BITMAP); 
            hCurrentFont  = hInitialFont  = IntUnsafeNativeMethods.GetCurrentObject(new HandleRef(this, hDC), IntNativeMethods.OBJ_FONT);
        } 

        public void DeleteObject(IntPtr handle, GdiObjectType type) {
            IntPtr handleToDelete = IntPtr.Zero;
            switch (type) { 
                case GdiObjectType.Pen:
                    if (handle == hCurrentPen) { 
                        IntPtr currentPen = IntUnsafeNativeMethods.SelectObject(new HandleRef(this, this.Hdc), new HandleRef( this, hInitialPen)); 
                        Debug.Assert(currentPen == hCurrentPen, "DeviceContext thinks a different pen is selected than the HDC");
                        hCurrentPen = IntPtr.Zero; 
                    }
                    handleToDelete = handle;
                    break;
                case GdiObjectType.Brush: 
                    if (handle == hCurrentBrush) {
                        IntPtr currentBrush = IntUnsafeNativeMethods.SelectObject(new HandleRef(this, this.Hdc), new HandleRef( this, hInitialBrush)); 
                        Debug.Assert(currentBrush == hCurrentBrush, "DeviceContext thinks a different brush is selected than the HDC"); 
                        hCurrentBrush = IntPtr.Zero;
                    } 
                    handleToDelete = handle;
                    break;
                case GdiObjectType.Bitmap:
                    if (handle == hCurrentBmp) { 
                        IntPtr currentBmp = IntUnsafeNativeMethods.SelectObject(new HandleRef(this, this.Hdc), new HandleRef( this, hInitialBmp));
                        Debug.Assert(currentBmp == hCurrentBmp, "DeviceContext thinks a different brush is selected than the HDC"); 
                        hCurrentBmp = IntPtr.Zero; 
                    }
                    handleToDelete = handle; 
                    break;
            }

            IntUnsafeNativeMethods.DeleteObject(new HandleRef(this, handleToDelete)); 
        }
 
        // 
        // object construction API.  Publicly constructable from static methods only.
        // 

        /// 
        ///     Constructor to contruct a DeviceContext object from an window handle.
        ///  
        private DeviceContext(IntPtr hWnd)
        { 
            this.hWnd   = hWnd; 
            this.dcType = DeviceContextType.Display;
 
            DeviceContexts.AddDeviceContext(this);

            // the hDc will be created on demand.
 
#if TRACK_HDC
            Debug.WriteLine( DbgUtil.StackTraceToStr(String.Format( "DeviceContext( hWnd=0x{0:x8} )", (int) hWnd))); 
#endif 
        }
 
        /// 
        ///     Constructor to contruct a DeviceContext object from an existing Win32 device context handle.
        /// 
        private DeviceContext(IntPtr hDC, DeviceContextType dcType) 
        {
            this.hDC    = hDC; 
            this.dcType = dcType; 

            CacheInitialState(); 
            DeviceContexts.AddDeviceContext(this);

            if( dcType == DeviceContextType.Display )
            { 
                this.hWnd = IntUnsafeNativeMethods.WindowFromDC( new HandleRef( this, this.hDC) );
            } 
#if TRACK_HDC 
            Debug.WriteLine( DbgUtil.StackTraceToStr( String.Format("DeviceContext( hDC=0x{0:X8}, Type={1} )", (int) hDC, dcType) ));
#endif 
        }

        //
 

        // 
 

        ///  
        ///     CreateDC creates a DeviceContext object wrapping an hdc created with the Win32 CreateDC function.
        /// 
        public static DeviceContext CreateDC(string driverName, string deviceName, string fileName, HandleRef devMode)
        { 
            // Note: All input params can be null but not at the same time.  See MSDN for information.
 
            IntPtr hdc = IntUnsafeNativeMethods.CreateDC(driverName, deviceName, fileName, devMode); 
            return new DeviceContext( hdc, DeviceContextType.NamedDevice );
        } 

        /// 
        ///     CreateIC creates a DeviceContext object wrapping an hdc created with the Win32 CreateIC function.
        ///  
        public static DeviceContext CreateIC(string driverName, string deviceName, string fileName, HandleRef devMode)
        { 
            // Note: All input params can be null but not at the same time.  See MSDN for information. 

            IntPtr hdc = IntUnsafeNativeMethods.CreateIC(driverName, deviceName, fileName, devMode); 
            return new DeviceContext( hdc, DeviceContextType.Information );
        }

        ///  
        ///     Creates a DeviceContext object wrapping a memory DC compatible with the specified device.
        ///  
        public static DeviceContext FromCompatibleDC(IntPtr hdc) 
        {
 

            // If hdc is null, the function creates a memory DC compatible with the application's current screen.
            // Win2K+: (See CreateCompatibleDC in the MSDN).
            // In this case the thread that calls CreateCompatibleDC owns the HDC that is created. When this thread is destroyed, 
            // the HDC is no longer valid.
 
            IntPtr compatibleDc = IntUnsafeNativeMethods.CreateCompatibleDC( new HandleRef(null, hdc) ); 
            return new DeviceContext(compatibleDc, DeviceContextType.Memory);
        } 

        /// 
        /// 
        ///     Used for wrapping an existing hdc.  In this case, this object doesn't own the hdc 
        ///     so calls to GetHdc/ReleaseHdc don't PInvoke into GDI.
        ///  
        public static DeviceContext FromHdc(IntPtr hdc) 
        {
            Debug.Assert( hdc != IntPtr.Zero, "hdc == 0" ); 
            return new DeviceContext(hdc, DeviceContextType.Unknown);
        }

        ///  
        /// 
        ///     When hwnd is null, we are getting the screen DC. 
        ///  
        public static DeviceContext FromHwnd( IntPtr hwnd )
        { 
            return new DeviceContext(hwnd);
        }

 
        /// 
        ~DeviceContext() 
        { 
            Dispose(false);
        } 

        /// 
        public void Dispose()
        { 
            Dispose(true);
            GC.SuppressFinalize(this); 
        } 

        ///  
        internal void Dispose(bool disposing)
        {
            if (disposed)
            { 
                return;
            } 
 
            if (this.Disposing != null)
            { 
                this.Disposing(this, EventArgs.Empty);
            }

            this.disposed = true; 

#if !DRAWING_NAMESPACE 
            DisposeFont(disposing); 
#endif
 
            switch( this.dcType )
            {
                case DeviceContextType.Display:
                    Debug.Assert( disposing, "WARNING: Finalizing a Display DeviceContext.\r\nReleaseDC may fail when not called from the same thread GetDC was called from." ); 

                    ((IDeviceContext)this).ReleaseHdc(); 
                    break; 

                case DeviceContextType.Information: 
                case DeviceContextType.NamedDevice:

                    // CreateDC and CreateIC add an HDC handle to the HandleCollector; to remove it properly we need
                    // to call DeleteHDC. 
#if TRACK_HDC
                    Debug.WriteLine( DbgUtil.StackTraceToStr( String.Format("DC.DeleteHDC(hdc=0x{0:x8})", (int) this.hDC))); 
#endif 

                    IntUnsafeNativeMethods.DeleteHDC(new HandleRef(this, this.hDC)); 

                    this.hDC = IntPtr.Zero;
                    break;
 
                case DeviceContextType.Memory:
 
                    // CreatCompatibleDC adds a GDI handle to HandleCollector, to remove it properly we need to call 
                    // DeleteDC.
#if TRACK_HDC 
                    Debug.WriteLine( DbgUtil.StackTraceToStr( String.Format("DC.DeleteDC(hdc=0x{0:x8})", (int) this.hDC)));
#endif
                    IntUnsafeNativeMethods.DeleteDC(new HandleRef(this, this.hDC));
 
                    this.hDC = IntPtr.Zero;
                    break; 
 
                // case DeviceContextType.Metafile: - not yet supported.
#if WINFORMS_PUBLIC_GRAPHICS_LIBRARY 
                case DeviceContextType.Metafile:
                    IntUnsafeNativeMethods.CloseEnhMetaFile(new HandleRef(this, this.Hdc));

                    this.hDC = IntPtr.Zero; 
                    break;
#endif 
                case DeviceContextType.Unknown: 
                default:
                    return; 
                    // do nothing, the hdc is not owned by this object.
                    // in this case it is ok if disposed throught finalization.
            }
 
            DbgUtil.AssertFinalization(this, disposing);
        } 
 
        /// 
        ///  
        ///     Explicit interface method implementation to hide them a bit for usability reasons so the object is seen
        ///     as a wrapper around an hdc that is always available, and for performance reasons since it caches the hdc
        ///     if used in this way.
        ///  
        IntPtr IDeviceContext.GetHdc()
        { 
            if (this.hDC == IntPtr.Zero) 
            {
                Debug.Assert( this.dcType == DeviceContextType.Display, "Calling GetDC from a non display/window device." ); 

                // Note: for common DCs, GetDC assigns default attributes to the DC each time it is retrieved.
                // For example, the default font is System.
                this.hDC = IntUnsafeNativeMethods.GetDC(new HandleRef(this, this.hWnd)); 
#if TRACK_HDC
                Debug.WriteLine( DbgUtil.StackTraceToStr( String.Format("hdc[0x{0:x8}]=DC.GetHdc(hWnd=0x{1:x8})", (int) this.hDC, (int) this.hWnd))); 
#endif 
            }
 
            return this.hDC;
        }

 
        /// 
        /// 
        ///     If the object was created from a DC, this object doesn't 'own' the dc so we just ignore 
        ///     this call.
        /// 
        void IDeviceContext.ReleaseHdc()
        {
            if (this.hDC != IntPtr.Zero && this.dcType == DeviceContextType.Display)
            { 
#if TRACK_HDC
                int retVal = 
#endif 
                IntUnsafeNativeMethods.ReleaseDC(new HandleRef(this, this.hWnd), new HandleRef(this, this.hDC));
                // Note: retVal == 0 means it was not released but doesn't necessarily means an error; class or private DCs are never released. 
#if TRACK_HDC
                Debug.WriteLine( DbgUtil.StackTraceToStr( String.Format("[ret={0}]=DC.ReleaseDC(hDc=0x{1:x8}, hWnd=0x{2:x8})", retVal, (int) this.hDC, (int) this.hWnd)));
#endif
                this.hDC = IntPtr.Zero; 
            }
        } 
 

        ///  
        ///     Specifies whether the DC is in GM_ADVANCE mode (supported only in NT platforms).
        ///     If false, it is in GM_COMPATIBLE mode.
        /// 
        public DeviceContextGraphicsMode GraphicsMode 
        {
            get 
            { 
                return (DeviceContextGraphicsMode) IntUnsafeNativeMethods.GetGraphicsMode( new HandleRef( this, this.Hdc ) );
            } 
#if WINFORMS_PUBLIC_GRAPHICS_LIBRARY
            set
            {
                SetGraphicsMode(value); 
            }
#endif 
        } 

        ///  
        ///     Sets the dc graphics mode and returns the old value.
        /// 
        public DeviceContextGraphicsMode SetGraphicsMode( DeviceContextGraphicsMode newMode )
        { 
            return (DeviceContextGraphicsMode) IntUnsafeNativeMethods.SetGraphicsMode( new HandleRef( this, this.Hdc ), (int) newMode );
        } 
 
        /// 
        ///     Restores the device context to the specified state. The DC is restored by popping state information off a 
        ///     stack created by earlier calls to the SaveHdc function.
        ///     The stack can contain the state information for several instances of the DC. If the state specified by the
        ///     specified parameter is not at the top of the stack, RestoreDC deletes all state information between the top
        ///     of the stack and the specified instance. 
        ///     Specifies the saved state to be restored. If this parameter is positive, nSavedDC represents a specific
        ///     instance of the state to be restored. If this parameter is negative, nSavedDC represents an instance relative 
        ///     to the current state. For example, -1 restores the most recently saved state. 
        ///     See MSDN for more info.
        ///  
        public void RestoreHdc()
        {
#if TRACK_HDC
            bool result = 
#endif
            // Note: Don't use the Hdc property here, it would force handle creation. 
            IntUnsafeNativeMethods.RestoreDC(new HandleRef(this, this.hDC), -1); 
#if TRACK_HDC
            // Note: Winforms may call this method during app exit at which point the DC may have been finalized already causing this assert to popup. 
            Debug.WriteLine( DbgUtil.StackTraceToStr( String.Format("ret[0]=DC.RestoreHdc(hDc=0x{1:x8}, state={2})", result, (int) this.hDC, restoreState) ));
#endif
            Debug.Assert(contextStack != null, "Someone is calling RestoreHdc() before SaveHdc()");
 
            if (contextStack != null) {
                GraphicsState g = (GraphicsState) contextStack.Pop(); 
 
                hCurrentBmp     = g.hBitmap;
                hCurrentBrush   = g.hBrush; 
                hCurrentPen     = g.hPen;
                hCurrentFont    = g.hFont;

#if !DRAWING_NAMESPACE 
                if (g.font != null && g.font.IsAlive) {
                    selectedFont    = g.font.Target as WindowsFont; 
                } 
                else {
                    WindowsFont previousFont = selectedFont; 
                    selectedFont = null;
                    if (previousFont != null && MeasurementDCInfo.IsMeasurementDC(this)) {
                        previousFont.Dispose();
                    } 
                }
#endif 
 
            }
 
#if OPTIMIZED_MEASUREMENTDC
            // in this case, GDI will copy back the previously saved font into the DC.
            // we dont actually know what the font is in our measurement DC so
            // we need to clear it off. 
            MeasurementDCInfo.ResetIfIsMeasurementDC(this.hDC);
#endif 
 
        }
 
        /// 
        ///     Saves the current state of the device context by copying data describing selected objects and graphic
        ///     modes (such as the bitmap, brush, palette, font, pen, region, drawing mode, and mapping mode) to a
        ///     context stack. 
        ///     The SaveDC function can be used any number of times to save any number of instances of the DC state.
        ///     A saved state can be restored by using the RestoreHdc method. 
        ///     See MSDN for more details. 
        /// 
        public int SaveHdc() 
        {
            HandleRef hdc = new HandleRef( this, this.Hdc);
            int state = IntUnsafeNativeMethods.SaveDC(hdc);
 
            if (contextStack == null) {
                contextStack = new Stack(); 
            } 

            GraphicsState g = new GraphicsState(); 
            g.hBitmap = hCurrentBmp;
            g.hBrush  = hCurrentBrush;
            g.hPen    = hCurrentPen;
            g.hFont   = hCurrentFont; 

#if !DRAWING_NAMESPACE 
            g.font    = new WeakReference(selectedFont); 
#endif
 

            contextStack.Push(g);

#if TRACK_HDC 
            Debug.WriteLine( DbgUtil.StackTraceToStr( String.Format("state[0]=DC.SaveHdc(hDc=0x{1:x8})", state, (int) this.hDC) ));
#endif 
 
            return state;
        } 

        /// 
        ///     Selects a region as the current clipping region for the device context.
        ///     Remarks (From MSDN): 
        ///         - Only a copy of the selected region is used. The region itself can be selected for any number of other device contexts or it can be deleted.
        ///         - The SelectClipRgn function assumes that the coordinates for a region are specified in device units. 
        ///         - To remove a device-context's clipping region, specify a NULL region handle. 
        /// 
        public void SetClip(WindowsRegion region) 
        {
            HandleRef hdc = new HandleRef(this, this.Hdc);
            HandleRef hRegion = new HandleRef(region, region.HRegion);
 
            IntUnsafeNativeMethods.SelectClipRgn(hdc, hRegion);
        } 
 
        ///
        ///     Creates a new clipping region from the intersection of the current clipping region and 
        ///     the specified rectangle.
        ///
        public void IntersectClip(WindowsRegion wr)
        { 
            //if the incoming windowsregion is infinite, there is no need to do any intersecting.
            if (wr.HRegion == IntPtr.Zero) { 
                return; 
            }
 
            WindowsRegion clip = new WindowsRegion(0,0,0,0);
            try {
                 int result = IntUnsafeNativeMethods.GetClipRgn(new HandleRef( this, this.Hdc), new HandleRef(clip, clip.HRegion));
 
                 // If the function succeeds and there is a clipping region for the given device context, the return value is 1.
                 if (result == 1) { 
                     Debug.Assert(clip.HRegion != IntPtr.Zero); 
                     wr.CombineRegion(clip, wr, RegionCombineMode.AND); //1 = AND (or Intersect)
                 } 

                 SetClip(wr);
            }
            finally { 
                 clip.Dispose();
            } 
        } 

        ///  
        ///     Modifies the viewport origin for a device context using the specified horizontal and vertical offsets in logical units.
        /// 
        public void TranslateTransform(int dx, int dy)
        { 
            IntNativeMethods.POINT orgn = new IntNativeMethods.POINT();
            IntUnsafeNativeMethods.OffsetViewportOrgEx( new HandleRef( this, this.Hdc ), dx, dy, orgn ); 
        } 

        ///  
        /// 
        public override bool Equals(object obj)
        {
            DeviceContext other = obj as DeviceContext; 

            if (other == this) 
            { 
                return true;
            } 

            if (other == null)
            {
                return false; 
            }
 
            // Note: Use property instead of field so the HDC is initialized.  Also, this avoid serialization issues (the obj could be a proxy that does not have access to private fields). 
            return other.Hdc == this.Hdc;
        } 

        /// 
        ///     This allows collections to treat DeviceContext objects wrapping the same HDC as the same objects.
        ///  
        public override int GetHashCode()
        { 
            return this.Hdc.GetHashCode(); 
        }
 

        internal class GraphicsState {
            internal IntPtr hBrush;
            internal IntPtr hFont; 
            internal IntPtr hPen;
            internal IntPtr hBitmap; 
#if !DRAWING_NAMESPACE 
            internal WeakReference font;
#endif 
        }
     }
}

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

//#define TRACK_HDC 
//#define GDI_FINALIZATION_WATCH 

#if WINFORMS_NAMESPACE 
namespace System.Windows.Forms.Internal
#elif DRAWING_NAMESPACE
namespace System.Drawing.Internal
#else 
namespace System.Experimental.Gdi
#endif 
{ 
    using System;
    using System.Collections; 
    using System.Internal;
    using System.Security;
    using System.Runtime.InteropServices;
    using System.Diagnostics; 
    using System.ComponentModel;
    using System.Drawing; 
    using System.Diagnostics.CodeAnalysis; 
    using System.Globalization;
 
    /// 
    /// 
    ///     Represents a Win32 device context.  Provides operations for setting some of the properties
    ///     of a device context.  It's the managed wrapper for an HDC. 
    ///
    ///     This class is divided into two files separating the code that needs to be compiled into 
    ///     reatail builds and debugging code. 
    /// 
#if WINFORMS_PUBLIC_GRAPHICS_LIBRARY 
    public
#else
    internal
#endif 
    sealed partial class DeviceContext : MarshalByRefObject, IDeviceContext, IDisposable
    { 
        ///  
        ///     This class is a wrapper to a Win32 device context, and the Hdc property is the way to get a
        ///     handle to it. 
        ///
        ///     The hDc is released/deleted only when owned by the object, meaning it was created internally;
        ///     in this case, the object is responsible for releasing/deleting it.
        ///     In the case the object is created from an exisiting hdc, it is not released; this is consistent 
        ///     with the Win32 guideline that says if you call GetDC/CreateDC/CreatIC/CreateEnhMetafile, you are
        ///     responsible for calling ReleaseDC/DeleteDC/DeleteEnhMetafile respectivelly. 
        /// 
        ///     This class implements some of the operations commonly performed on the properties of a dc  in WinForms,
        ///     specially for interacting with GDI+, like clipping and coordinate transformation. 
        ///     Several properties are not persisted in the dc but instead they are set/reset during a more comprehensive
        ///     operation like text rendering or painting; for instance text alignment is set and reset during DrawText (GDI),
        ///     DrawString (GDI+).
        /// 
        ///     Other properties are persisted from operation to operation until they are reset, like clipping,
        ///     one can make several calls to Graphics or WindowsGraphics obect after setting the dc clip area and 
        ///     before resetting it; these kinds of properties are the ones implemented in this class. 
        ///     This kind of properties place an extra chanllenge in the scenario where a DeviceContext is obtained
        ///     from a Graphics object that has been used with GDI+, because GDI+ saves the hdc internally, rendering the 
        ///     DeviceContext underlying hdc out of [....].  DeviceContext needs to support these kind of properties to
        ///     be able to keep the GDI+ and GDI HDCs in [....].
        ///
        ///     A few other persisting properties have been implemented in DeviceContext2, among them: 
        ///     1. Window origin.
        ///     2. Bounding rectangle. 
        ///     3. DC origin. 
        ///     4. View port extent.
        ///     5. View port origin. 
        ///     6. Window extent
        ///
        ///     Other non-persisted properties just for information: Background/Forground color, Palette, Color adjustment,
        ///     Color space, ICM mode and profile, Current pen position, Binary raster op (not supported by GDI+), 
        ///     Background mode, Logical Pen, DC pen color, ARc direction, Miter limit, Logical brush, DC brush color,
        ///     Brush origin, Polygon filling mode, Bitmap stretching mode, Logical font, Intercharacter spacing, 
        ///     Font mapper flags, Text alignment, Test justification, Layout, Path, Meta region. 
        ///     See book "Windows Graphics Programming - Feng Yuang", P315 - Device Context Attributes.
        ///  

        [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
        IntPtr hDC;
        DeviceContextType dcType; 

        public event EventHandler Disposing; 
 
        bool disposed;
 
        // We cache the hWnd when creating the dc from one, to provide support forIDeviceContext.GetHdc/ReleaseHdc.
        // This hWnd could be null, in such case it is referring to the screen.
        [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
        IntPtr hWnd = (IntPtr) (-1); // Unlikely to be a valid hWnd. 

        IntPtr hInitialPen; 
        IntPtr hInitialBrush; 
        IntPtr hInitialBmp;
        IntPtr hInitialFont; 

        IntPtr hCurrentPen;
        IntPtr hCurrentBrush;
        IntPtr hCurrentBmp; 
        IntPtr hCurrentFont;
 
        Stack  contextStack; 

#if GDI_FINALIZATION_WATCH 
        private string AllocationSite = DbgUtil.StackTrace;
        private string DeAllocationSite = "";
#endif
 
        ///
        /// Class properties... 
        /// 

        ///  
        ///     Specifies whether a modification has been applied to the dc, like setting the clipping area or a coordinate transform.
        /// 

        ///  
        ///     The device type the context refers to.
        ///  
        public DeviceContextType DeviceContextType 
        {
            get 
            {
                return this.dcType;
            }
        } 

        ///  
        ///     This object's hdc.  If this property is called, then the object will be used as an HDC wrapper, 
        ///     so the hdc is cached and calls to GetHdc/ReleaseHdc won't PInvoke into GDI.
        ///     Call Dispose to properly release the hdc. 
        /// 
        public IntPtr Hdc
        {
            get 
            {
                if( this.hDC == IntPtr.Zero ) 
                { 
                    if( this.dcType == DeviceContextType.Display )
                    { 
                        Debug.Assert(!this.disposed, "Accessing a disposed DC, forcing recreation of HDC - this will generate a Handle leak!");

                        // Note: ReleaseDC must be called from the same thread. This applies only to HDC obtained
                        // from calling GetDC. This means Display DeviceContext objects should never be finalized. 
                        this.hDC = ((IDeviceContext)this).GetHdc();  // this.hDC will be released on call to Dispose.
                        CacheInitialState(); 
                    } 
#if GDI_FINALIZATION_WATCH
                    else 
                    {
                        try { Debug.WriteLine(string.Format("Allocation stack:\r\n{0}\r\nDeallocation stack:\r\n{1}", AllocationSite, DeAllocationSite)); } catch  {}
                    }
#endif 
                }
 
                Debug.Assert( this.hDC != IntPtr.Zero, "Attempt to use deleted HDC - DC type: " + this.dcType ); 

                return this.hDC; 
            }
        }

        // VSWhidbey 536325 
        // Due to a problem with calling DeleteObject() on currently selected GDI objects,
        // we now track the initial set of objects when a DeviceContext is created.  Then, 
        // we also track which objects are currently selected in the DeviceContext.  When 
        // a currently selected object is disposed, it is first replaced in the DC and then
        // deleted. 

        private void CacheInitialState()
        {
            Debug.Assert(this.hDC != IntPtr.Zero, "Cannot get initial state without a valid HDC"); 
            hCurrentPen   = hInitialPen   = IntUnsafeNativeMethods.GetCurrentObject(new HandleRef(this, hDC), IntNativeMethods.OBJ_PEN);
            hCurrentBrush = hInitialBrush = IntUnsafeNativeMethods.GetCurrentObject(new HandleRef(this, hDC), IntNativeMethods.OBJ_BRUSH); 
            hCurrentBmp   = hInitialBmp   = IntUnsafeNativeMethods.GetCurrentObject(new HandleRef(this, hDC), IntNativeMethods.OBJ_BITMAP); 
            hCurrentFont  = hInitialFont  = IntUnsafeNativeMethods.GetCurrentObject(new HandleRef(this, hDC), IntNativeMethods.OBJ_FONT);
        } 

        public void DeleteObject(IntPtr handle, GdiObjectType type) {
            IntPtr handleToDelete = IntPtr.Zero;
            switch (type) { 
                case GdiObjectType.Pen:
                    if (handle == hCurrentPen) { 
                        IntPtr currentPen = IntUnsafeNativeMethods.SelectObject(new HandleRef(this, this.Hdc), new HandleRef( this, hInitialPen)); 
                        Debug.Assert(currentPen == hCurrentPen, "DeviceContext thinks a different pen is selected than the HDC");
                        hCurrentPen = IntPtr.Zero; 
                    }
                    handleToDelete = handle;
                    break;
                case GdiObjectType.Brush: 
                    if (handle == hCurrentBrush) {
                        IntPtr currentBrush = IntUnsafeNativeMethods.SelectObject(new HandleRef(this, this.Hdc), new HandleRef( this, hInitialBrush)); 
                        Debug.Assert(currentBrush == hCurrentBrush, "DeviceContext thinks a different brush is selected than the HDC"); 
                        hCurrentBrush = IntPtr.Zero;
                    } 
                    handleToDelete = handle;
                    break;
                case GdiObjectType.Bitmap:
                    if (handle == hCurrentBmp) { 
                        IntPtr currentBmp = IntUnsafeNativeMethods.SelectObject(new HandleRef(this, this.Hdc), new HandleRef( this, hInitialBmp));
                        Debug.Assert(currentBmp == hCurrentBmp, "DeviceContext thinks a different brush is selected than the HDC"); 
                        hCurrentBmp = IntPtr.Zero; 
                    }
                    handleToDelete = handle; 
                    break;
            }

            IntUnsafeNativeMethods.DeleteObject(new HandleRef(this, handleToDelete)); 
        }
 
        // 
        // object construction API.  Publicly constructable from static methods only.
        // 

        /// 
        ///     Constructor to contruct a DeviceContext object from an window handle.
        ///  
        private DeviceContext(IntPtr hWnd)
        { 
            this.hWnd   = hWnd; 
            this.dcType = DeviceContextType.Display;
 
            DeviceContexts.AddDeviceContext(this);

            // the hDc will be created on demand.
 
#if TRACK_HDC
            Debug.WriteLine( DbgUtil.StackTraceToStr(String.Format( "DeviceContext( hWnd=0x{0:x8} )", (int) hWnd))); 
#endif 
        }
 
        /// 
        ///     Constructor to contruct a DeviceContext object from an existing Win32 device context handle.
        /// 
        private DeviceContext(IntPtr hDC, DeviceContextType dcType) 
        {
            this.hDC    = hDC; 
            this.dcType = dcType; 

            CacheInitialState(); 
            DeviceContexts.AddDeviceContext(this);

            if( dcType == DeviceContextType.Display )
            { 
                this.hWnd = IntUnsafeNativeMethods.WindowFromDC( new HandleRef( this, this.hDC) );
            } 
#if TRACK_HDC 
            Debug.WriteLine( DbgUtil.StackTraceToStr( String.Format("DeviceContext( hDC=0x{0:X8}, Type={1} )", (int) hDC, dcType) ));
#endif 
        }

        //
 

        // 
 

        ///  
        ///     CreateDC creates a DeviceContext object wrapping an hdc created with the Win32 CreateDC function.
        /// 
        public static DeviceContext CreateDC(string driverName, string deviceName, string fileName, HandleRef devMode)
        { 
            // Note: All input params can be null but not at the same time.  See MSDN for information.
 
            IntPtr hdc = IntUnsafeNativeMethods.CreateDC(driverName, deviceName, fileName, devMode); 
            return new DeviceContext( hdc, DeviceContextType.NamedDevice );
        } 

        /// 
        ///     CreateIC creates a DeviceContext object wrapping an hdc created with the Win32 CreateIC function.
        ///  
        public static DeviceContext CreateIC(string driverName, string deviceName, string fileName, HandleRef devMode)
        { 
            // Note: All input params can be null but not at the same time.  See MSDN for information. 

            IntPtr hdc = IntUnsafeNativeMethods.CreateIC(driverName, deviceName, fileName, devMode); 
            return new DeviceContext( hdc, DeviceContextType.Information );
        }

        ///  
        ///     Creates a DeviceContext object wrapping a memory DC compatible with the specified device.
        ///  
        public static DeviceContext FromCompatibleDC(IntPtr hdc) 
        {
 

            // If hdc is null, the function creates a memory DC compatible with the application's current screen.
            // Win2K+: (See CreateCompatibleDC in the MSDN).
            // In this case the thread that calls CreateCompatibleDC owns the HDC that is created. When this thread is destroyed, 
            // the HDC is no longer valid.
 
            IntPtr compatibleDc = IntUnsafeNativeMethods.CreateCompatibleDC( new HandleRef(null, hdc) ); 
            return new DeviceContext(compatibleDc, DeviceContextType.Memory);
        } 

        /// 
        /// 
        ///     Used for wrapping an existing hdc.  In this case, this object doesn't own the hdc 
        ///     so calls to GetHdc/ReleaseHdc don't PInvoke into GDI.
        ///  
        public static DeviceContext FromHdc(IntPtr hdc) 
        {
            Debug.Assert( hdc != IntPtr.Zero, "hdc == 0" ); 
            return new DeviceContext(hdc, DeviceContextType.Unknown);
        }

        ///  
        /// 
        ///     When hwnd is null, we are getting the screen DC. 
        ///  
        public static DeviceContext FromHwnd( IntPtr hwnd )
        { 
            return new DeviceContext(hwnd);
        }

 
        /// 
        ~DeviceContext() 
        { 
            Dispose(false);
        } 

        /// 
        public void Dispose()
        { 
            Dispose(true);
            GC.SuppressFinalize(this); 
        } 

        ///  
        internal void Dispose(bool disposing)
        {
            if (disposed)
            { 
                return;
            } 
 
            if (this.Disposing != null)
            { 
                this.Disposing(this, EventArgs.Empty);
            }

            this.disposed = true; 

#if !DRAWING_NAMESPACE 
            DisposeFont(disposing); 
#endif
 
            switch( this.dcType )
            {
                case DeviceContextType.Display:
                    Debug.Assert( disposing, "WARNING: Finalizing a Display DeviceContext.\r\nReleaseDC may fail when not called from the same thread GetDC was called from." ); 

                    ((IDeviceContext)this).ReleaseHdc(); 
                    break; 

                case DeviceContextType.Information: 
                case DeviceContextType.NamedDevice:

                    // CreateDC and CreateIC add an HDC handle to the HandleCollector; to remove it properly we need
                    // to call DeleteHDC. 
#if TRACK_HDC
                    Debug.WriteLine( DbgUtil.StackTraceToStr( String.Format("DC.DeleteHDC(hdc=0x{0:x8})", (int) this.hDC))); 
#endif 

                    IntUnsafeNativeMethods.DeleteHDC(new HandleRef(this, this.hDC)); 

                    this.hDC = IntPtr.Zero;
                    break;
 
                case DeviceContextType.Memory:
 
                    // CreatCompatibleDC adds a GDI handle to HandleCollector, to remove it properly we need to call 
                    // DeleteDC.
#if TRACK_HDC 
                    Debug.WriteLine( DbgUtil.StackTraceToStr( String.Format("DC.DeleteDC(hdc=0x{0:x8})", (int) this.hDC)));
#endif
                    IntUnsafeNativeMethods.DeleteDC(new HandleRef(this, this.hDC));
 
                    this.hDC = IntPtr.Zero;
                    break; 
 
                // case DeviceContextType.Metafile: - not yet supported.
#if WINFORMS_PUBLIC_GRAPHICS_LIBRARY 
                case DeviceContextType.Metafile:
                    IntUnsafeNativeMethods.CloseEnhMetaFile(new HandleRef(this, this.Hdc));

                    this.hDC = IntPtr.Zero; 
                    break;
#endif 
                case DeviceContextType.Unknown: 
                default:
                    return; 
                    // do nothing, the hdc is not owned by this object.
                    // in this case it is ok if disposed throught finalization.
            }
 
            DbgUtil.AssertFinalization(this, disposing);
        } 
 
        /// 
        ///  
        ///     Explicit interface method implementation to hide them a bit for usability reasons so the object is seen
        ///     as a wrapper around an hdc that is always available, and for performance reasons since it caches the hdc
        ///     if used in this way.
        ///  
        IntPtr IDeviceContext.GetHdc()
        { 
            if (this.hDC == IntPtr.Zero) 
            {
                Debug.Assert( this.dcType == DeviceContextType.Display, "Calling GetDC from a non display/window device." ); 

                // Note: for common DCs, GetDC assigns default attributes to the DC each time it is retrieved.
                // For example, the default font is System.
                this.hDC = IntUnsafeNativeMethods.GetDC(new HandleRef(this, this.hWnd)); 
#if TRACK_HDC
                Debug.WriteLine( DbgUtil.StackTraceToStr( String.Format("hdc[0x{0:x8}]=DC.GetHdc(hWnd=0x{1:x8})", (int) this.hDC, (int) this.hWnd))); 
#endif 
            }
 
            return this.hDC;
        }

 
        /// 
        /// 
        ///     If the object was created from a DC, this object doesn't 'own' the dc so we just ignore 
        ///     this call.
        /// 
        void IDeviceContext.ReleaseHdc()
        {
            if (this.hDC != IntPtr.Zero && this.dcType == DeviceContextType.Display)
            { 
#if TRACK_HDC
                int retVal = 
#endif 
                IntUnsafeNativeMethods.ReleaseDC(new HandleRef(this, this.hWnd), new HandleRef(this, this.hDC));
                // Note: retVal == 0 means it was not released but doesn't necessarily means an error; class or private DCs are never released. 
#if TRACK_HDC
                Debug.WriteLine( DbgUtil.StackTraceToStr( String.Format("[ret={0}]=DC.ReleaseDC(hDc=0x{1:x8}, hWnd=0x{2:x8})", retVal, (int) this.hDC, (int) this.hWnd)));
#endif
                this.hDC = IntPtr.Zero; 
            }
        } 
 

        ///  
        ///     Specifies whether the DC is in GM_ADVANCE mode (supported only in NT platforms).
        ///     If false, it is in GM_COMPATIBLE mode.
        /// 
        public DeviceContextGraphicsMode GraphicsMode 
        {
            get 
            { 
                return (DeviceContextGraphicsMode) IntUnsafeNativeMethods.GetGraphicsMode( new HandleRef( this, this.Hdc ) );
            } 
#if WINFORMS_PUBLIC_GRAPHICS_LIBRARY
            set
            {
                SetGraphicsMode(value); 
            }
#endif 
        } 

        ///  
        ///     Sets the dc graphics mode and returns the old value.
        /// 
        public DeviceContextGraphicsMode SetGraphicsMode( DeviceContextGraphicsMode newMode )
        { 
            return (DeviceContextGraphicsMode) IntUnsafeNativeMethods.SetGraphicsMode( new HandleRef( this, this.Hdc ), (int) newMode );
        } 
 
        /// 
        ///     Restores the device context to the specified state. The DC is restored by popping state information off a 
        ///     stack created by earlier calls to the SaveHdc function.
        ///     The stack can contain the state information for several instances of the DC. If the state specified by the
        ///     specified parameter is not at the top of the stack, RestoreDC deletes all state information between the top
        ///     of the stack and the specified instance. 
        ///     Specifies the saved state to be restored. If this parameter is positive, nSavedDC represents a specific
        ///     instance of the state to be restored. If this parameter is negative, nSavedDC represents an instance relative 
        ///     to the current state. For example, -1 restores the most recently saved state. 
        ///     See MSDN for more info.
        ///  
        public void RestoreHdc()
        {
#if TRACK_HDC
            bool result = 
#endif
            // Note: Don't use the Hdc property here, it would force handle creation. 
            IntUnsafeNativeMethods.RestoreDC(new HandleRef(this, this.hDC), -1); 
#if TRACK_HDC
            // Note: Winforms may call this method during app exit at which point the DC may have been finalized already causing this assert to popup. 
            Debug.WriteLine( DbgUtil.StackTraceToStr( String.Format("ret[0]=DC.RestoreHdc(hDc=0x{1:x8}, state={2})", result, (int) this.hDC, restoreState) ));
#endif
            Debug.Assert(contextStack != null, "Someone is calling RestoreHdc() before SaveHdc()");
 
            if (contextStack != null) {
                GraphicsState g = (GraphicsState) contextStack.Pop(); 
 
                hCurrentBmp     = g.hBitmap;
                hCurrentBrush   = g.hBrush; 
                hCurrentPen     = g.hPen;
                hCurrentFont    = g.hFont;

#if !DRAWING_NAMESPACE 
                if (g.font != null && g.font.IsAlive) {
                    selectedFont    = g.font.Target as WindowsFont; 
                } 
                else {
                    WindowsFont previousFont = selectedFont; 
                    selectedFont = null;
                    if (previousFont != null && MeasurementDCInfo.IsMeasurementDC(this)) {
                        previousFont.Dispose();
                    } 
                }
#endif 
 
            }
 
#if OPTIMIZED_MEASUREMENTDC
            // in this case, GDI will copy back the previously saved font into the DC.
            // we dont actually know what the font is in our measurement DC so
            // we need to clear it off. 
            MeasurementDCInfo.ResetIfIsMeasurementDC(this.hDC);
#endif 
 
        }
 
        /// 
        ///     Saves the current state of the device context by copying data describing selected objects and graphic
        ///     modes (such as the bitmap, brush, palette, font, pen, region, drawing mode, and mapping mode) to a
        ///     context stack. 
        ///     The SaveDC function can be used any number of times to save any number of instances of the DC state.
        ///     A saved state can be restored by using the RestoreHdc method. 
        ///     See MSDN for more details. 
        /// 
        public int SaveHdc() 
        {
            HandleRef hdc = new HandleRef( this, this.Hdc);
            int state = IntUnsafeNativeMethods.SaveDC(hdc);
 
            if (contextStack == null) {
                contextStack = new Stack(); 
            } 

            GraphicsState g = new GraphicsState(); 
            g.hBitmap = hCurrentBmp;
            g.hBrush  = hCurrentBrush;
            g.hPen    = hCurrentPen;
            g.hFont   = hCurrentFont; 

#if !DRAWING_NAMESPACE 
            g.font    = new WeakReference(selectedFont); 
#endif
 

            contextStack.Push(g);

#if TRACK_HDC 
            Debug.WriteLine( DbgUtil.StackTraceToStr( String.Format("state[0]=DC.SaveHdc(hDc=0x{1:x8})", state, (int) this.hDC) ));
#endif 
 
            return state;
        } 

        /// 
        ///     Selects a region as the current clipping region for the device context.
        ///     Remarks (From MSDN): 
        ///         - Only a copy of the selected region is used. The region itself can be selected for any number of other device contexts or it can be deleted.
        ///         - The SelectClipRgn function assumes that the coordinates for a region are specified in device units. 
        ///         - To remove a device-context's clipping region, specify a NULL region handle. 
        /// 
        public void SetClip(WindowsRegion region) 
        {
            HandleRef hdc = new HandleRef(this, this.Hdc);
            HandleRef hRegion = new HandleRef(region, region.HRegion);
 
            IntUnsafeNativeMethods.SelectClipRgn(hdc, hRegion);
        } 
 
        ///
        ///     Creates a new clipping region from the intersection of the current clipping region and 
        ///     the specified rectangle.
        ///
        public void IntersectClip(WindowsRegion wr)
        { 
            //if the incoming windowsregion is infinite, there is no need to do any intersecting.
            if (wr.HRegion == IntPtr.Zero) { 
                return; 
            }
 
            WindowsRegion clip = new WindowsRegion(0,0,0,0);
            try {
                 int result = IntUnsafeNativeMethods.GetClipRgn(new HandleRef( this, this.Hdc), new HandleRef(clip, clip.HRegion));
 
                 // If the function succeeds and there is a clipping region for the given device context, the return value is 1.
                 if (result == 1) { 
                     Debug.Assert(clip.HRegion != IntPtr.Zero); 
                     wr.CombineRegion(clip, wr, RegionCombineMode.AND); //1 = AND (or Intersect)
                 } 

                 SetClip(wr);
            }
            finally { 
                 clip.Dispose();
            } 
        } 

        ///  
        ///     Modifies the viewport origin for a device context using the specified horizontal and vertical offsets in logical units.
        /// 
        public void TranslateTransform(int dx, int dy)
        { 
            IntNativeMethods.POINT orgn = new IntNativeMethods.POINT();
            IntUnsafeNativeMethods.OffsetViewportOrgEx( new HandleRef( this, this.Hdc ), dx, dy, orgn ); 
        } 

        ///  
        /// 
        public override bool Equals(object obj)
        {
            DeviceContext other = obj as DeviceContext; 

            if (other == this) 
            { 
                return true;
            } 

            if (other == null)
            {
                return false; 
            }
 
            // Note: Use property instead of field so the HDC is initialized.  Also, this avoid serialization issues (the obj could be a proxy that does not have access to private fields). 
            return other.Hdc == this.Hdc;
        } 

        /// 
        ///     This allows collections to treat DeviceContext objects wrapping the same HDC as the same objects.
        ///  
        public override int GetHashCode()
        { 
            return this.Hdc.GetHashCode(); 
        }
 

        internal class GraphicsState {
            internal IntPtr hBrush;
            internal IntPtr hFont; 
            internal IntPtr hPen;
            internal IntPtr hBitmap; 
#if !DRAWING_NAMESPACE 
            internal WeakReference font;
#endif 
        }
     }
}

// 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