File: winforms\Managed\System\WinForms\Cursor.cs
Project: ndp\fx\src\System.Windows.Forms.csproj (System.Windows.Forms)
//------------------------------------------------------------------------------
// <copyright file="Cursor.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
/*
 */
namespace System.Windows.Forms {
    using System.Runtime.InteropServices;
    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis;
    using System;
    using System.Drawing;
    using System.Drawing.Design;
    using CodeAccessPermission = System.Security.CodeAccessPermission;
    using System.Security.Permissions;  
    using System.ComponentModel;
    using System.IO;
    using Microsoft.Win32;
    using System.Runtime.Serialization;
    using System.Globalization;
    using System.Security;
 
 
    /// <include file='doc\Cursor.uex' path='docs/doc[@for="Cursor"]/*' />
    /// <devdoc>
    ///    <para>
    ///       Represents the image used to paint the mouse pointer.
    ///       Different cursor shapes are used to inform the user what operation the mouse will
    ///       have.
    ///    </para>
    /// </devdoc>
    // 
    [
    TypeConverterAttribute(typeof(CursorConverter)),
    Serializable,
    Editor("System.Drawing.Design.CursorEditor, " + AssemblyRef.SystemDrawingDesign, typeof(UITypeEditor))
    ]
    public sealed class Cursor : IDisposable, ISerializable {
        private static Size cursorSize = System.Drawing.Size.Empty;
 
        private byte[] cursorData;
        private IntPtr handle = IntPtr.Zero;       // handle to loaded image
        private bool ownHandle = true;
        private int    resourceId = 0;
 
        private object userData;
 
        /**
         * Constructor used in deserialization
         */
        internal Cursor(SerializationInfo info, StreamingContext context) {
            SerializationInfoEnumerator sie = info.GetEnumerator();
            if (sie == null) {
                return;
            }
            for (; sie.MoveNext();) {
                // Dont catch any exceptions while Deserialising objects from stream.
                if (String.Equals(sie.Name, "CursorData", StringComparison.OrdinalIgnoreCase) ){
                    cursorData = (byte[])sie.Value;
                    if (cursorData != null) {
                        LoadPicture(new UnsafeNativeMethods.ComStreamFromDataStream(new MemoryStream(cursorData)));
                    }
                }
                else if (String.Compare(sie.Name, "CursorResourceId", true, CultureInfo.InvariantCulture) == 0) {
                    LoadFromResourceId((int)sie.Value);
                }
            }
        }
 
        /// <devdoc>
        ///     Private constructor. If you want a standard system cursor, use one of the
        ///     definitions in the Cursors class.
        /// </devdoc>
        // 
        internal Cursor(int nResourceId, int dummy) {
            LoadFromResourceId(nResourceId);
        }
 
        // Private constructor.  We have a private constructor here for
        // static cursors that are loaded through resources.  The only reason
        // to use the private constructor is so that we can assert, rather
        // than throw, if the cursor couldn't be loaded.  Why?  Because
        // throwing in <clinit/> is really rude and will prevent any of windows forms
        // from initializing.  This seems extreme just because we fail to
        // load a cursor.
        internal Cursor(string resource, int dummy) {
            Stream stream = typeof(Cursor).Module.Assembly.GetManifestResourceStream(typeof(Cursor), resource);
            Debug.Assert(stream != null, "couldn't get stream for resource " + resource);
            cursorData = new byte[stream.Length];
            stream.Read(cursorData, 0, Convert.ToInt32(stream.Length)); // we assume that a cursor is less than 4gig big
            LoadPicture(new UnsafeNativeMethods.ComStreamFromDataStream(new MemoryStream(cursorData)));
        }
 
        /// <include file='doc\Cursor.uex' path='docs/doc[@for="Cursor.Cursor1"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Initializes a new instance of the <see cref='System.Windows.Forms.Cursor'/> class with the specified handle.
        ///    </para>
        /// </devdoc>
        public Cursor(IntPtr handle) {
            IntSecurity.UnmanagedCode.Demand();
            if (handle == IntPtr.Zero) {
                throw new ArgumentException(SR.GetString(SR.InvalidGDIHandle, (typeof(Cursor)).Name));
            }
 
            this.handle = handle;
            this.ownHandle = false;
        }
 
        /// <include file='doc\Cursor.uex' path='docs/doc[@for="Cursor.Cursor2"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Initializes a new instance of the <see cref='System.Windows.Forms.Cursor'/>
        ///       class with
        ///       the specified filename.
        ///    </para>
        /// </devdoc>
        public Cursor(string fileName) {
            //Filestream demands the correct FILEIO access here
            //
            FileStream f = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
            try {
                cursorData = new byte[f.Length];
                f.Read(cursorData, 0, Convert.ToInt32(f.Length)); // assume that a cursor is less than 4gig...
            }
            finally {
                f.Close();
            }
            LoadPicture(new UnsafeNativeMethods.ComStreamFromDataStream(new MemoryStream(cursorData)));
        }
 
        /// <include file='doc\Cursor.uex' path='docs/doc[@for="Cursor.Cursor3"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Initializes a new instance of the <see cref='System.Windows.Forms.Cursor'/> class from the specified resource.
        ///    </para>
        /// </devdoc>
        public Cursor(Type type, string resource) : this(type.Module.Assembly.GetManifestResourceStream(type,resource)) {
        }
 
        /// <include file='doc\Cursor.uex' path='docs/doc[@for="Cursor.Cursor4"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Initializes a new instance of the <see cref='System.Windows.Forms.Cursor'/> class from the
        ///       specified data stream.
        ///    </para>
        /// </devdoc>
        public Cursor(Stream stream) {
            cursorData = new byte[stream.Length];
            stream.Read(cursorData, 0, Convert.ToInt32(stream.Length));// assume that a cursor is less than 4gig...
            LoadPicture(new UnsafeNativeMethods.ComStreamFromDataStream(new MemoryStream(cursorData)));
        }
 
        
        /// <include file='doc\Cursor.uex' path='docs/doc[@for="Cursor.Clip"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Gets or
        ///       sets a <see cref='System.Drawing.Rectangle'/> that represents the current clipping rectangle for this <see cref='System.Windows.Forms.Cursor'/> in
        ///       screen coordinates.
        ///    </para>
        /// </devdoc>
        public static Rectangle Clip {
            get {
                return ClipInternal;
            }
            set {
                if (!value.IsEmpty) {
                    Debug.WriteLineIf(IntSecurity.SecurityDemand.TraceVerbose, "AdjustCursorClip Demanded");
                    IntSecurity.AdjustCursorClip.Demand();
                }
                ClipInternal = value;
            }
        }
 
        /// <devdoc>
        ///     Implemented separately to be used internally from safe places.
        /// </devdoc>
        internal static Rectangle ClipInternal
        {
            get {
                NativeMethods.RECT r = new NativeMethods.RECT();
                SafeNativeMethods.GetClipCursor(ref r);
                return Rectangle.FromLTRB(r.left, r.top, r.right, r.bottom);
            }
            set {
                if (value.IsEmpty) {
                    UnsafeNativeMethods.ClipCursor(null);
                }
                else {
                    NativeMethods.RECT rcClip = NativeMethods.RECT.FromXYWH(value.X, value.Y, value.Width, value.Height);
                    UnsafeNativeMethods.ClipCursor(ref rcClip);
                }
            }
        }
 
        /// <include file='doc\Cursor.uex' path='docs/doc[@for="Cursor.Current"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Gets or
        ///       sets a <see cref='System.Windows.Forms.Cursor'/> that
        ///       represents the current mouse cursor. The value is NULL if the current mouse cursor is not visible.
        ///    </para>
        /// </devdoc>
        public static Cursor Current {
            get {
                return CurrentInternal;
            }
 
            set {
                Debug.WriteLineIf(IntSecurity.SecurityDemand.TraceVerbose, "ModifyCursor Demanded");
                IntSecurity.ModifyCursor.Demand();
                CurrentInternal = value;
            }
        }
 
        internal static Cursor CurrentInternal {
            get {
                IntPtr curHandle = SafeNativeMethods.GetCursor();
 
                // SECREVIEW : This method is to be used internally from safe places.
                //
                IntSecurity.UnmanagedCode.Assert();
                return Cursors.KnownCursorFromHCursor( curHandle );
                // SECREVIEW RevertAssert automatically called on return from function.
            }
            set {
                IntPtr handle = (value == null) ? IntPtr.Zero : value.handle;
                UnsafeNativeMethods.SetCursor(new HandleRef(value, handle));
            }
        }
 
        /// <include file='doc\Cursor.uex' path='docs/doc[@for="Cursor.Handle"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Gets
        ///       the Win32 handle for this <see cref='System.Windows.Forms.Cursor'/> .
        ///    </para>
        /// </devdoc>
        public IntPtr Handle {
            get {
                if (handle == IntPtr.Zero) {
                    throw new ObjectDisposedException(SR.GetString(SR.ObjectDisposed, GetType().Name));
                }
                return handle;
            }
        }
 
        /// <include file='doc\Cursor.uex' path='docs/doc[@for="Cursor.Handle"]/*' />
        /// <devdoc>
        ///    <para>
        ///     returns the "hot" location of the cursor.
        ///    </para>
        /// </devdoc>
        [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")] //Minor, not worth breaking change
        public Point HotSpot
        {
            get {
                Point hotSpot = Point.Empty;
                NativeMethods.ICONINFO info = new NativeMethods.ICONINFO();
                Icon currentIcon = null;
 
                // SECREVIEW : Safe to assert here, the handle used was created by us and the Icon created is not exposed.
                //
                IntSecurity.ObjectFromWin32Handle.Assert();    
                try
                {
                    currentIcon = Icon.FromHandle(this.Handle);
                }
                finally
                {
                    CodeAccessPermission.RevertAssert();
                }
 
                try {
                    SafeNativeMethods.GetIconInfo(new HandleRef(this, currentIcon.Handle), info);
                    hotSpot = new Point(info.xHotspot, info.yHotspot);
                }
                finally {
                    // GetIconInfo creates bitmaps for the hbmMask and hbmColor members of ICONINFO.
                    // The calling application must manage these bitmaps and delete them when they are no longer necessary. 
   
                    if (info.hbmMask  != IntPtr.Zero) {
                      // ExternalDelete to prevent Handle underflow
                      SafeNativeMethods.ExternalDeleteObject(new HandleRef(null, info.hbmMask));
                      info.hbmMask  = IntPtr.Zero;
                    }
                    if (info.hbmColor != IntPtr.Zero) {
                      // ExternalDelete to prevent Handle underflow
                      SafeNativeMethods.ExternalDeleteObject(new HandleRef(null, info.hbmColor));
                      info.hbmColor  = IntPtr.Zero;
                    }
                    currentIcon.Dispose();
 
                }
                return hotSpot;
            }
        }
 
        /// <include file='doc\Cursor.uex' path='docs/doc[@for="Cursor.Position"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Gets or sets a <see cref='System.Drawing.Point'/> that specifies the current cursor
        ///       position in screen coordinates.
        ///    </para>
        /// </devdoc>
        public static Point Position {
            get {
                NativeMethods.POINT p = new NativeMethods.POINT();
                UnsafeNativeMethods.GetCursorPos(p);
                return new Point(p.x, p.y);
            }
            set {
                IntSecurity.AdjustCursorPosition.Demand();
                UnsafeNativeMethods.SetCursorPos(value.X, value.Y);
            }
        }
 
        /// <include file='doc\Cursor.uex' path='docs/doc[@for="Cursor.Size"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Gets
        ///       the size of this <see cref='System.Windows.Forms.Cursor'/> object.
        ///    </para>
        /// </devdoc>
        public Size Size {
            get {
                if (cursorSize.IsEmpty) {
                     cursorSize = new Size(
                                         UnsafeNativeMethods.GetSystemMetrics(NativeMethods.SM_CXCURSOR),
                                         UnsafeNativeMethods.GetSystemMetrics(NativeMethods.SM_CYCURSOR)
                                         );
 
                }
                return cursorSize;
            }
        }
 
        /// <include file='doc\CurSor.uex' path='docs/doc[@for="CurSor.Tag"]/*' />
        [
        SRCategory(SR.CatData),
        Localizable(false),
        Bindable(true),
        SRDescription(SR.ControlTagDescr),
        DefaultValue(null),
        TypeConverter(typeof(StringConverter)),
        ]
        public object Tag {
            get {
                return userData;
            }
            set {
                userData = value;
            }
        }
 
        /// <include file='doc\Cursor.uex' path='docs/doc[@for="Cursor.CopyHandle"]/*' />
        /// <devdoc>
        ///    Duplicates this the Win32 handle of this <see cref='System.Windows.Forms.Cursor'/>.
        /// </devdoc>
        public IntPtr CopyHandle() {
            Size sz = Size;
            return SafeNativeMethods.CopyImage(new HandleRef(this, Handle), NativeMethods.IMAGE_CURSOR, sz.Width, sz.Height, 0);
        }
 
        /// <devdoc>
        ///    Destroys the Win32 handle of this <see cref='System.Windows.Forms.Cursor'/>, if the
        /// <see cref='System.Windows.Forms.Cursor'/> 
        /// owns the handle
        /// </devdoc>
        private void DestroyHandle() {
            if (ownHandle) {
                UnsafeNativeMethods.DestroyCursor(new HandleRef(this, handle));
            }
        }
 
        /// <include file='doc\Cursor.uex' path='docs/doc[@for="Cursor.Dispose"]/*' />
        /// <devdoc>
        ///     Cleans up the resources allocated by this object.  Once called, the cursor
        ///     object is no longer useful.
        /// </devdoc>
        public void Dispose() {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
 
        void Dispose(bool disposing) {
            /*if (picture != null) {
                picture = null;
 
                // If we have no message loop, OLE may block on this call.
                // Let pent up SendMessage calls go through here.
                //
                NativeMethods.MSG msg = new NativeMethods.MSG();
                UnsafeNativeMethods.PeekMessage(ref msg, NativeMethods.NullHandleRef, 0, 0, NativeMethods.PM_NOREMOVE | NativeMethods.PM_NOYIELD);
            }*/ // do we still keep that?
 
            if (handle != IntPtr.Zero) {
                DestroyHandle();
                handle = IntPtr.Zero;
            }
        }
 
        /// <devdoc>
        ///     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.
        /// </devdoc>
        // This method is way more powerful than what we expose, but I'll leave it in place.
        private void DrawImageCore(Graphics graphics, Rectangle imageRect, Rectangle targetRect, bool stretch) {
            // Support GDI+ Translate method
            targetRect.X += (int) graphics.Transform.OffsetX;
            targetRect.Y += (int) graphics.Transform.OffsetY;
 
            int rop = 0xcc0020; // RasterOp.SOURCE.GetRop();
            IntPtr dc = graphics.GetHdc();
 
            try { // want finally clause to release dc
                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) {
                    // Short circuit the simple case of blasting an icon to the
                    // screen
                    //
                    if (targetWidth == imageWidth && targetHeight == imageHeight
                        && imageX == 0 && imageY == 0 && rop == NativeMethods.SRCCOPY
                        && imageWidth == cursorSize.Width && imageHeight == cursorSize.Height) {
                        SafeNativeMethods.DrawIcon(new HandleRef(graphics, dc), targetX, targetY, new HandleRef(this, handle));
                        return;
                    }
 
                    drawWidth = cursorSize.Width * targetWidth / imageWidth;
                    drawHeight = cursorSize.Height * targetHeight / imageHeight;
                    clipWidth = targetWidth;
                    clipHeight = targetHeight;
                }
                else {
                    // Short circuit the simple case of blasting an icon to the
                    // screen
                    //
                    if (imageX == 0 && imageY == 0 && rop == NativeMethods.SRCCOPY
                        && cursorSize.Width <= targetWidth && cursorSize.Height <= targetHeight
                        && cursorSize.Width == imageWidth && cursorSize.Height == imageHeight) {
                        SafeNativeMethods.DrawIcon(new HandleRef(graphics, dc), targetX, targetY, new HandleRef(this, handle));
                        return;
                    }
 
                    drawWidth = cursorSize.Width;
                    drawHeight = cursorSize.Height;
                    clipWidth = targetWidth < imageWidth ? targetWidth : imageWidth;
                    clipHeight = targetHeight < imageHeight ? targetHeight : imageHeight;
                }
 
                if (rop == NativeMethods.SRCCOPY) {
                    // 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.
                    //
                    SafeNativeMethods.IntersectClipRect(new HandleRef(this, Handle), targetX, targetY, targetX+clipWidth, targetY+clipHeight);
                    SafeNativeMethods.DrawIconEx(new HandleRef(graphics, dc), targetX - imageX, targetY - imageY,
                                       new HandleRef(this, handle), drawWidth, drawHeight, 0, NativeMethods.NullHandleRef, NativeMethods.DI_NORMAL);
                    // Let GDI+ restore clipping
                    return;
                }
 
                Debug.Fail("Cursor.Draw does not support raster ops.  How did you even pass one in?");
            }
            finally {
                graphics.ReleaseHdcInternal(dc);
            }
        }
 
        /// <include file='doc\Cursor.uex' path='docs/doc[@for="Cursor.Draw"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Draws this <see cref='System.Windows.Forms.Cursor'/> to a <see cref='System.Drawing.Graphics'/>.
        ///    </para>
        /// </devdoc>
        public void Draw(Graphics g, Rectangle targetRect) {
            DrawImageCore(g, Rectangle.Empty, targetRect, false);
        }
 
        /// <include file='doc\Cursor.uex' path='docs/doc[@for="Cursor.DrawStretched"]/*' />
        /// <devdoc>
        ///    Draws this <see cref='System.Windows.Forms.Cursor'/> to a <see cref='System.Drawing.Graphics'/>.
        /// </devdoc>
        public void DrawStretched(Graphics g, Rectangle targetRect) {
            DrawImageCore(g, Rectangle.Empty, targetRect, true);
        }
 
        /// <include file='doc\Cursor.uex' path='docs/doc[@for="Cursor.Finalize"]/*' />
        /// <devdoc>
        ///    Cleans up Windows resources for this object.
        /// </devdoc>
        ~Cursor() {
            Dispose(false);
        }
 
        /// <include file='doc\Cursor.uex' path='docs/doc[@for="Cursor.ISerializable.GetObjectData"]/*' />
        /// <devdoc>
        /// ISerializable private implementation
        /// </devdoc>
        /// <internalonly/>
    	[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)] 		
        void ISerializable.GetObjectData(SerializationInfo si, StreamingContext context) {
            if (cursorData != null) {
                si.AddValue("CursorData", cursorData, typeof(byte[]));
            }
            else if (resourceId != 0) {
                si.AddValue("CursorResourceId", resourceId, typeof(int));
            }
            else {
                Debug.Fail("Why are we trying to serialize an empty cursor?");
                throw new SerializationException(SR.GetString(SR.CursorNonSerializableHandle));
            }
        }
 
        /// <include file='doc\Cursor.uex' path='docs/doc[@for="Cursor.Hide"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Hides the cursor. For every call to Cursor.hide() there must be a
        ///       balancing call to Cursor.show().
        ///    </para>
        /// </devdoc>
        public static void Hide() {
            Debug.WriteLineIf(IntSecurity.SecurityDemand.TraceVerbose, "AdjustCursorClip Demanded");
            IntSecurity.AdjustCursorClip.Demand();
 
            UnsafeNativeMethods.ShowCursor(false);
        }
 
        private void LoadFromResourceId(int nResourceId) {
            ownHandle = false;  // we don't delete stock cursors.
 
           // We assert here on exception -- this constructor is used during clinit,
           // and it would be a shame if we failed to initialize all of windows forms just
           // just because a cursor couldn't load.
           //
           try {
               resourceId = nResourceId;
               handle = SafeNativeMethods.LoadCursor(NativeMethods.NullHandleRef, nResourceId);
           }
           catch (Exception e) {
               handle = IntPtr.Zero;
               Debug.Fail(e.ToString());
           }
        }
 
        // this code is adapted from Icon.GetIconSize please take this into account when changing this
        private Size GetIconSize(IntPtr iconHandle) { 
            Size iconSize = Size;
 
            NativeMethods.ICONINFO info = new NativeMethods.ICONINFO();
            SafeNativeMethods.GetIconInfo(new HandleRef(this, iconHandle), info);
            NativeMethods.BITMAP bmp = new NativeMethods.BITMAP();
 
            if (info.hbmColor != IntPtr.Zero) {
                UnsafeNativeMethods.GetObject(new HandleRef(null, info.hbmColor), Marshal.SizeOf(typeof(NativeMethods.BITMAP)), bmp);
                SafeNativeMethods.IntDeleteObject(new HandleRef(null, info.hbmColor));
                iconSize = new Size(bmp.bmWidth, bmp.bmHeight);
            }
            else if (info.hbmMask != IntPtr.Zero) {
                UnsafeNativeMethods.GetObject(new HandleRef(null, info.hbmMask), Marshal.SizeOf(typeof(NativeMethods.BITMAP)), bmp);
                iconSize = new Size(bmp.bmWidth, bmp.bmHeight / 2);
            }
            
            if (info.hbmMask != IntPtr.Zero) {
                SafeNativeMethods.IntDeleteObject(new HandleRef(null, info.hbmMask));
            }
            return iconSize;            
        }
 
 
 
        /// <devdoc>
        ///     Loads a picture from the requested stream.
        /// </devdoc>
        private  void LoadPicture(UnsafeNativeMethods.IStream stream) {
 
            if (stream == null) {
                throw new ArgumentNullException("stream");
            }
            try {
                Guid g = typeof(UnsafeNativeMethods.IPicture).GUID;
                UnsafeNativeMethods.IPicture picture = null;
 
                new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert();
                
                try {
                    picture = UnsafeNativeMethods.OleCreateIPictureIndirect(null, ref g, true);
                    UnsafeNativeMethods.IPersistStream ipictureAsIPersist = (UnsafeNativeMethods.IPersistStream)picture;
                    ipictureAsIPersist.Load(stream);
                    
                    if (picture != null && picture.GetPictureType() == NativeMethods.Ole.PICTYPE_ICON) {
                        IntPtr cursorHandle = picture.GetHandle();
                        Size picSize = GetIconSize(cursorHandle);
                        if (DpiHelper.IsScalingRequired) {
                            picSize = DpiHelper.LogicalToDeviceUnits(picSize);
                        }
 
                        handle = SafeNativeMethods.CopyImageAsCursor(new HandleRef(this, cursorHandle), NativeMethods.IMAGE_CURSOR,
                            picSize.Width, picSize.Height, 0);
                        ownHandle = true;
                    }
                    else {
                        throw new ArgumentException(SR.GetString(SR.InvalidPictureType,
                                                          "picture",
                                                          "Cursor"), "picture");
                    }
                }
                finally {
                    CodeAccessPermission.RevertAssert();
                    // destroy the picture...
                    if(picture != null) {
                        Marshal.ReleaseComObject(picture);
                    }
                }
            }
            catch (COMException e) {
                Debug.Fail(e.ToString());
                throw new ArgumentException(SR.GetString(SR.InvalidPictureFormat), "stream", e);
            }
        }
 
        /// <devdoc>
        ///     Saves a picture from the requested stream.
        /// </devdoc>
        internal void SavePicture(Stream stream) {
            if (stream == null) {
                throw new ArgumentNullException("stream");
            }
            if(this.resourceId != 0) {
                throw new FormatException(SR.GetString(SR.CursorCannotCovertToBytes));
            }
            try {
                stream.Write(cursorData, 0, cursorData.Length);
            }
            catch (SecurityException) {
                // VSWhidbey 424904 - dont eat security exceptions.
                throw;
            }
            catch (Exception e) {
                Debug.Fail(e.ToString());
                throw new InvalidOperationException(SR.GetString(SR.InvalidPictureFormat));
            }
        }
 
        /// <include file='doc\Cursor.uex' path='docs/doc[@for="Cursor.Show"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Displays the cursor. For every call to Cursor.show() there must have been
        ///       a previous call to Cursor.hide().
        ///    </para>
        /// </devdoc>
        public static void Show() {
            UnsafeNativeMethods.ShowCursor(true);
        }
 
        /// <include file='doc\Cursor.uex' path='docs/doc[@for="Cursor.ToString"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Retrieves a human readable string representing this
        ///    <see cref='System.Windows.Forms.Cursor'/>
        ///    .
        /// </para>
        /// </devdoc>
        public override string ToString() {
            string s = null;
            
            if (!this.ownHandle)
                s = TypeDescriptor.GetConverter(typeof(Cursor)).ConvertToString(this);
            else
                s = base.ToString();
            
            return "[Cursor: " + s + "]";
        }
        
        /// <include file='doc\Cursor.uex' path='docs/doc[@for="Cursor.operatorEQ"]/*' />
        public static bool operator ==(Cursor left, Cursor right) {
            if (object.ReferenceEquals(left, null) != object.ReferenceEquals(right, null)) {
                return false;
            }
            
            if (!object.ReferenceEquals(left, null)) {
                return (left.handle == right.handle);
            }
            else {
                return true;
            }
        }
        
        /// <include file='doc\Cursor.uex' path='docs/doc[@for="Cursor.operatorNE"]/*' />
        public static bool operator !=(Cursor left, Cursor right) {
            return !(left == right);
        }
        
        /// <include file='doc\Cursor.uex' path='docs/doc[@for="Cursor.GetHashCode"]/*' />
        public override int GetHashCode() {
            // Handle is a 64-bit value in 64-bit machines, uncheck here to avoid overflow exceptions.
            return unchecked((int)handle);
        }
        
        /// <include file='doc\Cursor.uex' path='docs/doc[@for="Cursor.Equals"]/*' />
        public override bool Equals(object obj) {
            if (!(obj is Cursor)) {
                return false;
            }
            return (this == (Cursor)obj);
        }
    }
}