BufferedGraphicsContext.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

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

    /// 
    /// 
    ///         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.
        /// 
        [ResourceExposure(ResourceScope.Process)] 
        [ResourceConsumption(ResourceScope.Process)]
        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)] 
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        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. 
        /// 
        [ResourceExposure(ResourceScope.Process)] 
        [ResourceConsumption(ResourceScope.Process)] 
        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")]
        [ResourceExposure(ResourceScope.Process)] 
        [ResourceConsumption(ResourceScope.Process)]
        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# 
        //
        ///  
        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
        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. 
        /// 
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        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. 
        /// 
        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
        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;
    using System.Runtime.Versioning; 

    /// 
    /// 
    ///         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.
        /// 
        [ResourceExposure(ResourceScope.Process)] 
        [ResourceConsumption(ResourceScope.Process)]
        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)] 
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        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. 
        /// 
        [ResourceExposure(ResourceScope.Process)] 
        [ResourceConsumption(ResourceScope.Process)] 
        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")]
        [ResourceExposure(ResourceScope.Process)] 
        [ResourceConsumption(ResourceScope.Process)]
        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# 
        //
        ///  
        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
        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. 
        /// 
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        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. 
        /// 
        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
        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