Icon.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / whidbey / NetFXspW7 / ndp / fx / src / CommonUI / System / Drawing / Icon.cs / 1 / Icon.cs

                            // #define CUSTOM_MARSHALING_ISTREAM 

//------------------------------------------------------------------------------
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved. 
// 
//----------------------------------------------------------------------------- 
 
/*
 */ 
namespace System.Drawing {
    using System.Runtime.Serialization.Formatters;
    using System.Runtime.InteropServices;
    using System.Runtime.Serialization; 
    using System.Security;
    using System.Security.Permissions; 
    using System.Diagnostics; 
    using System.Diagnostics.CodeAnalysis;
    using System; 
    using System.Collections;
    using System.ComponentModel;
    using Microsoft.Win32;
    using System.Drawing.Design; 
    using System.Drawing.Imaging;
    using System.IO; 
    using System.Reflection; 
    using System.Text;
    using System.Drawing.Internal; 

    /// 
    /// 
    ///     This class represents a Windows icon, which is a small bitmap image used to 
    ///     represent an object.  Icons can be thought of as transparent bitmaps, although
    ///     their size is determined by the system. 
    ///  
    [
    TypeConverterAttribute(typeof(IconConverter)), 
    Editor("System.Drawing.Design.IconEditor, " + AssemblyRef.SystemDrawingDesign, typeof(UITypeEditor))
    ]
    [Serializable]
    public sealed class Icon : MarshalByRefObject, ISerializable, ICloneable, IDisposable { 
#if FINALIZATION_WATCH
        private string allocationSite = Graphics.GetAllocationStack(); 
#endif 

        private static int bitDepth; 

        // Icon data
        //
        private byte[] iconData; 
        private int bestImageOffset;
        private int bestBitDepth; 
        private Size   iconSize = System.Drawing.Size.Empty; 
        private IntPtr handle = IntPtr.Zero;
        private bool   ownHandle = true; 

        private Icon() {
        }
 
        internal Icon(IntPtr handle) : this(handle, false) {
        } 
 
        internal Icon(IntPtr handle, bool takeOwnership) {
            if (handle == IntPtr.Zero) { 
                throw new ArgumentException(SR.GetString(SR.InvalidGDIHandle, (typeof(Icon)).Name));
            }
            this.handle = handle;
            this.ownHandle = takeOwnership; 
        }
 
 

        ///  
        /// 
        ///     Loads an icon object from the given filename.
        /// 
        public Icon(string fileName) : this(fileName, 0,0) { 
        }
 
        public Icon(string fileName, Size size) : this(fileName, size.Width, size.Height) { 
        }
 
        public Icon(string fileName, int width, int height) : this() {
            // SECREVIEW : This FileStream constructor demands FileIOPermission (FileIOPermissionAccess) for reading, writing,
            //             and appending to files so we don't need to set a demand here.
            // 
            using (FileStream f = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) {
                Debug.Assert(f != null, "File.OpenRead returned null instead of throwing an exception"); 
                iconData = new byte[(int)f.Length]; 
                f.Read(iconData, 0, iconData.Length);
            } 

            Initialize(width, height);
        }
 
        /// 
        ///  
        ///     Duplicates the given icon, attempting to find a version of the icon 
        ///     that matches the requested size.  If a version cannot be found that
        ///     exactally matches the size, the closest match will be used.  Note 
        ///     that if original is an icon with a single size, this will
        ///     merely create a dupicate icon.  You can use the stretching modes
        ///     of drawImage to force the icon to the size you want.
        ///  
        public Icon(Icon original, Size size) : this(original, size.Width, size.Height) {
        } 
 
        /// 
        ///  
        ///     Duplicates the given icon, attempting to find a version of the icon
        ///     that matches the requested size.  If a version cannot be found that
        ///     exactally matches the size, the closest match will be used.  Note
        ///     that if original is an icon with a single size, this will 
        ///     merely create a dupicate icon.  You can use the stretching modes
        ///     of drawImage to force the icon to the size you want. 
        ///  
        public Icon(Icon original, int width, int height) : this() {
            if (original == null) { 
                throw new ArgumentException(SR.GetString(SR.InvalidArgument, "original", "null"));
            }

            iconData = original.iconData; 

            if (iconData == null) { 
                iconSize = original.Size; 
                handle = SafeNativeMethods.CopyImage(new HandleRef(original, original.Handle), SafeNativeMethods.IMAGE_ICON, iconSize.Width, iconSize.Height, 0);
            } 
            else {
                Initialize(width, height);
            }
        } 

        ///  
        ///  
        ///     Loads an icon object from the given resource.
        ///  
        public Icon(Type type, string resource) : this() {
            Stream stream = type.Module.Assembly.GetManifestResourceStream(type, resource);
            if (stream == null) {
                throw new ArgumentException(SR.GetString(SR.ResourceNotFound, type, resource)); 
            }
 
            iconData = new byte[(int)stream.Length]; 
            stream.Read(iconData, 0, iconData.Length);
            Initialize(0, 0); 
        }

        /// 
        ///  
        ///     Loads an icon object from the given data stream.
        ///  
        public Icon(Stream stream) : this(stream, 0,0) { 
        }
        public Icon(Stream stream, Size size) : this(stream, size.Width, size.Height) { 
        }

        /// 
        ///  
        ///    [To be supplied.]
        ///  
        public Icon(Stream stream, int width, int height) : this() { 
            if (stream == null) {
                throw new ArgumentException(SR.GetString(SR.InvalidArgument, "stream", "null")); 
            }

            iconData = new byte[(int)stream.Length];
            stream.Read(iconData, 0, iconData.Length); 
            Initialize(width, height);
        } 
 

 
        /// 
        /// 
        ///     Constructor used in deserialization
        ///  
        /// 
        [SuppressMessage("Microsoft.Performance", "CA1808:AvoidCallsThatBoxValueTypes")] 
        private Icon(SerializationInfo info, StreamingContext context) { 
            iconData = (byte[])info.GetValue("IconData", typeof(byte[]));
            iconSize = (Size)info.GetValue("IconSize", typeof(Size)); 

            if (iconSize.IsEmpty) {
                Initialize(0, 0);
            } 
            else {
                Initialize(iconSize.Width, iconSize.Height); 
            } 
        }
 
        /// 
        /// 
        ///     Extracts an icon object from the given filename.
        ///  
        public static Icon ExtractAssociatedIcon(string filePath) {
            return ExtractAssociatedIcon(filePath, 0); 
        } 

        ///  
        /// 
        ///     Extracts an icon object from the given filename.
        /// 
        private static Icon ExtractAssociatedIcon(string filePath, int index) { 
            if (filePath == null) {
                throw new ArgumentException(SR.GetString(SR.InvalidArgument, "filePath", "null")); 
            } 

            Uri uri; 
            try
            {
                uri = new Uri(filePath);
            } 
            catch (UriFormatException)
            { 
                // It's a relative pathname, get its full path as a file. 
                // SECREVIEW : If path does exist, the caller must have FileIOPermissionAccess.PathDiscovery permission.
                //             Note that unlike most members of the Path class, this method accesses the file system. 
                //
                filePath = Path.GetFullPath(filePath);
                uri = new Uri(filePath);
            } 
            if (uri.IsUnc) {
                throw new ArgumentException (SR.GetString (SR.InvalidArgument, "filePath", filePath)); 
            } 
            if (uri.IsFile)
            { 
                // SECREVIEW : The File.Exists() below will do the demand for the FileIOPermission
                //             for us. So, we do not need an additional demand anymore.
                //
                if (!File.Exists(filePath)) { 
                    // I have to do this so I can give a meaningful
                    // error back to the user. File.Exists() cal fail because of either 
                    // a failure to demand security or because the file does not exist. 
                    // Always telling the user that the file does not exist is not a good
                    // choice. So, we demand the permission again. This means that we are 
                    // going to demand the permission twice for the failure case, but that's
                    // better than always demanding the permission twice.
                    //
                    IntSecurity.DemandReadFileIO(filePath); 

                    throw new FileNotFoundException(filePath); 
                } 

                Icon icon = new Icon(); 

                StringBuilder sb = new StringBuilder(NativeMethods.MAX_PATH);
                sb.Append(filePath);
 
                IntPtr hIcon = SafeNativeMethods.ExtractAssociatedIcon(NativeMethods.NullHandleRef, sb, ref index);
 
                if (hIcon != IntPtr.Zero) { 
                    IntSecurity.ObjectFromWin32Handle.Demand();
                    icon = new Icon(hIcon, true); 
                    return icon;
                }
            }
            return null; 

        } 
 
        /// 
        ///  
        ///     The Win32 handle for this object.  This is not a copy of the handle; do
        ///     not free it.
        /// 
        [Browsable(false)] 
        public IntPtr Handle {
            // SECREVIEW : Getting the handle is ok, methods receiving a handle should demand security permissions though. 
            // 
            get {
                if (handle == IntPtr.Zero) { 
                    throw new ObjectDisposedException(GetType().Name);
                }
                return handle;
            } 
        }
 
        ///  
        /// 
        ///    [To be supplied.] 
        /// 
        [Browsable(false)]
        public int Height {
            get { return Size.Height;} 
        }
 
        ///  
        /// 
        ///     The size of this icon object. 
        /// 
        public Size Size {
            get {
                if (iconSize.IsEmpty) { 
                    SafeNativeMethods.ICONINFO info = new SafeNativeMethods.ICONINFO();
                    SafeNativeMethods.GetIconInfo(new HandleRef(this, Handle), info); 
                    SafeNativeMethods.BITMAP bmp = new SafeNativeMethods.BITMAP(); 

                    if (info.hbmColor != IntPtr.Zero) { 
                        SafeNativeMethods.GetObject(new HandleRef(null, info.hbmColor), Marshal.SizeOf(typeof(SafeNativeMethods.BITMAP)), bmp);
                        SafeNativeMethods.IntDeleteObject(new HandleRef(null, info.hbmColor));
                        iconSize = new Size(bmp.bmWidth, bmp.bmHeight);
                    } 
                    else if (info.hbmMask != IntPtr.Zero) {
                        SafeNativeMethods.GetObject(new HandleRef(null, info.hbmMask), Marshal.SizeOf(typeof(SafeNativeMethods.BITMAP)), bmp); 
                        iconSize = new Size(bmp.bmWidth, bmp.bmHeight / 2); 
                    }
 
                    if (info.hbmMask != IntPtr.Zero) {
                        SafeNativeMethods.IntDeleteObject(new HandleRef(null, info.hbmMask));
                    }
                } 

                return iconSize; 
            } 
        }
 
        /// 
        /// 
        ///    [To be supplied.]
        ///  
        [Browsable(false)]
        public int Width { 
            get { return Size.Width;} 
        }
 
        /// 
        /// 
        ///     Clones the icon object, creating a duplicate image.
        ///  
        public object Clone() {
            return new Icon(this, Size.Width, Size.Height); 
        } 

        ///  
        /// 
        ///     Called when this object is going to destroy it's Win32 handle.  You
        ///     may override this if there is something special you need to do to
        ///     destroy the handle.  This will be called even if the handle is not 
        ///     owned by this object, which is handy if you want to create a
        ///     derived class that has it's own create/destroy semantics. 
        /// 
        ///     The default implementation will call the appropriate Win32
        ///     call to destroy the handle if this object currently owns the 
        ///     handle.  It will do nothing if the object does not currently
        ///     own the handle.
        /// 
        internal void DestroyHandle() { 
            if (ownHandle) {
                SafeNativeMethods.DestroyIcon(new HandleRef(this, handle)); 
                handle = IntPtr.Zero; 
            }
        } 

        /// 
        /// 
        ///     Cleans up the resources allocated by this object.  Once called, the cursor 
        ///     object is no longer useful.
        ///  
        public void Dispose() { 
            Dispose(true);
            GC.SuppressFinalize(this); 
        }

        void Dispose(bool disposing) {
            if (handle != IntPtr.Zero) { 
#if FINALIZATION_WATCH
                if (!disposing) { 
                    Debug.WriteLine("**********************\nDisposed through finalization:\n" + allocationSite); 
                }
#endif 
                DestroyHandle();
            }
        }
 
        /// 
        ///  
        ///     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.
        /// 
        // This method is way more powerful than what we expose, but I'll leave it in place.
        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);
            }
        } 

        internal void Draw(Graphics graphics, int x, int y) { 
            Size size = Size; 
            Draw(graphics, new Rectangle(x, y, size.Width, size.Height));
        } 

        /// 
        /// 
        ///     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 stretches the image to the given 
        ///     dimensions and allows the user to specify a rectangle within the image to draw. 
        /// 
        internal void Draw(Graphics graphics, Rectangle targetRect) { 
            Rectangle copy = targetRect;
            copy.X += (int) graphics.Transform.OffsetX;
            copy.Y += (int) graphics.Transform.OffsetY;
 
            WindowsGraphics wg = WindowsGraphics.FromGraphics(graphics, ApplyGraphicsProperties.Clipping);
            IntPtr dc = wg.GetHdc(); 
 
            try {
                DrawIcon(dc, Rectangle.Empty, copy, true); 
            }
            finally {
                wg.Dispose();
            } 
        }
 
        ///  
        /// 
        ///     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.
        ///  
        internal void DrawUnstretched(Graphics graphics, Rectangle targetRect) {
            Rectangle copy = targetRect; 
            copy.X += (int) graphics.Transform.OffsetX; 
            copy.Y += (int) graphics.Transform.OffsetY;
 
            WindowsGraphics wg = WindowsGraphics.FromGraphics(graphics, ApplyGraphicsProperties.Clipping);
            IntPtr dc = wg.GetHdc();
            try {
                DrawIcon(dc, Rectangle.Empty, copy, false); 
            }
            finally { 
                wg.Dispose(); 
            }
        } 

        /// 
        /// 
        ///     Cleans up Windows resources for this object. 
        /// 
        ~Icon() { 
            Dispose(false); 
        }
 
        /// 
        /// 
        ///     Creates an icon object from a given Win32 icon handle.  The Icon object
        ///     does not claim ownership of the icon handle; you must free it when you are 
        ///     done.
        ///  
        public static Icon FromHandle(IntPtr handle) { 
            IntSecurity.ObjectFromWin32Handle.Demand();
            return new Icon(handle); 
        }

        private unsafe short GetShort(byte* pb)
        { 
            int retval = 0;
            if (0 != (unchecked((byte)pb) & 1)) 
            { 
                retval = *pb;                   pb++;
                retval = retval | (*pb << 8); 
            }
            else
            {
                retval = (int)(*(short*)pb); 
            }
            return (short)retval; 
        } 

        private unsafe int GetInt(byte* pb) 
        {
            int retval = 0;
            if (0 != (unchecked((byte)pb) & 3))
            { 
                retval = *pb;                   pb++;
                retval = retval | (*pb <<  8);  pb++; 
                retval = retval | (*pb << 16);  pb++; 
                retval = retval | (*pb << 24);
            } 
            else
            {
                retval = *(int*)pb;
            } 
            return retval;
        } 
 

        ///  
        /// 
        ///     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.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)
            { 
                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.GetString(SR.InvalidPictureType, "picture", "Icon"));
                }
 
                SafeNativeMethods.ICONDIRENTRY  EntryTemp;
 
                byte    bestWidth           = 0; 
                byte    bestHeight          = 0;
                int     bestBytesInRes      = 0; 
                //int     bestBitDepth        = 0;

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

                Debug.Assert((icondirEntrySize * idCount) < iconData.Length, "Illegal number of ICONDIRENTRIES"); 
 
                if ((icondirEntrySize * idCount) >= iconData.Length)
                { 
                    throw new ArgumentException(SR.GetString(SR.InvalidPictureType, "picture", "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;
                    }

                    // it looks like if nothing is specified at this point, bpp is 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 (0 == bestBytesInRes) 
                    {
                        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 <= bitDepth && iconBitDepth > bestBitDepth || bestBitDepth > bitDepth && iconBitDepth < bestBitDepth)))
                        {
                            fUpdateBestFit = true;
                        } 
                    }
 
                    if (fUpdateBestFit) 
                    {
                        bestWidth       = EntryTemp.bWidth; 
                        bestHeight      = EntryTemp.bHeight;
                        bestImageOffset = EntryTemp.dwImageOffset;
                        bestBytesInRes  = EntryTemp.dwBytesInRes;
                        bestBitDepth    = iconBitDepth; 
                    }
 
                    pbIconDirEntry += icondirEntrySize; 
                }
 
                Debug.Assert(bestImageOffset >= 0 && (bestImageOffset + bestBytesInRes) <= iconData.Length, "Illegal offset/length for the Icon data");

                if (bestImageOffset < 0 || (bestImageOffset + bestBytesInRes) > iconData.Length)
                { 
                    throw new ArgumentException(SR.GetString(SR.InvalidPictureType, "picture", "Icon"));
                } 
 
                // See DevDivBugs 17509. Copying 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(this.iconData, bestImageOffset, alignedBuffer, 0, bestBytesInRes);
 
                    fixed (byte *pbAlignedBuffer = alignedBuffer) {
                        handle = SafeNativeMethods.CreateIconFromResourceEx(pbAlignedBuffer, bestBytesInRes, true, 0x00030000, 0, 0, 0); 
                    } 
                }
                else { 
                    handle = SafeNativeMethods.CreateIconFromResourceEx(pbIconData + bestImageOffset, bestBytesInRes, true, 0x00030000, 0, 0, 0);
                }
                if (handle == IntPtr.Zero) {
                    throw new Win32Exception(); 
                }
 
#if NEVER // old code 
                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();
                } 
#endif // WIN64
            }
        }
 
        /// 
        ///  
        ///     Saves this image to the given output stream. 
        /// 
        public void Save(Stream outputStream) { 
            if (iconData != null) {
                outputStream.Write(iconData, 0, iconData.Length);
            }
            else { 
                // Ideally, we would pick apart the icon using
                // GetIconInfo, and then pull the individual bitmaps out, 
                // converting them to DIBS and saving them into the file. 
                // But, in the interest of simplicity, we just call to
                // OLE to do it for us. 
                //
                SafeNativeMethods.IPicture picture;
                SafeNativeMethods.PICTDESC pictdesc = SafeNativeMethods.PICTDESC.CreateIconPICTDESC(Handle);
                Guid g = typeof(SafeNativeMethods.IPicture).GUID; 
                picture = SafeNativeMethods.OleCreatePictureIndirect(pictdesc, ref g, false);
 
                if (picture != null) { 
                    int temp;
                    try{ 
                        picture.SaveAsFile(new UnsafeNativeMethods.ComStreamFromDataStream(outputStream), -1, out temp);
                    }
                    finally{
                        Marshal.ReleaseComObject(picture); 
                    }
                } 
            } 
        }
 
        // SECREVIEW : Make sure the code calling this methods validates the source and target data.
        //
        // SAME CODE OR SIMILAR IN ImageList.cs
        private void CopyBitmapData(BitmapData sourceData, BitmapData targetData) { 
            // do the actual copy
            int offsetSrc = 0; 
            int offsetDest = 0; 

            Debug.Assert(sourceData.Height == targetData.Height, "Unexpected height. How did this happen?"); 

            for (int i = 0; i < Math.Min(sourceData.Height, targetData.Height); i++) {
                IntPtr srcPtr, destPtr;
                if (IntPtr.Size == 4) { 
                    srcPtr = new IntPtr(sourceData.Scan0.ToInt32() + offsetSrc);
                    destPtr = new IntPtr(targetData.Scan0.ToInt32() + offsetDest); 
                } else { 
                    srcPtr = new IntPtr(sourceData.Scan0.ToInt64() + offsetSrc);
                    destPtr = new IntPtr(targetData.Scan0.ToInt64() + offsetDest); 
                }

                // SECREVIEW : This is an usafe call, buffer overflow can occur.  It is mitigated by copying as much data as the smaller
                //             buffer can hold.  The src and dst of the data needs to be validated by callers of this function. 
                //
                UnsafeNativeMethods.CopyMemory(new HandleRef(this, destPtr), new HandleRef(this, srcPtr), Math.Abs(targetData.Stride)); 
 
                offsetSrc += sourceData.Stride;
                offsetDest += targetData.Stride; 
            }
        }

        private static bool BitmapHasAlpha(BitmapData bmpData) { 
            bool hasAlpha = false;
            for (int i = 0; i < bmpData.Height; i++) { 
                for (int j = 3; j < Math.Abs(bmpData.Stride); j += 4) { // stride here is fine since we know we're doing this on the whole image 
                    unsafe {
                        byte* candidate = ((byte*)bmpData.Scan0.ToPointer()) + (i * bmpData.Stride) + j; 
                        if (*candidate != 0) {
                            hasAlpha = true;
                            goto Found;
                        } 
                    }
                } 
            } 
            Found:
                return hasAlpha; 
        }

        //
 

 
 

        [SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts")] // supressing here since the call within the assert is safe 
        public Bitmap ToBitmap() {
            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 + 40 + (Size.Width * Size.Height - 1)*4) <= iconData.Length, "Illegal offset/length for the Icon data"); 

                unsafe 
                {
                    System.Drawing.Imaging.BitmapData bmpdata = bitmap.LockBits(new Rectangle(0, 0, Size.Width, Size.Height),
                        System.Drawing.Imaging.ImageLockMode.WriteOnly,
                        System.Drawing.Imaging.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){ // we don't know or we are 32bpp for sure
                //we don't have any icon data, let's fish out the data from the handle that we got...
                // we have to fish out the data for this icon if the icon is a 32bpp icon
                SafeNativeMethods.ICONINFO info = new SafeNativeMethods.ICONINFO(); 
                SafeNativeMethods.GetIconInfo(new HandleRef(this, handle), info);
                SafeNativeMethods.BITMAP 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; 
                            // SECREVIEW : This assert is safe here, all data passed to unmanaged code is created by us.  The scope is ok too,
                            //             most operations in it demand this permission. 
                            // 
                            IntSecurity.ObjectFromWin32Handle.Assert();
                            try 
                            {
                                tmpBitmap = Bitmap.FromHbitmap(info.hbmColor);

                                // 

 
 

                                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);
 
                                    // SECREVIEW : both bmpData and targetData point to memory owned by this Icon object so the following call 
                                    //             is safe.
                                    // 
                                    CopyBitmapData(bmpData, targetData);
                                }
                            } finally {
                                CodeAccessPermission.RevertAssert(); 
                                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; 
                try {
                    graphics = Graphics.FromImage(bitmap); 
                    // SECREVIEW : This assert is safe here, no user data is involved here.
                    //
                    IntSecurity.ObjectFromWin32Handle.Assert();
                    try{ 
                        using(Bitmap tmpBitmap = Bitmap.FromHicon(this.Handle)) {
                            graphics.DrawImage(tmpBitmap, new Rectangle(0, 0, size.Width, size.Height)); 
                        } 
                    } catch(ArgumentException) { // GDI+ weirdness episode MMMCLXXXXIVI, sometime FromHicon crash with no real reason,
                        // see VSWhidbey 518812 
                        // 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)); 
                    }
                    finally{ 
                        CodeAccessPermission.RevertAssert(); 
                    }
                } 
                finally {
                    if (graphics != null) {
                        graphics.Dispose();
                    } 
                }
 
 
                // gpr: GDI+ is filling the surface with a sentinel color for GetDC,
                // but is not correctly cleaning it up again, so we have to for it. 
                Color fakeTransparencyColor = Color.FromArgb(0x0d, 0x0b, 0x0c);
                bitmap.MakeTransparent(fakeTransparencyColor);

            } 

            Debug.Assert(bitmap != null, "Bitmap cannot be null"); 
            return bitmap; 

        } 

        /// 
        /// 
        ///     Retrieves a human readable string representing the cursor. 
        /// 
        public override string ToString() { 
            return SR.GetString(SR.toStringIcon); 
        }
 
        /// 
        /// 
        ///     ISerializable private implementation
        ///  
        /// 
        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)] 
        void ISerializable.GetObjectData(SerializationInfo si, StreamingContext context) { 
            if (iconData != null) {
                si.AddValue("IconData", iconData, typeof(byte[])); 
            }
            else {
                MemoryStream stream = new MemoryStream();
                Save(stream); 
                si.AddValue("IconData", stream.ToArray(), typeof(byte[]));
            } 
            si.AddValue("IconSize", iconSize, typeof(Size)); 
        }
 
    }
}


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// #define CUSTOM_MARSHALING_ISTREAM 

//------------------------------------------------------------------------------
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved. 
// 
//----------------------------------------------------------------------------- 
 
/*
 */ 
namespace System.Drawing {
    using System.Runtime.Serialization.Formatters;
    using System.Runtime.InteropServices;
    using System.Runtime.Serialization; 
    using System.Security;
    using System.Security.Permissions; 
    using System.Diagnostics; 
    using System.Diagnostics.CodeAnalysis;
    using System; 
    using System.Collections;
    using System.ComponentModel;
    using Microsoft.Win32;
    using System.Drawing.Design; 
    using System.Drawing.Imaging;
    using System.IO; 
    using System.Reflection; 
    using System.Text;
    using System.Drawing.Internal; 

    /// 
    /// 
    ///     This class represents a Windows icon, which is a small bitmap image used to 
    ///     represent an object.  Icons can be thought of as transparent bitmaps, although
    ///     their size is determined by the system. 
    ///  
    [
    TypeConverterAttribute(typeof(IconConverter)), 
    Editor("System.Drawing.Design.IconEditor, " + AssemblyRef.SystemDrawingDesign, typeof(UITypeEditor))
    ]
    [Serializable]
    public sealed class Icon : MarshalByRefObject, ISerializable, ICloneable, IDisposable { 
#if FINALIZATION_WATCH
        private string allocationSite = Graphics.GetAllocationStack(); 
#endif 

        private static int bitDepth; 

        // Icon data
        //
        private byte[] iconData; 
        private int bestImageOffset;
        private int bestBitDepth; 
        private Size   iconSize = System.Drawing.Size.Empty; 
        private IntPtr handle = IntPtr.Zero;
        private bool   ownHandle = true; 

        private Icon() {
        }
 
        internal Icon(IntPtr handle) : this(handle, false) {
        } 
 
        internal Icon(IntPtr handle, bool takeOwnership) {
            if (handle == IntPtr.Zero) { 
                throw new ArgumentException(SR.GetString(SR.InvalidGDIHandle, (typeof(Icon)).Name));
            }
            this.handle = handle;
            this.ownHandle = takeOwnership; 
        }
 
 

        ///  
        /// 
        ///     Loads an icon object from the given filename.
        /// 
        public Icon(string fileName) : this(fileName, 0,0) { 
        }
 
        public Icon(string fileName, Size size) : this(fileName, size.Width, size.Height) { 
        }
 
        public Icon(string fileName, int width, int height) : this() {
            // SECREVIEW : This FileStream constructor demands FileIOPermission (FileIOPermissionAccess) for reading, writing,
            //             and appending to files so we don't need to set a demand here.
            // 
            using (FileStream f = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) {
                Debug.Assert(f != null, "File.OpenRead returned null instead of throwing an exception"); 
                iconData = new byte[(int)f.Length]; 
                f.Read(iconData, 0, iconData.Length);
            } 

            Initialize(width, height);
        }
 
        /// 
        ///  
        ///     Duplicates the given icon, attempting to find a version of the icon 
        ///     that matches the requested size.  If a version cannot be found that
        ///     exactally matches the size, the closest match will be used.  Note 
        ///     that if original is an icon with a single size, this will
        ///     merely create a dupicate icon.  You can use the stretching modes
        ///     of drawImage to force the icon to the size you want.
        ///  
        public Icon(Icon original, Size size) : this(original, size.Width, size.Height) {
        } 
 
        /// 
        ///  
        ///     Duplicates the given icon, attempting to find a version of the icon
        ///     that matches the requested size.  If a version cannot be found that
        ///     exactally matches the size, the closest match will be used.  Note
        ///     that if original is an icon with a single size, this will 
        ///     merely create a dupicate icon.  You can use the stretching modes
        ///     of drawImage to force the icon to the size you want. 
        ///  
        public Icon(Icon original, int width, int height) : this() {
            if (original == null) { 
                throw new ArgumentException(SR.GetString(SR.InvalidArgument, "original", "null"));
            }

            iconData = original.iconData; 

            if (iconData == null) { 
                iconSize = original.Size; 
                handle = SafeNativeMethods.CopyImage(new HandleRef(original, original.Handle), SafeNativeMethods.IMAGE_ICON, iconSize.Width, iconSize.Height, 0);
            } 
            else {
                Initialize(width, height);
            }
        } 

        ///  
        ///  
        ///     Loads an icon object from the given resource.
        ///  
        public Icon(Type type, string resource) : this() {
            Stream stream = type.Module.Assembly.GetManifestResourceStream(type, resource);
            if (stream == null) {
                throw new ArgumentException(SR.GetString(SR.ResourceNotFound, type, resource)); 
            }
 
            iconData = new byte[(int)stream.Length]; 
            stream.Read(iconData, 0, iconData.Length);
            Initialize(0, 0); 
        }

        /// 
        ///  
        ///     Loads an icon object from the given data stream.
        ///  
        public Icon(Stream stream) : this(stream, 0,0) { 
        }
        public Icon(Stream stream, Size size) : this(stream, size.Width, size.Height) { 
        }

        /// 
        ///  
        ///    [To be supplied.]
        ///  
        public Icon(Stream stream, int width, int height) : this() { 
            if (stream == null) {
                throw new ArgumentException(SR.GetString(SR.InvalidArgument, "stream", "null")); 
            }

            iconData = new byte[(int)stream.Length];
            stream.Read(iconData, 0, iconData.Length); 
            Initialize(width, height);
        } 
 

 
        /// 
        /// 
        ///     Constructor used in deserialization
        ///  
        /// 
        [SuppressMessage("Microsoft.Performance", "CA1808:AvoidCallsThatBoxValueTypes")] 
        private Icon(SerializationInfo info, StreamingContext context) { 
            iconData = (byte[])info.GetValue("IconData", typeof(byte[]));
            iconSize = (Size)info.GetValue("IconSize", typeof(Size)); 

            if (iconSize.IsEmpty) {
                Initialize(0, 0);
            } 
            else {
                Initialize(iconSize.Width, iconSize.Height); 
            } 
        }
 
        /// 
        /// 
        ///     Extracts an icon object from the given filename.
        ///  
        public static Icon ExtractAssociatedIcon(string filePath) {
            return ExtractAssociatedIcon(filePath, 0); 
        } 

        ///  
        /// 
        ///     Extracts an icon object from the given filename.
        /// 
        private static Icon ExtractAssociatedIcon(string filePath, int index) { 
            if (filePath == null) {
                throw new ArgumentException(SR.GetString(SR.InvalidArgument, "filePath", "null")); 
            } 

            Uri uri; 
            try
            {
                uri = new Uri(filePath);
            } 
            catch (UriFormatException)
            { 
                // It's a relative pathname, get its full path as a file. 
                // SECREVIEW : If path does exist, the caller must have FileIOPermissionAccess.PathDiscovery permission.
                //             Note that unlike most members of the Path class, this method accesses the file system. 
                //
                filePath = Path.GetFullPath(filePath);
                uri = new Uri(filePath);
            } 
            if (uri.IsUnc) {
                throw new ArgumentException (SR.GetString (SR.InvalidArgument, "filePath", filePath)); 
            } 
            if (uri.IsFile)
            { 
                // SECREVIEW : The File.Exists() below will do the demand for the FileIOPermission
                //             for us. So, we do not need an additional demand anymore.
                //
                if (!File.Exists(filePath)) { 
                    // I have to do this so I can give a meaningful
                    // error back to the user. File.Exists() cal fail because of either 
                    // a failure to demand security or because the file does not exist. 
                    // Always telling the user that the file does not exist is not a good
                    // choice. So, we demand the permission again. This means that we are 
                    // going to demand the permission twice for the failure case, but that's
                    // better than always demanding the permission twice.
                    //
                    IntSecurity.DemandReadFileIO(filePath); 

                    throw new FileNotFoundException(filePath); 
                } 

                Icon icon = new Icon(); 

                StringBuilder sb = new StringBuilder(NativeMethods.MAX_PATH);
                sb.Append(filePath);
 
                IntPtr hIcon = SafeNativeMethods.ExtractAssociatedIcon(NativeMethods.NullHandleRef, sb, ref index);
 
                if (hIcon != IntPtr.Zero) { 
                    IntSecurity.ObjectFromWin32Handle.Demand();
                    icon = new Icon(hIcon, true); 
                    return icon;
                }
            }
            return null; 

        } 
 
        /// 
        ///  
        ///     The Win32 handle for this object.  This is not a copy of the handle; do
        ///     not free it.
        /// 
        [Browsable(false)] 
        public IntPtr Handle {
            // SECREVIEW : Getting the handle is ok, methods receiving a handle should demand security permissions though. 
            // 
            get {
                if (handle == IntPtr.Zero) { 
                    throw new ObjectDisposedException(GetType().Name);
                }
                return handle;
            } 
        }
 
        ///  
        /// 
        ///    [To be supplied.] 
        /// 
        [Browsable(false)]
        public int Height {
            get { return Size.Height;} 
        }
 
        ///  
        /// 
        ///     The size of this icon object. 
        /// 
        public Size Size {
            get {
                if (iconSize.IsEmpty) { 
                    SafeNativeMethods.ICONINFO info = new SafeNativeMethods.ICONINFO();
                    SafeNativeMethods.GetIconInfo(new HandleRef(this, Handle), info); 
                    SafeNativeMethods.BITMAP bmp = new SafeNativeMethods.BITMAP(); 

                    if (info.hbmColor != IntPtr.Zero) { 
                        SafeNativeMethods.GetObject(new HandleRef(null, info.hbmColor), Marshal.SizeOf(typeof(SafeNativeMethods.BITMAP)), bmp);
                        SafeNativeMethods.IntDeleteObject(new HandleRef(null, info.hbmColor));
                        iconSize = new Size(bmp.bmWidth, bmp.bmHeight);
                    } 
                    else if (info.hbmMask != IntPtr.Zero) {
                        SafeNativeMethods.GetObject(new HandleRef(null, info.hbmMask), Marshal.SizeOf(typeof(SafeNativeMethods.BITMAP)), bmp); 
                        iconSize = new Size(bmp.bmWidth, bmp.bmHeight / 2); 
                    }
 
                    if (info.hbmMask != IntPtr.Zero) {
                        SafeNativeMethods.IntDeleteObject(new HandleRef(null, info.hbmMask));
                    }
                } 

                return iconSize; 
            } 
        }
 
        /// 
        /// 
        ///    [To be supplied.]
        ///  
        [Browsable(false)]
        public int Width { 
            get { return Size.Width;} 
        }
 
        /// 
        /// 
        ///     Clones the icon object, creating a duplicate image.
        ///  
        public object Clone() {
            return new Icon(this, Size.Width, Size.Height); 
        } 

        ///  
        /// 
        ///     Called when this object is going to destroy it's Win32 handle.  You
        ///     may override this if there is something special you need to do to
        ///     destroy the handle.  This will be called even if the handle is not 
        ///     owned by this object, which is handy if you want to create a
        ///     derived class that has it's own create/destroy semantics. 
        /// 
        ///     The default implementation will call the appropriate Win32
        ///     call to destroy the handle if this object currently owns the 
        ///     handle.  It will do nothing if the object does not currently
        ///     own the handle.
        /// 
        internal void DestroyHandle() { 
            if (ownHandle) {
                SafeNativeMethods.DestroyIcon(new HandleRef(this, handle)); 
                handle = IntPtr.Zero; 
            }
        } 

        /// 
        /// 
        ///     Cleans up the resources allocated by this object.  Once called, the cursor 
        ///     object is no longer useful.
        ///  
        public void Dispose() { 
            Dispose(true);
            GC.SuppressFinalize(this); 
        }

        void Dispose(bool disposing) {
            if (handle != IntPtr.Zero) { 
#if FINALIZATION_WATCH
                if (!disposing) { 
                    Debug.WriteLine("**********************\nDisposed through finalization:\n" + allocationSite); 
                }
#endif 
                DestroyHandle();
            }
        }
 
        /// 
        ///  
        ///     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.
        /// 
        // This method is way more powerful than what we expose, but I'll leave it in place.
        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);
            }
        } 

        internal void Draw(Graphics graphics, int x, int y) { 
            Size size = Size; 
            Draw(graphics, new Rectangle(x, y, size.Width, size.Height));
        } 

        /// 
        /// 
        ///     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 stretches the image to the given 
        ///     dimensions and allows the user to specify a rectangle within the image to draw. 
        /// 
        internal void Draw(Graphics graphics, Rectangle targetRect) { 
            Rectangle copy = targetRect;
            copy.X += (int) graphics.Transform.OffsetX;
            copy.Y += (int) graphics.Transform.OffsetY;
 
            WindowsGraphics wg = WindowsGraphics.FromGraphics(graphics, ApplyGraphicsProperties.Clipping);
            IntPtr dc = wg.GetHdc(); 
 
            try {
                DrawIcon(dc, Rectangle.Empty, copy, true); 
            }
            finally {
                wg.Dispose();
            } 
        }
 
        ///  
        /// 
        ///     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.
        ///  
        internal void DrawUnstretched(Graphics graphics, Rectangle targetRect) {
            Rectangle copy = targetRect; 
            copy.X += (int) graphics.Transform.OffsetX; 
            copy.Y += (int) graphics.Transform.OffsetY;
 
            WindowsGraphics wg = WindowsGraphics.FromGraphics(graphics, ApplyGraphicsProperties.Clipping);
            IntPtr dc = wg.GetHdc();
            try {
                DrawIcon(dc, Rectangle.Empty, copy, false); 
            }
            finally { 
                wg.Dispose(); 
            }
        } 

        /// 
        /// 
        ///     Cleans up Windows resources for this object. 
        /// 
        ~Icon() { 
            Dispose(false); 
        }
 
        /// 
        /// 
        ///     Creates an icon object from a given Win32 icon handle.  The Icon object
        ///     does not claim ownership of the icon handle; you must free it when you are 
        ///     done.
        ///  
        public static Icon FromHandle(IntPtr handle) { 
            IntSecurity.ObjectFromWin32Handle.Demand();
            return new Icon(handle); 
        }

        private unsafe short GetShort(byte* pb)
        { 
            int retval = 0;
            if (0 != (unchecked((byte)pb) & 1)) 
            { 
                retval = *pb;                   pb++;
                retval = retval | (*pb << 8); 
            }
            else
            {
                retval = (int)(*(short*)pb); 
            }
            return (short)retval; 
        } 

        private unsafe int GetInt(byte* pb) 
        {
            int retval = 0;
            if (0 != (unchecked((byte)pb) & 3))
            { 
                retval = *pb;                   pb++;
                retval = retval | (*pb <<  8);  pb++; 
                retval = retval | (*pb << 16);  pb++; 
                retval = retval | (*pb << 24);
            } 
            else
            {
                retval = *(int*)pb;
            } 
            return retval;
        } 
 

        ///  
        /// 
        ///     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.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)
            { 
                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.GetString(SR.InvalidPictureType, "picture", "Icon"));
                }
 
                SafeNativeMethods.ICONDIRENTRY  EntryTemp;
 
                byte    bestWidth           = 0; 
                byte    bestHeight          = 0;
                int     bestBytesInRes      = 0; 
                //int     bestBitDepth        = 0;

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

                Debug.Assert((icondirEntrySize * idCount) < iconData.Length, "Illegal number of ICONDIRENTRIES"); 
 
                if ((icondirEntrySize * idCount) >= iconData.Length)
                { 
                    throw new ArgumentException(SR.GetString(SR.InvalidPictureType, "picture", "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;
                    }

                    // it looks like if nothing is specified at this point, bpp is 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 (0 == bestBytesInRes) 
                    {
                        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 <= bitDepth && iconBitDepth > bestBitDepth || bestBitDepth > bitDepth && iconBitDepth < bestBitDepth)))
                        {
                            fUpdateBestFit = true;
                        } 
                    }
 
                    if (fUpdateBestFit) 
                    {
                        bestWidth       = EntryTemp.bWidth; 
                        bestHeight      = EntryTemp.bHeight;
                        bestImageOffset = EntryTemp.dwImageOffset;
                        bestBytesInRes  = EntryTemp.dwBytesInRes;
                        bestBitDepth    = iconBitDepth; 
                    }
 
                    pbIconDirEntry += icondirEntrySize; 
                }
 
                Debug.Assert(bestImageOffset >= 0 && (bestImageOffset + bestBytesInRes) <= iconData.Length, "Illegal offset/length for the Icon data");

                if (bestImageOffset < 0 || (bestImageOffset + bestBytesInRes) > iconData.Length)
                { 
                    throw new ArgumentException(SR.GetString(SR.InvalidPictureType, "picture", "Icon"));
                } 
 
                // See DevDivBugs 17509. Copying 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(this.iconData, bestImageOffset, alignedBuffer, 0, bestBytesInRes);
 
                    fixed (byte *pbAlignedBuffer = alignedBuffer) {
                        handle = SafeNativeMethods.CreateIconFromResourceEx(pbAlignedBuffer, bestBytesInRes, true, 0x00030000, 0, 0, 0); 
                    } 
                }
                else { 
                    handle = SafeNativeMethods.CreateIconFromResourceEx(pbIconData + bestImageOffset, bestBytesInRes, true, 0x00030000, 0, 0, 0);
                }
                if (handle == IntPtr.Zero) {
                    throw new Win32Exception(); 
                }
 
#if NEVER // old code 
                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();
                } 
#endif // WIN64
            }
        }
 
        /// 
        ///  
        ///     Saves this image to the given output stream. 
        /// 
        public void Save(Stream outputStream) { 
            if (iconData != null) {
                outputStream.Write(iconData, 0, iconData.Length);
            }
            else { 
                // Ideally, we would pick apart the icon using
                // GetIconInfo, and then pull the individual bitmaps out, 
                // converting them to DIBS and saving them into the file. 
                // But, in the interest of simplicity, we just call to
                // OLE to do it for us. 
                //
                SafeNativeMethods.IPicture picture;
                SafeNativeMethods.PICTDESC pictdesc = SafeNativeMethods.PICTDESC.CreateIconPICTDESC(Handle);
                Guid g = typeof(SafeNativeMethods.IPicture).GUID; 
                picture = SafeNativeMethods.OleCreatePictureIndirect(pictdesc, ref g, false);
 
                if (picture != null) { 
                    int temp;
                    try{ 
                        picture.SaveAsFile(new UnsafeNativeMethods.ComStreamFromDataStream(outputStream), -1, out temp);
                    }
                    finally{
                        Marshal.ReleaseComObject(picture); 
                    }
                } 
            } 
        }
 
        // SECREVIEW : Make sure the code calling this methods validates the source and target data.
        //
        // SAME CODE OR SIMILAR IN ImageList.cs
        private void CopyBitmapData(BitmapData sourceData, BitmapData targetData) { 
            // do the actual copy
            int offsetSrc = 0; 
            int offsetDest = 0; 

            Debug.Assert(sourceData.Height == targetData.Height, "Unexpected height. How did this happen?"); 

            for (int i = 0; i < Math.Min(sourceData.Height, targetData.Height); i++) {
                IntPtr srcPtr, destPtr;
                if (IntPtr.Size == 4) { 
                    srcPtr = new IntPtr(sourceData.Scan0.ToInt32() + offsetSrc);
                    destPtr = new IntPtr(targetData.Scan0.ToInt32() + offsetDest); 
                } else { 
                    srcPtr = new IntPtr(sourceData.Scan0.ToInt64() + offsetSrc);
                    destPtr = new IntPtr(targetData.Scan0.ToInt64() + offsetDest); 
                }

                // SECREVIEW : This is an usafe call, buffer overflow can occur.  It is mitigated by copying as much data as the smaller
                //             buffer can hold.  The src and dst of the data needs to be validated by callers of this function. 
                //
                UnsafeNativeMethods.CopyMemory(new HandleRef(this, destPtr), new HandleRef(this, srcPtr), Math.Abs(targetData.Stride)); 
 
                offsetSrc += sourceData.Stride;
                offsetDest += targetData.Stride; 
            }
        }

        private static bool BitmapHasAlpha(BitmapData bmpData) { 
            bool hasAlpha = false;
            for (int i = 0; i < bmpData.Height; i++) { 
                for (int j = 3; j < Math.Abs(bmpData.Stride); j += 4) { // stride here is fine since we know we're doing this on the whole image 
                    unsafe {
                        byte* candidate = ((byte*)bmpData.Scan0.ToPointer()) + (i * bmpData.Stride) + j; 
                        if (*candidate != 0) {
                            hasAlpha = true;
                            goto Found;
                        } 
                    }
                } 
            } 
            Found:
                return hasAlpha; 
        }

        //
 

 
 

        [SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts")] // supressing here since the call within the assert is safe 
        public Bitmap ToBitmap() {
            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 + 40 + (Size.Width * Size.Height - 1)*4) <= iconData.Length, "Illegal offset/length for the Icon data"); 

                unsafe 
                {
                    System.Drawing.Imaging.BitmapData bmpdata = bitmap.LockBits(new Rectangle(0, 0, Size.Width, Size.Height),
                        System.Drawing.Imaging.ImageLockMode.WriteOnly,
                        System.Drawing.Imaging.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){ // we don't know or we are 32bpp for sure
                //we don't have any icon data, let's fish out the data from the handle that we got...
                // we have to fish out the data for this icon if the icon is a 32bpp icon
                SafeNativeMethods.ICONINFO info = new SafeNativeMethods.ICONINFO(); 
                SafeNativeMethods.GetIconInfo(new HandleRef(this, handle), info);
                SafeNativeMethods.BITMAP 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; 
                            // SECREVIEW : This assert is safe here, all data passed to unmanaged code is created by us.  The scope is ok too,
                            //             most operations in it demand this permission. 
                            // 
                            IntSecurity.ObjectFromWin32Handle.Assert();
                            try 
                            {
                                tmpBitmap = Bitmap.FromHbitmap(info.hbmColor);

                                // 

 
 

                                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);
 
                                    // SECREVIEW : both bmpData and targetData point to memory owned by this Icon object so the following call 
                                    //             is safe.
                                    // 
                                    CopyBitmapData(bmpData, targetData);
                                }
                            } finally {
                                CodeAccessPermission.RevertAssert(); 
                                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; 
                try {
                    graphics = Graphics.FromImage(bitmap); 
                    // SECREVIEW : This assert is safe here, no user data is involved here.
                    //
                    IntSecurity.ObjectFromWin32Handle.Assert();
                    try{ 
                        using(Bitmap tmpBitmap = Bitmap.FromHicon(this.Handle)) {
                            graphics.DrawImage(tmpBitmap, new Rectangle(0, 0, size.Width, size.Height)); 
                        } 
                    } catch(ArgumentException) { // GDI+ weirdness episode MMMCLXXXXIVI, sometime FromHicon crash with no real reason,
                        // see VSWhidbey 518812 
                        // 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)); 
                    }
                    finally{ 
                        CodeAccessPermission.RevertAssert(); 
                    }
                } 
                finally {
                    if (graphics != null) {
                        graphics.Dispose();
                    } 
                }
 
 
                // gpr: GDI+ is filling the surface with a sentinel color for GetDC,
                // but is not correctly cleaning it up again, so we have to for it. 
                Color fakeTransparencyColor = Color.FromArgb(0x0d, 0x0b, 0x0c);
                bitmap.MakeTransparent(fakeTransparencyColor);

            } 

            Debug.Assert(bitmap != null, "Bitmap cannot be null"); 
            return bitmap; 

        } 

        /// 
        /// 
        ///     Retrieves a human readable string representing the cursor. 
        /// 
        public override string ToString() { 
            return SR.GetString(SR.toStringIcon); 
        }
 
        /// 
        /// 
        ///     ISerializable private implementation
        ///  
        /// 
        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)] 
        void ISerializable.GetObjectData(SerializationInfo si, StreamingContext context) { 
            if (iconData != null) {
                si.AddValue("IconData", iconData, typeof(byte[])); 
            }
            else {
                MemoryStream stream = new MemoryStream();
                Save(stream); 
                si.AddValue("IconData", stream.ToArray(), typeof(byte[]));
            } 
            si.AddValue("IconSize", iconSize, typeof(Size)); 
        }
 
    }
}


// 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