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;
        }
        /// <summary>
        /// Create a DIB section with an optimal format w.r.t. the specified hdc.
        ///
        /// If DIB &lt;= 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.
        /// </summary>
        /// <returns>A valid bitmap handle if successful, IntPtr.Zero otherwise.</returns>
        private IntPtr CreateCompatibleDIB(IntPtr hdc, IntPtr hpal, int ulWidth, int ulHeight, ref IntPtr ppvBits)
        {
            if (hdc == IntPtr.Zero)
            {
                throw new ArgumentNullException(nameof(hdc));
            }

            IntPtr hbmRet = IntPtr.Zero;
            var    pbmi   = new NativeMethods.BITMAPINFO_FLAT();

            // Validate hdc.
            Interop.Gdi32.ObjectType objType = Interop.Gdi32.GetObjectType(hdc);
            switch (objType)
            {
            case Interop.Gdi32.ObjectType.OBJ_DC:
            case Interop.Gdi32.ObjectType.OBJ_METADC:
            case Interop.Gdi32.ObjectType.OBJ_MEMDC:
            case Interop.Gdi32.ObjectType.OBJ_ENHMETADC:
                break;

            default:
                throw new ArgumentException(SR.DCTypeInvalid);
            }

            if (FillBitmapInfo(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 (ex != null)
                {
                    throw ex;
                }
            }

            return(hbmRet);
        }