BufferedGraphicsContext.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

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

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

namespace System.Drawing { 
    using System; 
    using System.ComponentModel;
    using System.Collections; 
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Drawing.Text;
    using System.Diagnostics; 
    using System.Runtime.InteropServices;
    using System.Threading; 
    using System.Security; 
    using System.Security.Permissions;
 
    /// 
    /// 
    ///         The BufferedGraphicsContext class can be used to perform standard double buffer
    ///         rendering techniques. 
    /// 
    public sealed class BufferedGraphicsContext : IDisposable { 
 
        private Size                    maximumBuffer;
        private Size                    bufferSize; 
        private Size                    virtualSize;
        private Point                   targetLoc;
        private IntPtr                  compatDC;
        private IntPtr                  dib; 
        private IntPtr                  oldBitmap;
        private Graphics                compatGraphics; 
        private BufferedGraphics        buffer; 
        private int                     busy;
        private bool                    invalidateWhenFree; 

        private const int               BUFFER_FREE = 0; //the graphics buffer is free to use
        private const int               BUFFER_BUSY_PAINTING = 1; //graphics buffer is busy being created/painting
        private const int               BUFFER_BUSY_DISPOSING = 2; //graphics buffer is busy disposing 

        static TraceSwitch              doubleBuffering; 
 
        #if DEBUG
        string stackAtBusy; 
        #endif

        /// 
        ///  
        ///         Basic constructor.
        ///  
        public BufferedGraphicsContext() { 
            //by defualt, the size of our maxbuffer will be 3 x standard button size
            maximumBuffer.Width = 75 * 3; 
            maximumBuffer.Height = 32 * 3;

            bufferSize = Size.Empty;
        } 

        ///  
        ///  
        ///         Destructor.
        ///  
        ~BufferedGraphicsContext() {
            Dispose(false);
        }
 
        //Internal trace switch for debugging
        // 
        internal static TraceSwitch DoubleBuffering { 
            get {
                if (doubleBuffering == null) { 
                    doubleBuffering = new TraceSwitch("DoubleBuffering", "Output information about double buffering");
                }
                return doubleBuffering;
            } 
        }
 
        ///  
        /// 
        ///         Allows you to set the maximum width and height of the buffer that will be retained in memory. 
        ///         You can allocate a buffer of any size, however any request for a buffer that would have a total
        ///         memory footprint larger that the maximum size will be allocated temporarily and then discarded
        ///         with the BufferedGraphics is released.
        ///  
        public Size MaximumBuffer {
            get { 
                return maximumBuffer; 
            }
            [UIPermission(SecurityAction.Demand, Window=UIPermissionWindow.AllWindows)] 
            set {
                if (value.Width <= 0 || value.Height <= 0) {
                    throw new ArgumentException(SR.GetString(SR.InvalidArgument, "MaximumBuffer", value));
                } 

                //if we've been asked to decrease the size of the maximum buffer, 
                //then invalidate the older & larger buffer 
                //
                if (value.Width * value.Height < maximumBuffer.Width * maximumBuffer.Height) { 
                    Invalidate();
                }

                maximumBuffer = value; 
            }
        } 
 
        /// 
        ///  
        ///         Returns a BufferedGraphics that is matched for the specified target Graphics object.
        /// 
        public BufferedGraphics Allocate(Graphics targetGraphics, Rectangle targetRectangle) {
            if (ShouldUseTempManager(targetRectangle)) { 
                Debug.WriteLineIf(DoubleBuffering.TraceWarning, "Too big of buffer requested (" + targetRectangle.Width + " x " + targetRectangle.Height + ") ... allocating temp buffer manager");
                return AllocBufferInTempManager(targetGraphics, IntPtr.Zero, targetRectangle); 
            } 
            return AllocBuffer(targetGraphics, IntPtr.Zero, targetRectangle);
        } 

        /// 
        /// 
        ///         Returns a BufferedGraphics that is matched for the specified target HDC object. 
        /// 
        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] 
        public BufferedGraphics Allocate(IntPtr targetDC, Rectangle targetRectangle) { 
            if (ShouldUseTempManager(targetRectangle)) {
                Debug.WriteLineIf(DoubleBuffering.TraceWarning, "Too big of buffer requested (" + targetRectangle.Width + " x " + targetRectangle.Height + ") ... allocating temp buffer manager"); 
                return AllocBufferInTempManager(null, targetDC, targetRectangle);
            }
            return AllocBuffer(null, targetDC, targetRectangle);
        } 

        ///  
        ///  
        ///         Returns a BufferedGraphics that is matched for the specified target HDC object.
        ///  
        private BufferedGraphics AllocBuffer(Graphics targetGraphics, IntPtr targetDC, Rectangle targetRectangle) {

            int oldBusy = Interlocked.CompareExchange(ref busy, BUFFER_BUSY_PAINTING, BUFFER_FREE);
 
            // In the case were we have contention on the buffer - i.e. two threads
            // trying to use the buffer at the same time, we just create a temp 
            // buffermanager and have the buffer dispose of it when it is done. 
            //
            if (oldBusy != BUFFER_FREE) { 
                Debug.WriteLineIf(DoubleBuffering.TraceWarning, "Attempt to have two buffers for a buffer manager... allocating temp buffer manager");
                return AllocBufferInTempManager(targetGraphics, targetDC, targetRectangle);
            }
 
            #if DEBUG
            if (DoubleBuffering.TraceVerbose) { 
                stackAtBusy = new StackTrace().ToString(); 
            }
            #endif 

            Graphics surface;
            this.targetLoc = new Point(targetRectangle.X, targetRectangle.Y);
 
            try {
                if (targetGraphics != null) { 
                    IntPtr destDc = targetGraphics.GetHdc(); 
                    try {
                        surface = CreateBuffer(destDc, -targetLoc.X, -targetLoc.Y, targetRectangle.Width, targetRectangle.Height); 
                    }
                    finally {
                        targetGraphics.ReleaseHdcInternal(destDc);
                    } 
                }
                else { 
                    surface = CreateBuffer(targetDC, -targetLoc.X, -targetLoc.Y, targetRectangle.Width, targetRectangle.Height); 
                }
 
                this.buffer = new BufferedGraphics(surface, this, targetGraphics, targetDC, targetLoc, virtualSize);
            }
            catch {
                this.busy = BUFFER_FREE; // free the buffer so it can be disposed. 
                throw;
            } 
            return this.buffer; 
        }
 
        /// 
        /// 
        ///         Returns a BufferedGraphics that is matched for the specified target HDC object.
        ///  
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope")]
        private BufferedGraphics AllocBufferInTempManager(Graphics targetGraphics, IntPtr targetDC, Rectangle targetRectangle) { 
            BufferedGraphicsContext tempContext = null; 
            BufferedGraphics tempBuffer = null;
 
            try {
                tempContext = new BufferedGraphicsContext();
                if (tempContext != null) {
                    tempBuffer = tempContext.AllocBuffer(targetGraphics, targetDC, targetRectangle); 
                    tempBuffer.DisposeContext = true;
                } 
            } 
            finally {
                if (tempContext != null && (tempBuffer == null || (tempBuffer != null && !tempBuffer.DisposeContext))) { 
                    tempContext.Dispose();
                }
            }
 
            return tempBuffer;
        } 
 

        ///  
        /// 
        // bFillBitmapInfo
        //
        // Fills in the fields of a BITMAPINFO so that we can create a bitmap 
        // that matches the format of the display.
        // 
        // This is done by creating a compatible bitmap and calling GetDIBits 
        // to return the color masks.  This is done with two calls.  The first
        // call passes in biBitCount = 0 to GetDIBits which will fill in the 
        // base BITMAPINFOHEADER data.  The second call to GetDIBits (passing
        // in the BITMAPINFO filled in by the first call) will return the color
        // table or bitmasks, as appropriate.
        // 
        // Returns:
        //   TRUE if successful, FALSE otherwise. 
        // 
        // History:
        //  07-Jun-1995 -by- Gilman Wong [[....]] 
        // Wrote it.
        //
        //  15-Nov-2000 -by- Chris Anderson [[....]]
        // Ported it to C# 
        //
        ///  
        private bool bFillBitmapInfo(IntPtr hdc, IntPtr hpal, ref NativeMethods.BITMAPINFO_FLAT pbmi) { 
            IntPtr hbm = IntPtr.Zero;
            bool bRet = false; 
            try {

                //
                // Create a dummy bitmap from which we can query color format info 
                // about the device surface.
                // 
                hbm = SafeNativeMethods.CreateCompatibleBitmap(new HandleRef(null, hdc), 1, 1); 

                if (hbm == IntPtr.Zero) { 
                    throw new OutOfMemoryException(SR.GetString(SR.GraphicsBufferQueryFail));
                }

                pbmi.bmiHeader_biSize = Marshal.SizeOf(typeof(NativeMethods.BITMAPINFOHEADER)); 
                pbmi.bmiColors = new byte[NativeMethods.BITMAPINFO_MAX_COLORSIZE*4];
 
                // 
                // Call first time to fill in BITMAPINFO header.
                // 
                SafeNativeMethods.GetDIBits(new HandleRef(null, hdc),
                                                    new HandleRef(null, hbm),
                                                    0,
                                                    0, 
                                                    IntPtr.Zero,
                                                    ref pbmi, 
                                                    NativeMethods.DIB_RGB_COLORS); 

                if ( pbmi.bmiHeader_biBitCount <= 8 ) { 
                    bRet = bFillColorTable(hdc, hpal, ref pbmi);
                }
                else {
                    if ( pbmi.bmiHeader_biCompression == NativeMethods.BI_BITFIELDS ) { 

                        // 
                        // Call a second time to get the color masks. 
                        // It's a GetDIBits Win32 "feature".
                        // 
                        SafeNativeMethods.GetDIBits(new HandleRef(null, hdc),
                                                new HandleRef(null, hbm),
                                                0,
                                                pbmi.bmiHeader_biHeight, 
                                                IntPtr.Zero,
                                                ref pbmi, 
                                                NativeMethods.DIB_RGB_COLORS); 
                    }
                    bRet = true; 
                }
            }
            finally {
                if (hbm != IntPtr.Zero) { 
                    SafeNativeMethods.DeleteObject(new HandleRef(null, hbm));
                    hbm = IntPtr.Zero; 
                } 
            }
            return bRet; 
        }

        /// 
        ///  
        // bFillColorTable
        // 
        // Initialize the color table of the BITMAPINFO pointed to by pbmi.  Colors 
        // are set to the current system palette.
        // 
        // Note: call only valid for displays of 8bpp or less.
        //
        // Returns:
        //   TRUE if successful, FALSE otherwise. 
        //
        // History: 
        //  23-Jan-1996 -by- Gilman Wong [[....]] 
        // Wrote it.
        // 
        //  15-Nov-2000 -by- Chris Anderson [[....]]
        // Ported it to C#
        //
        ///  
        private unsafe bool bFillColorTable(IntPtr hdc, IntPtr hpal, ref NativeMethods.BITMAPINFO_FLAT pbmi) {
            bool bRet = false; 
            byte[] aj = new byte[sizeof(NativeMethods.PALETTEENTRY) * 256]; 
            int i, cColors;
 
            fixed (byte* pcolors = pbmi.bmiColors) {
                fixed (byte* ppal = aj) {
                    NativeMethods.RGBQUAD* prgb = (NativeMethods.RGBQUAD*)pcolors;
                    NativeMethods.PALETTEENTRY* lppe = (NativeMethods.PALETTEENTRY*)ppal; 

                    cColors = 1 << pbmi.bmiHeader_biBitCount; 
                    if ( cColors <= 256 ) { 
                        Debug.WriteLineIf(DoubleBuffering.TraceVerbose, "8 bit or less...");
 
                        // NOTE : Didn't port "MyGetPaletteEntries" as it is only
                        //      : for 4bpp displays, which we don't work on anyway.
                        uint palRet;
                        IntPtr palHalftone = IntPtr.Zero; 
                        if (hpal == IntPtr.Zero) {
                            Debug.WriteLineIf(DoubleBuffering.TraceVerbose, "using halftone palette..."); 
                            palHalftone = Graphics.GetHalftonePalette(); 
                            palRet = SafeNativeMethods.GetPaletteEntries(new HandleRef(null, palHalftone), 0, cColors, aj);
                        } 
                        else {
                            Debug.WriteLineIf(DoubleBuffering.TraceVerbose, "using custom palette...");
                            palRet = SafeNativeMethods.GetPaletteEntries(new HandleRef(null, hpal), 0, cColors, aj);
                        } 
                        if ( palRet != 0 ) {
                            for (i = 0; i < cColors; i++) { 
                                prgb[i].rgbRed      = lppe[i].peRed; 
                                prgb[i].rgbGreen    = lppe[i].peGreen;
                                prgb[i].rgbBlue     = lppe[i].peBlue; 
                                prgb[i].rgbReserved = 0;
                            }
                            bRet = true;
                        } 
                        else {
                            Debug.WriteLineIf(DoubleBuffering.TraceWarning, "bFillColorTable: MyGetSystemPaletteEntries failed\n"); 
                        } 
                    }
                } 
            }
            return bRet;
        }
 
        /// 
        ///  
        ///         Returns a Graphics object representing a buffer. 
        /// 
        private Graphics CreateBuffer(IntPtr src, int offsetX, int offsetY, int width, int height) 
        {
            //create the compat DC
            busy = BUFFER_BUSY_DISPOSING;
            DisposeDC(); 
            busy = BUFFER_BUSY_PAINTING;
            compatDC = UnsafeNativeMethods.CreateCompatibleDC(new HandleRef(null, src)); 
 
            //recreate the bitmap if necessary
            if (width > bufferSize.Width || height > bufferSize.Height) 
            {
                Debug.WriteLineIf(DoubleBuffering.TraceInfo, "allocating new bitmap: " + width + " x " + height);
                int optWidth = Math.Max(width, bufferSize.Width);
                int optHeight = Math.Max(height, bufferSize.Height); 

                busy = BUFFER_BUSY_DISPOSING; 
                DisposeBitmap(); 
                busy = BUFFER_BUSY_PAINTING;
 
                Debug.WriteLineIf(DoubleBuffering.TraceInfo, "    new size         : " + optWidth + " x " + optHeight);
                IntPtr pvbits = IntPtr.Zero;
                dib = CreateCompatibleDIB(src, IntPtr.Zero, optWidth, optHeight, ref pvbits);
                bufferSize = new Size(optWidth, optHeight); 
            }
 
            //select the bitmap 
            oldBitmap = SafeNativeMethods.SelectObject(new HandleRef(this, compatDC), new HandleRef(this, dib));
 
            //create compat graphics
            Debug.WriteLineIf(DoubleBuffering.TraceInfo, "    Create compatGraphics");
            compatGraphics = Graphics.FromHdcInternal(compatDC);
            compatGraphics.TranslateTransform(-targetLoc.X, -targetLoc.Y); 
            virtualSize = new Size(width, height);
 
            return compatGraphics; 
        }
 
        /// 
        /// 
        // CreateCompatibleDIB
        // 
        // Create a DIB section with an optimal format w.r.t. the specified hdc.
        // 
        // If DIB <= 8bpp, then the DIB color table is initialized based on the 
        // specified palette.  If the palette handle is NULL, then the system
        // palette is used. 
        //
        // Note: The hdc must be a direct DC (not an info or memory DC).
        //
        // Note: On palettized displays, if the system palette changes the 
        //       UpdateDIBColorTable function should be called to maintain
        //       the identity palette mapping between the DIB and the display. 
        // 
        // Returns:
        //   Valid bitmap handle if successful, NULL if error. 
        //
        // History:
        //  23-Jan-1996 -by- Gilman Wong [[....]]
        // Wrote it. 
        //
        //  15-Nov-2000 -by- Chris Anderson [[....]] 
        // Ported it to C#. 
        //
        ///  
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Interoperability", "CA1404:CallGetLastErrorImmediatelyAfterPInvoke")]
        private IntPtr CreateCompatibleDIB(IntPtr hdc, IntPtr hpal, int ulWidth, int ulHeight, ref IntPtr ppvBits) {
            if (hdc == IntPtr.Zero) {
                throw new ArgumentNullException("hdc"); 
            }
 
            IntPtr hbmRet = IntPtr.Zero; 
            NativeMethods.BITMAPINFO_FLAT pbmi = new NativeMethods.BITMAPINFO_FLAT();
 
            //
            // Validate hdc.
            //
            int objType = UnsafeNativeMethods.GetObjectType(new HandleRef(null, hdc)); 

            switch(objType) { 
                case NativeMethods.OBJ_DC: 
                case NativeMethods.OBJ_METADC:
                case NativeMethods.OBJ_MEMDC: 
                case NativeMethods.OBJ_ENHMETADC:
                    break;
                default:
                    throw new ArgumentException(SR.GetString(SR.DCTypeInvalid)); 
            }
 
            if (bFillBitmapInfo(hdc, hpal, ref pbmi)) { 

                // 
                // Change bitmap size to match specified dimensions.
                //

                pbmi.bmiHeader_biWidth = ulWidth; 
                pbmi.bmiHeader_biHeight = ulHeight;
                if (pbmi.bmiHeader_biCompression == NativeMethods.BI_RGB) { 
                    pbmi.bmiHeader_biSizeImage = 0; 
                }
                else { 
                    if ( pbmi.bmiHeader_biBitCount == 16 )
                        pbmi.bmiHeader_biSizeImage = ulWidth * ulHeight * 2;
                    else if ( pbmi.bmiHeader_biBitCount == 32 )
                        pbmi.bmiHeader_biSizeImage = ulWidth * ulHeight * 4; 
                    else
                        pbmi.bmiHeader_biSizeImage = 0; 
                } 
                pbmi.bmiHeader_biClrUsed = 0;
                pbmi.bmiHeader_biClrImportant = 0; 

                //
                // Create the DIB section.  Let Win32 allocate the memory and return
                // a pointer to the bitmap surface. 
                //
 
                hbmRet = SafeNativeMethods.CreateDIBSection(new HandleRef(null, hdc), ref pbmi, NativeMethods.DIB_RGB_COLORS, ref ppvBits, IntPtr.Zero, 0); 
                Win32Exception ex = null;
                if ( hbmRet == IntPtr.Zero ) { 
                    ex = new Win32Exception(Marshal.GetLastWin32Error());
#if DEBUG
                    DumpBitmapInfo(ref pbmi);
#endif 
                }
 
#if DEBUG 
                if (DoubleBuffering.TraceVerbose) {
                    DumpBitmapInfo(ref pbmi); 
                }
#endif
                if(ex!=null) {
                    throw ex; 
                }
 
            } 
            return hbmRet;
        } 

        /// 
        /// 
        ///     Disposes of native handles. 
        /// 
        public void Dispose() { 
            Dispose(true); 
            GC.SuppressFinalize(this);
        } 

        /// 
        ///         Disposes the DC, but leaves the bitmap alone.
        ///  
        private void DisposeDC()
        { 
            if (oldBitmap != IntPtr.Zero && compatDC != IntPtr.Zero) 
            {
                Debug.WriteLineIf(DoubleBuffering.TraceVerbose, "restoring bitmap to DC"); 
                SafeNativeMethods.SelectObject(new HandleRef(this, compatDC), new HandleRef(this, oldBitmap));
                oldBitmap = IntPtr.Zero;
            }
            if (compatDC != IntPtr.Zero) 
            {
                Debug.WriteLineIf(DoubleBuffering.TraceVerbose, "delete compat DC"); 
                UnsafeNativeMethods.DeleteDC(new HandleRef(this, compatDC)); 
                compatDC = IntPtr.Zero;
            } 
        }

        /// 
        ///         Disposes the bitmap, will ASSERT if bitmap is being used (checks oldbitmap). 
        ///         if ASSERTed, call DisposeDC() first.
        ///  
        private void DisposeBitmap() 
        {
            if (dib != IntPtr.Zero) 
            {
                Debug.Assert(oldBitmap == IntPtr.Zero);
                Debug.WriteLineIf(DoubleBuffering.TraceVerbose, "delete dib");
 
                SafeNativeMethods.DeleteObject(new HandleRef(this, dib));
                dib = IntPtr.Zero; 
            } 
        }
 
        /// 
        /// 
        ///     Disposes of the Graphics buffer.
        ///  
        private void Dispose(bool disposing) {
            Debug.WriteLineIf(DoubleBuffering.TraceInfo, "Dispose(" + disposing + ") {"); 
            Debug.Indent(); 
            int oldBusy = Interlocked.CompareExchange(ref busy, BUFFER_BUSY_DISPOSING, BUFFER_FREE);
 
            if(disposing){
                if (oldBusy == BUFFER_BUSY_PAINTING) {
                    #if DEBUG
                        Debug.WriteLineIf(DoubleBuffering.TraceInfo, "Stack at busy buffer: \n" + stackAtBusy); 
                    #endif
 
                    throw new InvalidOperationException(SR.GetString(SR.GraphicsBufferCurrentlyBusy)); 
                }
 
                if (compatGraphics != null) {
                    Debug.WriteLineIf(DoubleBuffering.TraceVerbose, "Disposing compatGraphics");
                    compatGraphics.Dispose();
                    compatGraphics = null; 
                }
            } 
            else{ 
                Debug.Fail("Never let a graphics buffer finalize!");
            } 

            DisposeDC();
            DisposeBitmap();
 
            if (buffer != null) {
                Debug.WriteLineIf(DoubleBuffering.TraceVerbose, "Disposing buffer"); 
                buffer.Dispose(); 
                buffer = null;
            } 

            bufferSize = Size.Empty;
            virtualSize = Size.Empty;
            Debug.Unindent(); 
            Debug.WriteLineIf(DoubleBuffering.TraceInfo, "}");
 
            this.busy = BUFFER_FREE; 
        }
 
#if DEBUG
        private void DumpBitmapInfo(ref NativeMethods.BITMAPINFO_FLAT pbmi) {
            //Debug.WriteLine("biSize --> " + pbmi.bmiHeader_biSize);
            Debug.WriteLine("biWidth --> " + pbmi.bmiHeader_biWidth); 
            Debug.WriteLine("biHeight --> " + pbmi.bmiHeader_biHeight);
            Debug.WriteLine("biPlanes --> " + pbmi.bmiHeader_biPlanes); 
            Debug.WriteLine("biBitCount --> " + pbmi.bmiHeader_biBitCount); 
            //Debug.WriteLine("biCompression --> " + pbmi.bmiHeader_biCompression);
            //Debug.WriteLine("biSizeImage --> " + pbmi.bmiHeader_biSizeImage); 
            //Debug.WriteLine("biXPelsPerMeter --> " + pbmi.bmiHeader_biXPelsPerMeter);
            //Debug.WriteLine("biYPelsPerMeter --> " + pbmi.bmiHeader_biYPelsPerMeter);
            //Debug.WriteLine("biClrUsed --> " + pbmi.bmiHeader_biClrUsed);
            //Debug.WriteLine("biClrImportant --> " + pbmi.bmiHeader_biClrImportant); 
            //Debug.Write("bmiColors --> ");
            //for (int i=0; i 
        /// 
        ///         Invalidates the cached graphics buffer. 
        ///  
        public void Invalidate() {
            int oldBusy = Interlocked.CompareExchange(ref busy, BUFFER_BUSY_DISPOSING, BUFFER_FREE); 

            //if we're not busy with our buffer, lets
            //clean it up now
            // 
            if (oldBusy == BUFFER_FREE) {
                Dispose(); 
                this.busy = BUFFER_FREE; 
            }
            else { 
                //this will indicate to free the buffer
                //as soon as it becomes non-busy
                //
                this.invalidateWhenFree = true; 
            }
        } 
 
        /// 
        ///  
        ///         Returns a Graphics object representing a buffer.
        /// 
        internal void ReleaseBuffer(BufferedGraphics buffer) {
            Debug.Assert(buffer == this.buffer, "Tried to release a bogus buffer"); 

            this.buffer = null; 
            if (this.invalidateWhenFree) { 
                this.busy = BUFFER_BUSY_DISPOSING;
                Dispose(); //clears everything (incl bitmap) 
            }
            else {  //otherwise, just dispose the DC.  A new one will be created next time.
                this.busy = BUFFER_BUSY_DISPOSING;
                DisposeDC(); //only clears out the DC 
            }
 
            this.busy = BUFFER_FREE; 
        }
 
        /// 
        /// 
        ///         This routine allows us to control the point were we start using throw away
        ///         managers for painting. Since the buffer manager stays around (by default) 
        ///         for the life of the app, we don't want to consume too much memory
        ///         in the buffer. However, re-allocating the buffer for small things (like 
        ///         buttons, labels, etc) will hit us on runtime performance. 
        /// 
        private bool ShouldUseTempManager(Rectangle targetBounds) { 
            return (targetBounds.Width * targetBounds.Height) > (MaximumBuffer.Width * MaximumBuffer.Height);
        }

    } 
}

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

namespace System.Drawing { 
    using System; 
    using System.ComponentModel;
    using System.Collections; 
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Drawing.Text;
    using System.Diagnostics; 
    using System.Runtime.InteropServices;
    using System.Threading; 
    using System.Security; 
    using System.Security.Permissions;
 
    /// 
    /// 
    ///         The BufferedGraphicsContext class can be used to perform standard double buffer
    ///         rendering techniques. 
    /// 
    public sealed class BufferedGraphicsContext : IDisposable { 
 
        private Size                    maximumBuffer;
        private Size                    bufferSize; 
        private Size                    virtualSize;
        private Point                   targetLoc;
        private IntPtr                  compatDC;
        private IntPtr                  dib; 
        private IntPtr                  oldBitmap;
        private Graphics                compatGraphics; 
        private BufferedGraphics        buffer; 
        private int                     busy;
        private bool                    invalidateWhenFree; 

        private const int               BUFFER_FREE = 0; //the graphics buffer is free to use
        private const int               BUFFER_BUSY_PAINTING = 1; //graphics buffer is busy being created/painting
        private const int               BUFFER_BUSY_DISPOSING = 2; //graphics buffer is busy disposing 

        static TraceSwitch              doubleBuffering; 
 
        #if DEBUG
        string stackAtBusy; 
        #endif

        /// 
        ///  
        ///         Basic constructor.
        ///  
        public BufferedGraphicsContext() { 
            //by defualt, the size of our maxbuffer will be 3 x standard button size
            maximumBuffer.Width = 75 * 3; 
            maximumBuffer.Height = 32 * 3;

            bufferSize = Size.Empty;
        } 

        ///  
        ///  
        ///         Destructor.
        ///  
        ~BufferedGraphicsContext() {
            Dispose(false);
        }
 
        //Internal trace switch for debugging
        // 
        internal static TraceSwitch DoubleBuffering { 
            get {
                if (doubleBuffering == null) { 
                    doubleBuffering = new TraceSwitch("DoubleBuffering", "Output information about double buffering");
                }
                return doubleBuffering;
            } 
        }
 
        ///  
        /// 
        ///         Allows you to set the maximum width and height of the buffer that will be retained in memory. 
        ///         You can allocate a buffer of any size, however any request for a buffer that would have a total
        ///         memory footprint larger that the maximum size will be allocated temporarily and then discarded
        ///         with the BufferedGraphics is released.
        ///  
        public Size MaximumBuffer {
            get { 
                return maximumBuffer; 
            }
            [UIPermission(SecurityAction.Demand, Window=UIPermissionWindow.AllWindows)] 
            set {
                if (value.Width <= 0 || value.Height <= 0) {
                    throw new ArgumentException(SR.GetString(SR.InvalidArgument, "MaximumBuffer", value));
                } 

                //if we've been asked to decrease the size of the maximum buffer, 
                //then invalidate the older & larger buffer 
                //
                if (value.Width * value.Height < maximumBuffer.Width * maximumBuffer.Height) { 
                    Invalidate();
                }

                maximumBuffer = value; 
            }
        } 
 
        /// 
        ///  
        ///         Returns a BufferedGraphics that is matched for the specified target Graphics object.
        /// 
        public BufferedGraphics Allocate(Graphics targetGraphics, Rectangle targetRectangle) {
            if (ShouldUseTempManager(targetRectangle)) { 
                Debug.WriteLineIf(DoubleBuffering.TraceWarning, "Too big of buffer requested (" + targetRectangle.Width + " x " + targetRectangle.Height + ") ... allocating temp buffer manager");
                return AllocBufferInTempManager(targetGraphics, IntPtr.Zero, targetRectangle); 
            } 
            return AllocBuffer(targetGraphics, IntPtr.Zero, targetRectangle);
        } 

        /// 
        /// 
        ///         Returns a BufferedGraphics that is matched for the specified target HDC object. 
        /// 
        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] 
        public BufferedGraphics Allocate(IntPtr targetDC, Rectangle targetRectangle) { 
            if (ShouldUseTempManager(targetRectangle)) {
                Debug.WriteLineIf(DoubleBuffering.TraceWarning, "Too big of buffer requested (" + targetRectangle.Width + " x " + targetRectangle.Height + ") ... allocating temp buffer manager"); 
                return AllocBufferInTempManager(null, targetDC, targetRectangle);
            }
            return AllocBuffer(null, targetDC, targetRectangle);
        } 

        ///  
        ///  
        ///         Returns a BufferedGraphics that is matched for the specified target HDC object.
        ///  
        private BufferedGraphics AllocBuffer(Graphics targetGraphics, IntPtr targetDC, Rectangle targetRectangle) {

            int oldBusy = Interlocked.CompareExchange(ref busy, BUFFER_BUSY_PAINTING, BUFFER_FREE);
 
            // In the case were we have contention on the buffer - i.e. two threads
            // trying to use the buffer at the same time, we just create a temp 
            // buffermanager and have the buffer dispose of it when it is done. 
            //
            if (oldBusy != BUFFER_FREE) { 
                Debug.WriteLineIf(DoubleBuffering.TraceWarning, "Attempt to have two buffers for a buffer manager... allocating temp buffer manager");
                return AllocBufferInTempManager(targetGraphics, targetDC, targetRectangle);
            }
 
            #if DEBUG
            if (DoubleBuffering.TraceVerbose) { 
                stackAtBusy = new StackTrace().ToString(); 
            }
            #endif 

            Graphics surface;
            this.targetLoc = new Point(targetRectangle.X, targetRectangle.Y);
 
            try {
                if (targetGraphics != null) { 
                    IntPtr destDc = targetGraphics.GetHdc(); 
                    try {
                        surface = CreateBuffer(destDc, -targetLoc.X, -targetLoc.Y, targetRectangle.Width, targetRectangle.Height); 
                    }
                    finally {
                        targetGraphics.ReleaseHdcInternal(destDc);
                    } 
                }
                else { 
                    surface = CreateBuffer(targetDC, -targetLoc.X, -targetLoc.Y, targetRectangle.Width, targetRectangle.Height); 
                }
 
                this.buffer = new BufferedGraphics(surface, this, targetGraphics, targetDC, targetLoc, virtualSize);
            }
            catch {
                this.busy = BUFFER_FREE; // free the buffer so it can be disposed. 
                throw;
            } 
            return this.buffer; 
        }
 
        /// 
        /// 
        ///         Returns a BufferedGraphics that is matched for the specified target HDC object.
        ///  
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope")]
        private BufferedGraphics AllocBufferInTempManager(Graphics targetGraphics, IntPtr targetDC, Rectangle targetRectangle) { 
            BufferedGraphicsContext tempContext = null; 
            BufferedGraphics tempBuffer = null;
 
            try {
                tempContext = new BufferedGraphicsContext();
                if (tempContext != null) {
                    tempBuffer = tempContext.AllocBuffer(targetGraphics, targetDC, targetRectangle); 
                    tempBuffer.DisposeContext = true;
                } 
            } 
            finally {
                if (tempContext != null && (tempBuffer == null || (tempBuffer != null && !tempBuffer.DisposeContext))) { 
                    tempContext.Dispose();
                }
            }
 
            return tempBuffer;
        } 
 

        ///  
        /// 
        // bFillBitmapInfo
        //
        // Fills in the fields of a BITMAPINFO so that we can create a bitmap 
        // that matches the format of the display.
        // 
        // This is done by creating a compatible bitmap and calling GetDIBits 
        // to return the color masks.  This is done with two calls.  The first
        // call passes in biBitCount = 0 to GetDIBits which will fill in the 
        // base BITMAPINFOHEADER data.  The second call to GetDIBits (passing
        // in the BITMAPINFO filled in by the first call) will return the color
        // table or bitmasks, as appropriate.
        // 
        // Returns:
        //   TRUE if successful, FALSE otherwise. 
        // 
        // History:
        //  07-Jun-1995 -by- Gilman Wong [[....]] 
        // Wrote it.
        //
        //  15-Nov-2000 -by- Chris Anderson [[....]]
        // Ported it to C# 
        //
        ///  
        private bool bFillBitmapInfo(IntPtr hdc, IntPtr hpal, ref NativeMethods.BITMAPINFO_FLAT pbmi) { 
            IntPtr hbm = IntPtr.Zero;
            bool bRet = false; 
            try {

                //
                // Create a dummy bitmap from which we can query color format info 
                // about the device surface.
                // 
                hbm = SafeNativeMethods.CreateCompatibleBitmap(new HandleRef(null, hdc), 1, 1); 

                if (hbm == IntPtr.Zero) { 
                    throw new OutOfMemoryException(SR.GetString(SR.GraphicsBufferQueryFail));
                }

                pbmi.bmiHeader_biSize = Marshal.SizeOf(typeof(NativeMethods.BITMAPINFOHEADER)); 
                pbmi.bmiColors = new byte[NativeMethods.BITMAPINFO_MAX_COLORSIZE*4];
 
                // 
                // Call first time to fill in BITMAPINFO header.
                // 
                SafeNativeMethods.GetDIBits(new HandleRef(null, hdc),
                                                    new HandleRef(null, hbm),
                                                    0,
                                                    0, 
                                                    IntPtr.Zero,
                                                    ref pbmi, 
                                                    NativeMethods.DIB_RGB_COLORS); 

                if ( pbmi.bmiHeader_biBitCount <= 8 ) { 
                    bRet = bFillColorTable(hdc, hpal, ref pbmi);
                }
                else {
                    if ( pbmi.bmiHeader_biCompression == NativeMethods.BI_BITFIELDS ) { 

                        // 
                        // Call a second time to get the color masks. 
                        // It's a GetDIBits Win32 "feature".
                        // 
                        SafeNativeMethods.GetDIBits(new HandleRef(null, hdc),
                                                new HandleRef(null, hbm),
                                                0,
                                                pbmi.bmiHeader_biHeight, 
                                                IntPtr.Zero,
                                                ref pbmi, 
                                                NativeMethods.DIB_RGB_COLORS); 
                    }
                    bRet = true; 
                }
            }
            finally {
                if (hbm != IntPtr.Zero) { 
                    SafeNativeMethods.DeleteObject(new HandleRef(null, hbm));
                    hbm = IntPtr.Zero; 
                } 
            }
            return bRet; 
        }

        /// 
        ///  
        // bFillColorTable
        // 
        // Initialize the color table of the BITMAPINFO pointed to by pbmi.  Colors 
        // are set to the current system palette.
        // 
        // Note: call only valid for displays of 8bpp or less.
        //
        // Returns:
        //   TRUE if successful, FALSE otherwise. 
        //
        // History: 
        //  23-Jan-1996 -by- Gilman Wong [[....]] 
        // Wrote it.
        // 
        //  15-Nov-2000 -by- Chris Anderson [[....]]
        // Ported it to C#
        //
        ///  
        private unsafe bool bFillColorTable(IntPtr hdc, IntPtr hpal, ref NativeMethods.BITMAPINFO_FLAT pbmi) {
            bool bRet = false; 
            byte[] aj = new byte[sizeof(NativeMethods.PALETTEENTRY) * 256]; 
            int i, cColors;
 
            fixed (byte* pcolors = pbmi.bmiColors) {
                fixed (byte* ppal = aj) {
                    NativeMethods.RGBQUAD* prgb = (NativeMethods.RGBQUAD*)pcolors;
                    NativeMethods.PALETTEENTRY* lppe = (NativeMethods.PALETTEENTRY*)ppal; 

                    cColors = 1 << pbmi.bmiHeader_biBitCount; 
                    if ( cColors <= 256 ) { 
                        Debug.WriteLineIf(DoubleBuffering.TraceVerbose, "8 bit or less...");
 
                        // NOTE : Didn't port "MyGetPaletteEntries" as it is only
                        //      : for 4bpp displays, which we don't work on anyway.
                        uint palRet;
                        IntPtr palHalftone = IntPtr.Zero; 
                        if (hpal == IntPtr.Zero) {
                            Debug.WriteLineIf(DoubleBuffering.TraceVerbose, "using halftone palette..."); 
                            palHalftone = Graphics.GetHalftonePalette(); 
                            palRet = SafeNativeMethods.GetPaletteEntries(new HandleRef(null, palHalftone), 0, cColors, aj);
                        } 
                        else {
                            Debug.WriteLineIf(DoubleBuffering.TraceVerbose, "using custom palette...");
                            palRet = SafeNativeMethods.GetPaletteEntries(new HandleRef(null, hpal), 0, cColors, aj);
                        } 
                        if ( palRet != 0 ) {
                            for (i = 0; i < cColors; i++) { 
                                prgb[i].rgbRed      = lppe[i].peRed; 
                                prgb[i].rgbGreen    = lppe[i].peGreen;
                                prgb[i].rgbBlue     = lppe[i].peBlue; 
                                prgb[i].rgbReserved = 0;
                            }
                            bRet = true;
                        } 
                        else {
                            Debug.WriteLineIf(DoubleBuffering.TraceWarning, "bFillColorTable: MyGetSystemPaletteEntries failed\n"); 
                        } 
                    }
                } 
            }
            return bRet;
        }
 
        /// 
        ///  
        ///         Returns a Graphics object representing a buffer. 
        /// 
        private Graphics CreateBuffer(IntPtr src, int offsetX, int offsetY, int width, int height) 
        {
            //create the compat DC
            busy = BUFFER_BUSY_DISPOSING;
            DisposeDC(); 
            busy = BUFFER_BUSY_PAINTING;
            compatDC = UnsafeNativeMethods.CreateCompatibleDC(new HandleRef(null, src)); 
 
            //recreate the bitmap if necessary
            if (width > bufferSize.Width || height > bufferSize.Height) 
            {
                Debug.WriteLineIf(DoubleBuffering.TraceInfo, "allocating new bitmap: " + width + " x " + height);
                int optWidth = Math.Max(width, bufferSize.Width);
                int optHeight = Math.Max(height, bufferSize.Height); 

                busy = BUFFER_BUSY_DISPOSING; 
                DisposeBitmap(); 
                busy = BUFFER_BUSY_PAINTING;
 
                Debug.WriteLineIf(DoubleBuffering.TraceInfo, "    new size         : " + optWidth + " x " + optHeight);
                IntPtr pvbits = IntPtr.Zero;
                dib = CreateCompatibleDIB(src, IntPtr.Zero, optWidth, optHeight, ref pvbits);
                bufferSize = new Size(optWidth, optHeight); 
            }
 
            //select the bitmap 
            oldBitmap = SafeNativeMethods.SelectObject(new HandleRef(this, compatDC), new HandleRef(this, dib));
 
            //create compat graphics
            Debug.WriteLineIf(DoubleBuffering.TraceInfo, "    Create compatGraphics");
            compatGraphics = Graphics.FromHdcInternal(compatDC);
            compatGraphics.TranslateTransform(-targetLoc.X, -targetLoc.Y); 
            virtualSize = new Size(width, height);
 
            return compatGraphics; 
        }
 
        /// 
        /// 
        // CreateCompatibleDIB
        // 
        // Create a DIB section with an optimal format w.r.t. the specified hdc.
        // 
        // If DIB <= 8bpp, then the DIB color table is initialized based on the 
        // specified palette.  If the palette handle is NULL, then the system
        // palette is used. 
        //
        // Note: The hdc must be a direct DC (not an info or memory DC).
        //
        // Note: On palettized displays, if the system palette changes the 
        //       UpdateDIBColorTable function should be called to maintain
        //       the identity palette mapping between the DIB and the display. 
        // 
        // Returns:
        //   Valid bitmap handle if successful, NULL if error. 
        //
        // History:
        //  23-Jan-1996 -by- Gilman Wong [[....]]
        // Wrote it. 
        //
        //  15-Nov-2000 -by- Chris Anderson [[....]] 
        // Ported it to C#. 
        //
        ///  
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Interoperability", "CA1404:CallGetLastErrorImmediatelyAfterPInvoke")]
        private IntPtr CreateCompatibleDIB(IntPtr hdc, IntPtr hpal, int ulWidth, int ulHeight, ref IntPtr ppvBits) {
            if (hdc == IntPtr.Zero) {
                throw new ArgumentNullException("hdc"); 
            }
 
            IntPtr hbmRet = IntPtr.Zero; 
            NativeMethods.BITMAPINFO_FLAT pbmi = new NativeMethods.BITMAPINFO_FLAT();
 
            //
            // Validate hdc.
            //
            int objType = UnsafeNativeMethods.GetObjectType(new HandleRef(null, hdc)); 

            switch(objType) { 
                case NativeMethods.OBJ_DC: 
                case NativeMethods.OBJ_METADC:
                case NativeMethods.OBJ_MEMDC: 
                case NativeMethods.OBJ_ENHMETADC:
                    break;
                default:
                    throw new ArgumentException(SR.GetString(SR.DCTypeInvalid)); 
            }
 
            if (bFillBitmapInfo(hdc, hpal, ref pbmi)) { 

                // 
                // Change bitmap size to match specified dimensions.
                //

                pbmi.bmiHeader_biWidth = ulWidth; 
                pbmi.bmiHeader_biHeight = ulHeight;
                if (pbmi.bmiHeader_biCompression == NativeMethods.BI_RGB) { 
                    pbmi.bmiHeader_biSizeImage = 0; 
                }
                else { 
                    if ( pbmi.bmiHeader_biBitCount == 16 )
                        pbmi.bmiHeader_biSizeImage = ulWidth * ulHeight * 2;
                    else if ( pbmi.bmiHeader_biBitCount == 32 )
                        pbmi.bmiHeader_biSizeImage = ulWidth * ulHeight * 4; 
                    else
                        pbmi.bmiHeader_biSizeImage = 0; 
                } 
                pbmi.bmiHeader_biClrUsed = 0;
                pbmi.bmiHeader_biClrImportant = 0; 

                //
                // Create the DIB section.  Let Win32 allocate the memory and return
                // a pointer to the bitmap surface. 
                //
 
                hbmRet = SafeNativeMethods.CreateDIBSection(new HandleRef(null, hdc), ref pbmi, NativeMethods.DIB_RGB_COLORS, ref ppvBits, IntPtr.Zero, 0); 
                Win32Exception ex = null;
                if ( hbmRet == IntPtr.Zero ) { 
                    ex = new Win32Exception(Marshal.GetLastWin32Error());
#if DEBUG
                    DumpBitmapInfo(ref pbmi);
#endif 
                }
 
#if DEBUG 
                if (DoubleBuffering.TraceVerbose) {
                    DumpBitmapInfo(ref pbmi); 
                }
#endif
                if(ex!=null) {
                    throw ex; 
                }
 
            } 
            return hbmRet;
        } 

        /// 
        /// 
        ///     Disposes of native handles. 
        /// 
        public void Dispose() { 
            Dispose(true); 
            GC.SuppressFinalize(this);
        } 

        /// 
        ///         Disposes the DC, but leaves the bitmap alone.
        ///  
        private void DisposeDC()
        { 
            if (oldBitmap != IntPtr.Zero && compatDC != IntPtr.Zero) 
            {
                Debug.WriteLineIf(DoubleBuffering.TraceVerbose, "restoring bitmap to DC"); 
                SafeNativeMethods.SelectObject(new HandleRef(this, compatDC), new HandleRef(this, oldBitmap));
                oldBitmap = IntPtr.Zero;
            }
            if (compatDC != IntPtr.Zero) 
            {
                Debug.WriteLineIf(DoubleBuffering.TraceVerbose, "delete compat DC"); 
                UnsafeNativeMethods.DeleteDC(new HandleRef(this, compatDC)); 
                compatDC = IntPtr.Zero;
            } 
        }

        /// 
        ///         Disposes the bitmap, will ASSERT if bitmap is being used (checks oldbitmap). 
        ///         if ASSERTed, call DisposeDC() first.
        ///  
        private void DisposeBitmap() 
        {
            if (dib != IntPtr.Zero) 
            {
                Debug.Assert(oldBitmap == IntPtr.Zero);
                Debug.WriteLineIf(DoubleBuffering.TraceVerbose, "delete dib");
 
                SafeNativeMethods.DeleteObject(new HandleRef(this, dib));
                dib = IntPtr.Zero; 
            } 
        }
 
        /// 
        /// 
        ///     Disposes of the Graphics buffer.
        ///  
        private void Dispose(bool disposing) {
            Debug.WriteLineIf(DoubleBuffering.TraceInfo, "Dispose(" + disposing + ") {"); 
            Debug.Indent(); 
            int oldBusy = Interlocked.CompareExchange(ref busy, BUFFER_BUSY_DISPOSING, BUFFER_FREE);
 
            if(disposing){
                if (oldBusy == BUFFER_BUSY_PAINTING) {
                    #if DEBUG
                        Debug.WriteLineIf(DoubleBuffering.TraceInfo, "Stack at busy buffer: \n" + stackAtBusy); 
                    #endif
 
                    throw new InvalidOperationException(SR.GetString(SR.GraphicsBufferCurrentlyBusy)); 
                }
 
                if (compatGraphics != null) {
                    Debug.WriteLineIf(DoubleBuffering.TraceVerbose, "Disposing compatGraphics");
                    compatGraphics.Dispose();
                    compatGraphics = null; 
                }
            } 
            else{ 
                Debug.Fail("Never let a graphics buffer finalize!");
            } 

            DisposeDC();
            DisposeBitmap();
 
            if (buffer != null) {
                Debug.WriteLineIf(DoubleBuffering.TraceVerbose, "Disposing buffer"); 
                buffer.Dispose(); 
                buffer = null;
            } 

            bufferSize = Size.Empty;
            virtualSize = Size.Empty;
            Debug.Unindent(); 
            Debug.WriteLineIf(DoubleBuffering.TraceInfo, "}");
 
            this.busy = BUFFER_FREE; 
        }
 
#if DEBUG
        private void DumpBitmapInfo(ref NativeMethods.BITMAPINFO_FLAT pbmi) {
            //Debug.WriteLine("biSize --> " + pbmi.bmiHeader_biSize);
            Debug.WriteLine("biWidth --> " + pbmi.bmiHeader_biWidth); 
            Debug.WriteLine("biHeight --> " + pbmi.bmiHeader_biHeight);
            Debug.WriteLine("biPlanes --> " + pbmi.bmiHeader_biPlanes); 
            Debug.WriteLine("biBitCount --> " + pbmi.bmiHeader_biBitCount); 
            //Debug.WriteLine("biCompression --> " + pbmi.bmiHeader_biCompression);
            //Debug.WriteLine("biSizeImage --> " + pbmi.bmiHeader_biSizeImage); 
            //Debug.WriteLine("biXPelsPerMeter --> " + pbmi.bmiHeader_biXPelsPerMeter);
            //Debug.WriteLine("biYPelsPerMeter --> " + pbmi.bmiHeader_biYPelsPerMeter);
            //Debug.WriteLine("biClrUsed --> " + pbmi.bmiHeader_biClrUsed);
            //Debug.WriteLine("biClrImportant --> " + pbmi.bmiHeader_biClrImportant); 
            //Debug.Write("bmiColors --> ");
            //for (int i=0; i 
        /// 
        ///         Invalidates the cached graphics buffer. 
        ///  
        public void Invalidate() {
            int oldBusy = Interlocked.CompareExchange(ref busy, BUFFER_BUSY_DISPOSING, BUFFER_FREE); 

            //if we're not busy with our buffer, lets
            //clean it up now
            // 
            if (oldBusy == BUFFER_FREE) {
                Dispose(); 
                this.busy = BUFFER_FREE; 
            }
            else { 
                //this will indicate to free the buffer
                //as soon as it becomes non-busy
                //
                this.invalidateWhenFree = true; 
            }
        } 
 
        /// 
        ///  
        ///         Returns a Graphics object representing a buffer.
        /// 
        internal void ReleaseBuffer(BufferedGraphics buffer) {
            Debug.Assert(buffer == this.buffer, "Tried to release a bogus buffer"); 

            this.buffer = null; 
            if (this.invalidateWhenFree) { 
                this.busy = BUFFER_BUSY_DISPOSING;
                Dispose(); //clears everything (incl bitmap) 
            }
            else {  //otherwise, just dispose the DC.  A new one will be created next time.
                this.busy = BUFFER_BUSY_DISPOSING;
                DisposeDC(); //only clears out the DC 
            }
 
            this.busy = BUFFER_FREE; 
        }
 
        /// 
        /// 
        ///         This routine allows us to control the point were we start using throw away
        ///         managers for painting. Since the buffer manager stays around (by default) 
        ///         for the life of the app, we don't want to consume too much memory
        ///         in the buffer. However, re-allocating the buffer for small things (like 
        ///         buttons, labels, etc) will hit us on runtime performance. 
        /// 
        private bool ShouldUseTempManager(Rectangle targetBounds) { 
            return (targetBounds.Width * targetBounds.Height) > (MaximumBuffer.Width * MaximumBuffer.Height);
        }

    } 
}

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