/// <summary>
        /// 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.
        /// </summary>
        /// <returns>True if successful, false otherwise.</returns>
        private unsafe bool FillBitmapInfo(IntPtr hdc, IntPtr hpal, ref Interop.Gdi32.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 = Interop.Gdi32.CreateCompatibleBitmap(new HandleRef(null, hdc), 1, 1);

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

                pbmi.bmiHeader_biSize = sizeof(NativeMethods.BITMAPINFOHEADER);

                // Call first time to fill in BITMAPINFO header.
                Interop.Gdi32.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 = FillColorTable(hdc, hpal, ref pbmi);
                }
                else
                {
                    if (pbmi.bmiHeader_biCompression == NativeMethods.BI_BITFIELDS)
                    {
                        // Call a second time to get the color masks.
                        Interop.Gdi32.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)
                {
                    Interop.Gdi32.DeleteObject(hbm);
                    hbm = IntPtr.Zero;
                }
            }
            return(bRet);
        }
Beispiel #2
0
        /// <summary>
        /// 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.
        /// </summary>
        /// <returns>True is successful, false otherwise.</returns>
        private unsafe bool FillColorTable(IntPtr hdc, IntPtr hpal, ref Interop.Gdi32.BITMAPINFO_FLAT pbmi)
        {
            byte[] aj = new byte[sizeof(NativeMethods.PALETTEENTRY) * 256];

            fixed(byte *pcolors = pbmi.bmiColors)
            {
                fixed(byte *ppal = aj)
                {
                    NativeMethods.RGBQUAD *     prgb = (NativeMethods.RGBQUAD *)pcolors;
                    NativeMethods.PALETTEENTRY *lppe = (NativeMethods.PALETTEENTRY *)ppal;

                    int cColors = 1 << pbmi.bmiHeader_biBitCount;

                    if (cColors <= 256)
                    {
                        // Note: we don't support 4bpp displays.
                        uint   palRet;
                        IntPtr palHalftone = IntPtr.Zero;
                        if (hpal == IntPtr.Zero)
                        {
                            palHalftone = Graphics.GetHalftonePalette();
                            palRet      = Interop.Gdi32.GetPaletteEntries(new HandleRef(null, palHalftone), 0, cColors, aj);
                        }
                        else
                        {
                            palRet = Interop.Gdi32.GetPaletteEntries(new HandleRef(null, hpal), 0, cColors, aj);
                        }

                        if (palRet != 0)
                        {
                            for (int 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;
                            }

                            return(true);
                        }
                    }
                }
            }

            return(false);
        }
Beispiel #3
0
        /// <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;

            Interop.Gdi32.BITMAPINFO_FLAT pbmi = default;

            // 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 = Interop.Gdi32.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);
        }