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);
        }
Esempio n. 2
0
 private static Icon GetIcon(ref Icon icon, int iconId)
 {
     return(icon ?? (icon = new Icon(SafeNativeMethods.LoadIcon(NativeMethods.NullHandleRef, iconId))));
 }
Esempio n. 3
0
        private Bitmap BmpFrame()
        {
            Bitmap bitmap = null;

            if (_iconData != null && _bestBitDepth == 32)
            {
                // GDI+ doesnt handle 32 bpp icons with alpha properly
                // we load the icon ourself from the byte table
                bitmap = new Bitmap(Size.Width, Size.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                Debug.Assert(_bestImageOffset >= 0 && (_bestImageOffset + _bestBytesInRes) <= _iconData.Length, "Illegal offset/length for the Icon data");

                unsafe
                {
                    BitmapData bmpdata = bitmap.LockBits(new Rectangle(0, 0, Size.Width, Size.Height),
                                                         ImageLockMode.WriteOnly,
                                                         PixelFormat.Format32bppArgb);
                    try
                    {
                        uint *pixelPtr = (uint *)bmpdata.Scan0.ToPointer();

                        // jumping the image header
                        int newOffset = _bestImageOffset + Marshal.SizeOf(typeof(SafeNativeMethods.BITMAPINFOHEADER));
                        // there is no color table that we need to skip since we're 32bpp

                        int lineLength = Size.Width * 4;
                        int width      = Size.Width;
                        for (int j = (Size.Height - 1) * 4; j >= 0; j -= 4)
                        {
                            Marshal.Copy(_iconData, newOffset + j * width, (IntPtr)pixelPtr, lineLength);
                            pixelPtr += width;
                        }

                        // note: we ignore the mask that's available after the pixel table
                    }
                    finally
                    {
                        bitmap.UnlockBits(bmpdata);
                    }
                }
            }
            else if (_bestBitDepth == 0 || _bestBitDepth == 32)
            {
                // This may be a 32bpp icon or an icon without any data.
                var info = new SafeNativeMethods.ICONINFO();
                SafeNativeMethods.GetIconInfo(new HandleRef(this, _handle), info);
                var bmp = new SafeNativeMethods.BITMAP();
                try
                {
                    if (info.hbmColor != IntPtr.Zero)
                    {
                        SafeNativeMethods.GetObject(new HandleRef(null, info.hbmColor), Marshal.SizeOf(typeof(SafeNativeMethods.BITMAP)), bmp);
                        if (bmp.bmBitsPixel == 32)
                        {
                            Bitmap     tmpBitmap  = null;
                            BitmapData bmpData    = null;
                            BitmapData targetData = null;
                            try
                            {
                                tmpBitmap = Image.FromHbitmap(info.hbmColor);

                                // In GDI+ the bits are there but the bitmap was created with no alpha channel
                                // so copy the bits by hand to a new bitmap
                                // we also need to go around a limitation in the way the ICON is stored (ie if it's another bpp
                                // but stored in 32bpp all pixels are transparent and not opaque)
                                // (Here you mostly need to remain calm....)
                                bmpData = tmpBitmap.LockBits(new Rectangle(0, 0, tmpBitmap.Width, tmpBitmap.Height), ImageLockMode.ReadOnly, tmpBitmap.PixelFormat);

                                // we need do the following if the image has alpha because otherwise the image is fully transparent even though it has data
                                if (BitmapHasAlpha(bmpData))
                                {
                                    bitmap     = new Bitmap(bmpData.Width, bmpData.Height, PixelFormat.Format32bppArgb);
                                    targetData = bitmap.LockBits(new Rectangle(0, 0, bmpData.Width, bmpData.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);

                                    CopyBitmapData(bmpData, targetData);
                                }
                            }
                            finally
                            {
                                if (tmpBitmap != null && bmpData != null)
                                {
                                    tmpBitmap.UnlockBits(bmpData);
                                }
                                if (bitmap != null && targetData != null)
                                {
                                    bitmap.UnlockBits(targetData);
                                }
                            }
                            tmpBitmap.Dispose();
                        }
                    }
                }
                finally
                {
                    if (info.hbmColor != IntPtr.Zero)
                    {
                        SafeNativeMethods.IntDeleteObject(new HandleRef(null, info.hbmColor));
                    }
                    if (info.hbmMask != IntPtr.Zero)
                    {
                        SafeNativeMethods.IntDeleteObject(new HandleRef(null, info.hbmMask));
                    }
                }
            }


            if (bitmap == null)
            {
                // last chance... all the other cases (ie non 32 bpp icons coming from a handle or from the bitmapData)

                // we have to do this rather than just return Bitmap.FromHIcon because
                // the bitmap returned from that, even though it's 32bpp, just paints where the mask allows it
                // seems like another GDI+ weirdness. might be interesting to investigate further. In the meantime
                // this looks like the right thing to do and is not more expansive that what was present before.

                Size size = Size;
                bitmap = new Bitmap(size.Width, size.Height); // initialized to transparent
                Graphics graphics = null;
                using (graphics = Graphics.FromImage(bitmap))
                {
                    try
                    {
                        using (Bitmap tmpBitmap = Bitmap.FromHicon(Handle))
                        {
                            graphics.DrawImage(tmpBitmap, new Rectangle(0, 0, size.Width, size.Height));
                        }
                    }
                    catch (ArgumentException)
                    {
                        // Sometimes FromHicon will crash with no real reason.
                        // The backup plan is to just draw the image like we used to.
                        // NOTE: FromHIcon is also where we have the buffer overrun
                        // if width and height are mismatched.
                        Draw(graphics, new Rectangle(0, 0, size.Width, size.Height));
                    }
                }


                // GDI+ fills the surface with a sentinel color for GetDC, but does
                // not correctly clean it up again, so we have to do it.
                Color fakeTransparencyColor = Color.FromArgb(0x0d, 0x0b, 0x0c);
                bitmap.MakeTransparent(fakeTransparencyColor);
            }

            Debug.Assert(bitmap != null, "Bitmap cannot be null");
            return(bitmap);
        }
        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);
        }
Esempio n. 5
0
        // Draws this image to a graphics object.  The drawing command originates on the graphics
        // object, but a graphics object generally has no idea how to render a given image.  So,
        // it passes the call to the actual image.  This version crops the image to the given
        // dimensions and allows the user to specify a rectangle within the image to draw.
        private void DrawIcon(IntPtr dc, Rectangle imageRect, Rectangle targetRect, bool stretch)
        {
            int imageX = 0;
            int imageY = 0;
            int imageWidth;
            int imageHeight;
            int targetX      = 0;
            int targetY      = 0;
            int targetWidth  = 0;
            int targetHeight = 0;

            Size cursorSize = Size;

            // Compute the dimensions of the icon if needed.
            if (!imageRect.IsEmpty)
            {
                imageX      = imageRect.X;
                imageY      = imageRect.Y;
                imageWidth  = imageRect.Width;
                imageHeight = imageRect.Height;
            }
            else
            {
                imageWidth  = cursorSize.Width;
                imageHeight = cursorSize.Height;
            }

            if (!targetRect.IsEmpty)
            {
                targetX      = targetRect.X;
                targetY      = targetRect.Y;
                targetWidth  = targetRect.Width;
                targetHeight = targetRect.Height;
            }
            else
            {
                targetWidth  = cursorSize.Width;
                targetHeight = cursorSize.Height;
            }

            int drawWidth, drawHeight;
            int clipWidth, clipHeight;

            if (stretch)
            {
                drawWidth  = cursorSize.Width * targetWidth / imageWidth;
                drawHeight = cursorSize.Height * targetHeight / imageHeight;
                clipWidth  = targetWidth;
                clipHeight = targetHeight;
            }
            else
            {
                drawWidth  = cursorSize.Width;
                drawHeight = cursorSize.Height;
                clipWidth  = targetWidth < imageWidth ? targetWidth : imageWidth;
                clipHeight = targetHeight < imageHeight ? targetHeight : imageHeight;
            }

            // The ROP is SRCCOPY, so we can be simple here and take
            // advantage of clipping regions.  Drawing the cursor
            // is merely a matter of offsetting and clipping.
            IntPtr hSaveRgn = SafeNativeMethods.SaveClipRgn(dc);

            try
            {
                SafeNativeMethods.IntersectClipRect(new HandleRef(this, dc), targetX, targetY, targetX + clipWidth, targetY + clipHeight);
                SafeNativeMethods.DrawIconEx(new HandleRef(null, dc),
                                             targetX - imageX,
                                             targetY - imageY,
                                             new HandleRef(this, _handle),
                                             drawWidth,
                                             drawHeight,
                                             0,
                                             NativeMethods.NullHandleRef,
                                             SafeNativeMethods.DI_NORMAL);
            }
            finally
            {
                SafeNativeMethods.RestoreClipRgn(dc, hSaveRgn);
            }
        }
Esempio n. 6
0
        // Initializes this Image object.  This is identical to calling the image's
        // constructor with picture, but this allows non-constructor initialization,
        // which may be necessary in some instances.
        private unsafe void Initialize(int width, int height)
        {
            if (_iconData == null || _handle != IntPtr.Zero)
            {
                throw new InvalidOperationException(SR.Format(SR.IllegalState, GetType().Name));
            }

            int icondirSize = Marshal.SizeOf(typeof(SafeNativeMethods.ICONDIR));

            if (_iconData.Length < icondirSize)
            {
                throw new ArgumentException(SR.Format(SR.InvalidPictureType, "picture", nameof(Icon)));
            }

            // Get the correct width and height.
            if (width == 0)
            {
                width = UnsafeNativeMethods.GetSystemMetrics(SafeNativeMethods.SM_CXICON);
            }

            if (height == 0)
            {
                height = UnsafeNativeMethods.GetSystemMetrics(SafeNativeMethods.SM_CYICON);
            }

            if (s_bitDepth == 0)
            {
                IntPtr dc = UnsafeNativeMethods.GetDC(NativeMethods.NullHandleRef);
                s_bitDepth  = UnsafeNativeMethods.GetDeviceCaps(new HandleRef(null, dc), SafeNativeMethods.BITSPIXEL);
                s_bitDepth *= UnsafeNativeMethods.GetDeviceCaps(new HandleRef(null, dc), SafeNativeMethods.PLANES);
                UnsafeNativeMethods.ReleaseDC(NativeMethods.NullHandleRef, new HandleRef(null, dc));

                // If the bitdepth is 8, make it 4 because windows does not
                // choose a 256 color icon if the display is running in 256 color mode
                // due to palette flicker.
                if (s_bitDepth == 8)
                {
                    s_bitDepth = 4;
                }
            }

            fixed(byte *pbIconData = _iconData)
            {
                short idReserved = GetShort(pbIconData);
                short idType     = GetShort(pbIconData + 2);
                short idCount    = GetShort(pbIconData + 4);

                if (idReserved != 0 || idType != 1 || idCount == 0)
                {
                    throw new ArgumentException(SR.Format(SR.InvalidPictureType, "picture", nameof(Icon)));
                }

                SafeNativeMethods.ICONDIRENTRY EntryTemp;

                byte bestWidth  = 0;
                byte bestHeight = 0;

                byte *pbIconDirEntry   = unchecked (pbIconData + 6);
                int   icondirEntrySize = Marshal.SizeOf(typeof(SafeNativeMethods.ICONDIRENTRY));

                if ((icondirEntrySize * (idCount - 1) + icondirSize) > _iconData.Length)
                {
                    throw new ArgumentException(SR.Format(SR.InvalidPictureType, "picture", nameof(Icon)));
                }

                for (int i = 0; i < idCount; i++)
                {
                    // Fill in EntryTemp
                    EntryTemp.bWidth        = pbIconDirEntry[0];
                    EntryTemp.bHeight       = pbIconDirEntry[1];
                    EntryTemp.bColorCount   = pbIconDirEntry[2];
                    EntryTemp.bReserved     = pbIconDirEntry[3];
                    EntryTemp.wPlanes       = GetShort(pbIconDirEntry + 4);
                    EntryTemp.wBitCount     = GetShort(pbIconDirEntry + 6);
                    EntryTemp.dwBytesInRes  = GetInt(pbIconDirEntry + 8);
                    EntryTemp.dwImageOffset = GetInt(pbIconDirEntry + 12);

                    bool fUpdateBestFit = false;
                    int  iconBitDepth   = 0;
                    if (EntryTemp.bColorCount != 0)
                    {
                        iconBitDepth = 4;
                        if (EntryTemp.bColorCount < 0x10)
                        {
                            iconBitDepth = 1;
                        }
                    }
                    else
                    {
                        iconBitDepth = EntryTemp.wBitCount;
                    }

                    // If it looks like if nothing is specified at this point then set the bits per pixel to 8.
                    if (iconBitDepth == 0)
                    {
                        iconBitDepth = 8;
                    }

                    //  Windows rules for specifing an icon:
                    //
                    //  1.  The icon with the closest size match.
                    //  2.  For matching sizes, the image with the closest bit depth.
                    //  3.  If there is no color depth match, the icon with the closest color depth that does not exceed the display.
                    //  4.  If all icon color depth > display, lowest color depth is chosen.
                    //  5.  color depth of > 8bpp are all equal.
                    //  6.  Never choose an 8bpp icon on an 8bpp system.
                    //

                    if (_bestBytesInRes == 0)
                    {
                        fUpdateBestFit = true;
                    }
                    else
                    {
                        int bestDelta = Math.Abs(bestWidth - width) + Math.Abs(bestHeight - height);
                        int thisDelta = Math.Abs(EntryTemp.bWidth - width) + Math.Abs(EntryTemp.bHeight - height);

                        if ((thisDelta < bestDelta) ||
                            (thisDelta == bestDelta && (iconBitDepth <= s_bitDepth && iconBitDepth > _bestBitDepth || _bestBitDepth > s_bitDepth && iconBitDepth < _bestBitDepth)))
                        {
                            fUpdateBestFit = true;
                        }
                    }

                    if (fUpdateBestFit)
                    {
                        bestWidth        = EntryTemp.bWidth;
                        bestHeight       = EntryTemp.bHeight;
                        _bestImageOffset = EntryTemp.dwImageOffset;
                        _bestBytesInRes  = EntryTemp.dwBytesInRes;
                        _bestBitDepth    = iconBitDepth;
                    }

                    pbIconDirEntry += icondirEntrySize;
                }

                if (_bestImageOffset < 0)
                {
                    throw new ArgumentException(SR.Format(SR.InvalidPictureType, "picture", nameof(Icon)));
                }

                if (_bestBytesInRes < 0)
                {
                    throw new Win32Exception(SafeNativeMethods.ERROR_INVALID_PARAMETER);
                }

                int endOffset;

                try
                {
                    endOffset = checked (_bestImageOffset + _bestBytesInRes);
                }
                catch (OverflowException)
                {
                    throw new Win32Exception(SafeNativeMethods.ERROR_INVALID_PARAMETER);
                }

                if (endOffset > _iconData.Length)
                {
                    throw new ArgumentException(SR.Format(SR.InvalidPictureType, "picture", nameof(Icon)));
                }

                // Copy the bytes into an aligned buffer if needed.
                if ((_bestImageOffset % IntPtr.Size) != 0)
                {
                    // Beginning of icon's content is misaligned.
                    byte[] alignedBuffer = new byte[_bestBytesInRes];
                    Array.Copy(_iconData, _bestImageOffset, alignedBuffer, 0, _bestBytesInRes);

                    fixed(byte *pbAlignedBuffer = alignedBuffer)
                    {
                        _handle = SafeNativeMethods.CreateIconFromResourceEx(pbAlignedBuffer, _bestBytesInRes, true, 0x00030000, 0, 0, 0);
                    }
                }
                else
                {
                    try
                    {
                        _handle = SafeNativeMethods.CreateIconFromResourceEx(checked (pbIconData + _bestImageOffset), _bestBytesInRes, true, 0x00030000, 0, 0, 0);
                    }
                    catch (OverflowException)
                    {
                        throw new Win32Exception(SafeNativeMethods.ERROR_INVALID_PARAMETER);
                    }
                }
                if (_handle == IntPtr.Zero)
                {
                    throw new Win32Exception();
                }
            }
        }
 public LOGFONT(SafeNativeMethods.LOGFONT lf)
 {
     this.lfHeight = lf.lfHeight;
     this.lfWidth = lf.lfWidth;
     this.lfEscapement = lf.lfEscapement;
     this.lfOrientation = lf.lfOrientation;
     this.lfWeight = lf.lfWeight;
     this.lfItalic = lf.lfItalic;
     this.lfUnderline = lf.lfUnderline;
     this.lfStrikeOut = lf.lfStrikeOut;
     this.lfCharSet = lf.lfCharSet;
     this.lfOutPrecision = lf.lfOutPrecision;
     this.lfClipPrecision = lf.lfClipPrecision;
     this.lfQuality = lf.lfQuality;
     this.lfPitchAndFamily = lf.lfPitchAndFamily;
     this.lfFaceName = lf.lfFaceName;
 }
Esempio n. 8
0
        /// <include file='doc\Icon.uex' path='docs/doc[@for="Icon.Initialize"]/*' />
        /// <devdoc>
        ///     Initializes this Image object.  This is identical to calling the image's
        ///     constructor with picture, but this allows non-constructor initialization,
        ///     which may be necessary in some instances.
        /// </devdoc>
        private unsafe void Initialize(int width, int height)
        {
            if (iconData == null || handle != IntPtr.Zero)
            {
                throw new InvalidOperationException(SR.GetString(SR.IllegalState, GetType().Name));
            }

            if (iconData.Length < Marshal.SizeOf(typeof(SafeNativeMethods.ICONDIR)))
            {
                throw new ArgumentException(SR.GetString(SR.InvalidPictureType, "picture", "Icon"));
            }

            // Get the correct width / height
            //
            if (width == 0)
            {
                width = UnsafeNativeMethods.GetSystemMetrics(SafeNativeMethods.SM_CXICON);
            }

            if (height == 0)
            {
                height = UnsafeNativeMethods.GetSystemMetrics(SafeNativeMethods.SM_CYICON);
            }


            if (bitDepth == 0)
            {
                IntPtr dc = UnsafeNativeMethods.GetDC(NativeMethods.NullHandleRef);
                bitDepth  = UnsafeNativeMethods.GetDeviceCaps(new HandleRef(null, dc), SafeNativeMethods.BITSPIXEL);
                bitDepth *= UnsafeNativeMethods.GetDeviceCaps(new HandleRef(null, dc), SafeNativeMethods.PLANES);
                UnsafeNativeMethods.ReleaseDC(NativeMethods.NullHandleRef, new HandleRef(null, dc));

                // If the bitdepth is 8, make it 4.  Why?  Because windows does not
                // choose a 256 color icon if the display is running in 256 color mode
                // because of palette flicker.
                //
                if (bitDepth == 8)
                {
                    bitDepth = 4;
                }
            }

            fixed(byte *pbIconData = iconData)
            {
                SafeNativeMethods.ICONDIR *pIconDir = (SafeNativeMethods.ICONDIR *)pbIconData;

                if (pIconDir->idReserved != 0 || pIconDir->idType != 1 || pIconDir->idCount == 0)
                {
                    throw new ArgumentException(SR.GetString(SR.InvalidPictureType, "picture", "Icon"));
                }

                SafeNativeMethods.ICONDIRENTRY *pIconDirEntry = &pIconDir->idEntries;
                SafeNativeMethods.ICONDIRENTRY *pBestFit      = null;
                int bestBitDepth = 0;

                int icondirEntrySize = Marshal.SizeOf(typeof(SafeNativeMethods.ICONDIRENTRY));

                Debug.Assert((icondirEntrySize * pIconDir->idCount) < iconData.Length, "Illegal number of ICONDIRENTRIES");

                if ((icondirEntrySize * pIconDir->idCount) >= iconData.Length)
                {
                    throw new ArgumentException(SR.GetString(SR.InvalidPictureType, "picture", "Icon"));
                }

                for (int i = 0; i < pIconDir->idCount; i++)
                {
                    int iconBitDepth = pIconDirEntry->wPlanes * pIconDirEntry->wBitCount;

                    if (iconBitDepth == 0)
                    {
                        if (pIconDirEntry->bColorCount == 0)
                        {
                            iconBitDepth = 16;
                        }
                        else
                        {
                            iconBitDepth = 8;
                            if (pIconDirEntry->bColorCount < 0xFF)
                            {
                                iconBitDepth = 4;
                            }
                            if (pIconDirEntry->bColorCount < 0x10)
                            {
                                iconBitDepth = 2;
                            }
                        }
                    }

                    //  Windows rules for specifing an icon:
                    //
                    //  1.  The icon with the closest size match.
                    //  2.  For matching sizes, the image with the closest bit depth.
                    //  3.  If there is no color depth match, the icon with the closest color depth that does not exceed the display.
                    //  4.  If all icon color depth > display, lowest color depth is chosen.
                    //  5.  color depth of > 8bpp are all equal.
                    //  6.  Never choose an 8bpp icon on an 8bpp system.
                    //

                    if (pBestFit == null)
                    {
                        pBestFit     = pIconDirEntry;
                        bestBitDepth = iconBitDepth;
                    }
                    else
                    {
                        int bestDelta = Math.Abs(pBestFit->bWidth - width) + Math.Abs(pBestFit->bHeight - height);
                        int thisDelta = Math.Abs(pIconDirEntry->bWidth - width) + Math.Abs(pIconDirEntry->bHeight - height);

                        if (thisDelta < bestDelta)
                        {
                            pBestFit     = pIconDirEntry;
                            bestBitDepth = iconBitDepth;
                        }
                        else if (thisDelta == bestDelta && (iconBitDepth <= bitDepth && iconBitDepth > bestBitDepth || bestBitDepth > bitDepth && iconBitDepth < bestBitDepth))
                        {
                            pBestFit     = pIconDirEntry;
                            bestBitDepth = iconBitDepth;
                        }
                    }

                    pIconDirEntry++;
                }

                Debug.Assert(pBestFit->dwImageOffset >= 0 && (pBestFit->dwImageOffset + pBestFit->dwBytesInRes) <= iconData.Length, "Illegal offset/length for the Icon data");

                if (pBestFit->dwImageOffset < 0 || (pBestFit->dwImageOffset + pBestFit->dwBytesInRes) > iconData.Length)
                {
                    throw new ArgumentException(SR.GetString(SR.InvalidPictureType, "picture", "Icon"));
                }

                handle = SafeNativeMethods.CreateIconFromResourceEx(pbIconData + pBestFit->dwImageOffset, pBestFit->dwBytesInRes, true, 0x00030000, 0, 0, 0);
                if (handle == IntPtr.Zero)
                {
                    throw new Win32Exception();
                }
            }
        }
Esempio n. 9
0
 private static int SystemColorToArgb(int index)
 {
     return(FromWin32Value(SafeNativeMethods.GetSysColor(index)));
 }
 private System.Drawing.Printing.PrinterResolution PrinterResolutionFromMode(SafeNativeMethods.DEVMODE mode)
 {
     System.Drawing.Printing.PrinterResolution[] resolutionArray = this.printerSettings.Get_PrinterResolutions();
     for (int i = 0; i < resolutionArray.Length; i++)
     {
         if (((mode.dmPrintQuality >= 0) && ((mode.dmFields & 0x400) == 0x400)) && ((mode.dmFields & 0x2000) == 0x2000))
         {
             if ((resolutionArray[i].X == mode.dmPrintQuality) && (resolutionArray[i].Y == mode.dmYResolution))
             {
                 return resolutionArray[i];
             }
         }
         else if (((mode.dmFields & 0x400) == 0x400) && (resolutionArray[i].Kind == ((PrinterResolutionKind) mode.dmPrintQuality)))
         {
             return resolutionArray[i];
         }
     }
     return new System.Drawing.Printing.PrinterResolution(PrinterResolutionKind.Custom, mode.dmPrintQuality, mode.dmYResolution);
 }
 private System.Drawing.Printing.PaperSource PaperSourceFromMode(SafeNativeMethods.DEVMODE mode)
 {
     System.Drawing.Printing.PaperSource[] sourceArray = this.printerSettings.Get_PaperSources();
     if ((mode.dmFields & 0x200) == 0x200)
     {
         for (int i = 0; i < sourceArray.Length; i++)
         {
             if (((short) sourceArray[i].RawKind) == mode.dmDefaultSource)
             {
                 return sourceArray[i];
             }
         }
     }
     return new System.Drawing.Printing.PaperSource((PaperSourceKind) mode.dmDefaultSource, "unknown");
 }
 private System.Drawing.Printing.PaperSize PaperSizeFromMode(SafeNativeMethods.DEVMODE mode)
 {
     System.Drawing.Printing.PaperSize[] sizeArray = this.printerSettings.Get_PaperSizes();
     if ((mode.dmFields & 2) == 2)
     {
         for (int i = 0; i < sizeArray.Length; i++)
         {
             if (sizeArray[i].RawKind == mode.dmPaperSize)
             {
                 return sizeArray[i];
             }
         }
     }
     return new System.Drawing.Printing.PaperSize(PaperKind.Custom, "custom", PrinterUnitConvert.Convert((int) mode.dmPaperWidth, PrinterUnit.TenthsOfAMillimeter, PrinterUnit.Display), PrinterUnitConvert.Convert((int) mode.dmPaperLength, PrinterUnit.TenthsOfAMillimeter, PrinterUnit.Display));
 }
        // Initializes this Image object.  This is identical to calling the image's
        // constructor with picture, but this allows non-constructor initialization,
        // which may be necessary in some instances.
        private unsafe void Initialize(int width, int height)
        {
            if (_iconData == null || _handle != IntPtr.Zero)
            {
                throw new InvalidOperationException(SR.Format(SR.IllegalState, GetType().Name));
            }

            if (_iconData.Length < sizeof(SafeNativeMethods.ICONDIR))
            {
                throw new ArgumentException(SR.Format(SR.InvalidPictureType, "picture", nameof(Icon)));
            }

            // Get the correct width and height.
            if (width == 0)
            {
                width = UnsafeNativeMethods.GetSystemMetrics(SafeNativeMethods.SM_CXICON);
            }

            if (height == 0)
            {
                height = UnsafeNativeMethods.GetSystemMetrics(SafeNativeMethods.SM_CYICON);
            }

            if (s_bitDepth == 0)
            {
                IntPtr dc = UnsafeNativeMethods.GetDC(NativeMethods.NullHandleRef);
                s_bitDepth  = UnsafeNativeMethods.GetDeviceCaps(new HandleRef(null, dc), SafeNativeMethods.BITSPIXEL);
                s_bitDepth *= UnsafeNativeMethods.GetDeviceCaps(new HandleRef(null, dc), SafeNativeMethods.PLANES);
                UnsafeNativeMethods.ReleaseDC(NativeMethods.NullHandleRef, new HandleRef(null, dc));

                // If the bitdepth is 8, make it 4 because windows does not
                // choose a 256 color icon if the display is running in 256 color mode
                // due to palette flicker.
                if (s_bitDepth == 8)
                {
                    s_bitDepth = 4;
                }
            }

            fixed(byte *b = _iconData)
            {
                SafeNativeMethods.ICONDIR *dir = (SafeNativeMethods.ICONDIR *)b;

                if (dir->idReserved != 0 || dir->idType != 1 || dir->idCount == 0)
                {
                    throw new ArgumentException(SR.Format(SR.InvalidPictureType, "picture", nameof(Icon)));
                }

                byte bestWidth  = 0;
                byte bestHeight = 0;

                if (sizeof(SafeNativeMethods.ICONDIRENTRY) * (dir->idCount - 1) + sizeof(SafeNativeMethods.ICONDIR)
                    > _iconData.Length)
                {
                    throw new ArgumentException(SR.Format(SR.InvalidPictureType, "picture", nameof(Icon)));
                }

                var entries = new ReadOnlySpan <SafeNativeMethods.ICONDIRENTRY>(&dir->idEntries, dir->idCount);

                foreach (SafeNativeMethods.ICONDIRENTRY entry in entries)
                {
                    bool fUpdateBestFit = false;
                    uint iconBitDepth;
                    if (entry.bColorCount != 0)
                    {
                        iconBitDepth = 4;
                        if (entry.bColorCount < 0x10)
                        {
                            iconBitDepth = 1;
                        }
                    }
                    else
                    {
                        iconBitDepth = entry.wBitCount;
                    }

                    // If it looks like if nothing is specified at this point then set the bits per pixel to 8.
                    if (iconBitDepth == 0)
                    {
                        iconBitDepth = 8;
                    }

                    //  Windows rules for specifing an icon:
                    //
                    //  1.  The icon with the closest size match.
                    //  2.  For matching sizes, the image with the closest bit depth.
                    //  3.  If there is no color depth match, the icon with the closest color depth that does not exceed the display.
                    //  4.  If all icon color depth > display, lowest color depth is chosen.
                    //  5.  color depth of > 8bpp are all equal.
                    //  6.  Never choose an 8bpp icon on an 8bpp system.

                    if (_bestBytesInRes == 0)
                    {
                        fUpdateBestFit = true;
                    }
                    else
                    {
                        int bestDelta = Math.Abs(bestWidth - width) + Math.Abs(bestHeight - height);
                        int thisDelta = Math.Abs(entry.bWidth - width) + Math.Abs(entry.bHeight - height);

                        if ((thisDelta < bestDelta) ||
                            (thisDelta == bestDelta && (0 <= s_bitDepth && 0 > _bestBitDepth || _bestBitDepth > s_bitDepth && 0 < _bestBitDepth)))
                        {
                            fUpdateBestFit = true;
                        }
                    }

                    if (fUpdateBestFit)
                    {
                        bestWidth        = entry.bWidth;
                        bestHeight       = entry.bHeight;
                        _bestImageOffset = entry.dwImageOffset;
                        _bestBytesInRes  = entry.dwBytesInRes;
                        _bestBitDepth    = iconBitDepth;
                    }
                }

                if (_bestImageOffset > int.MaxValue)
                {
                    throw new ArgumentException(SR.Format(SR.InvalidPictureType, "picture", nameof(Icon)));
                }

                if (_bestBytesInRes > int.MaxValue)
                {
                    throw new Win32Exception(SafeNativeMethods.ERROR_INVALID_PARAMETER);
                }

                uint endOffset;

                try
                {
                    endOffset = checked (_bestImageOffset + _bestBytesInRes);
                }
                catch (OverflowException)
                {
                    throw new Win32Exception(SafeNativeMethods.ERROR_INVALID_PARAMETER);
                }

                if (endOffset > _iconData.Length)
                {
                    throw new ArgumentException(SR.Format(SR.InvalidPictureType, "picture", nameof(Icon)));
                }

                // Copy the bytes into an aligned buffer if needed.
                if ((_bestImageOffset % IntPtr.Size) != 0)
                {
                    // Beginning of icon's content is misaligned.
                    byte[] alignedBuffer = ArrayPool <byte> .Shared.Rent((int)_bestBytesInRes);

                    Array.Copy(_iconData, _bestImageOffset, alignedBuffer, 0, _bestBytesInRes);

                    fixed(byte *pbAlignedBuffer = alignedBuffer)
                    {
                        _handle = SafeNativeMethods.CreateIconFromResourceEx(pbAlignedBuffer, _bestBytesInRes, true, 0x00030000, 0, 0, 0);
                    }

                    ArrayPool <byte> .Shared.Return(alignedBuffer);
                }
                else
                {
                    try
                    {
                        _handle = SafeNativeMethods.CreateIconFromResourceEx(checked (b + _bestImageOffset), _bestBytesInRes, true, 0x00030000, 0, 0, 0);
                    }
                    catch (OverflowException)
                    {
                        throw new Win32Exception(SafeNativeMethods.ERROR_INVALID_PARAMETER);
                    }
                }

                if (_handle == IntPtr.Zero)
                {
                    throw new Win32Exception();
                }
            }
        }