private IntPtr CreateCompatibleDIB(IntPtr hdc, IntPtr hpal, int ulWidth, int ulHeight, ref IntPtr ppvBits)
        {
            if (hdc == IntPtr.Zero)
            {
                throw new ArgumentNullException("hdc");
            }
            IntPtr zero = IntPtr.Zero;

            System.Drawing.NativeMethods.BITMAPINFO_FLAT pbmi = new System.Drawing.NativeMethods.BITMAPINFO_FLAT();
            switch (System.Drawing.UnsafeNativeMethods.GetObjectType(new HandleRef(null, hdc)))
            {
            case 3:
            case 4:
            case 10:
            case 12:
                if (this.bFillBitmapInfo(hdc, hpal, ref pbmi))
                {
                    pbmi.bmiHeader_biWidth  = ulWidth;
                    pbmi.bmiHeader_biHeight = ulHeight;
                    if (pbmi.bmiHeader_biCompression == 0)
                    {
                        pbmi.bmiHeader_biSizeImage = 0;
                    }
                    else if (pbmi.bmiHeader_biBitCount == 0x10)
                    {
                        pbmi.bmiHeader_biSizeImage = (ulWidth * ulHeight) * 2;
                    }
                    else if (pbmi.bmiHeader_biBitCount == 0x20)
                    {
                        pbmi.bmiHeader_biSizeImage = (ulWidth * ulHeight) * 4;
                    }
                    else
                    {
                        pbmi.bmiHeader_biSizeImage = 0;
                    }
                    pbmi.bmiHeader_biClrUsed      = 0;
                    pbmi.bmiHeader_biClrImportant = 0;
                    zero = SafeNativeMethods.CreateDIBSection(new HandleRef(null, hdc), ref pbmi, 0, ref ppvBits, IntPtr.Zero, 0);
                    Win32Exception exception = null;
                    if (zero == IntPtr.Zero)
                    {
                        exception = new Win32Exception(Marshal.GetLastWin32Error());
                    }
                    if (exception != null)
                    {
                        throw exception;
                    }
                }
                return(zero);
            }
            throw new ArgumentException(System.Drawing.SR.GetString("DCTypeInvalid"));
        }
        /// <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.
            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.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);
        }