1

Assuming I have an existing System.Drawing.Bitmap object, how do I create a System.Windows.Forms.Cursor object with the same pixel data as my Bitmap object?

tckmn
  • 57,719
  • 27
  • 114
  • 156
Walt D
  • 4,491
  • 6
  • 33
  • 43
  • *You also need to manually use the DesroyIcon() API to release the IntPtr retrieved with GetHicon(). – Idle_Mind Jun 14 '13 at 02:30
  • Thanks for the link, I'll give that solution a shot. It's not a duplicate question though, even though the answer is relevant; that question is very situation-specific, whereas this question is general to any situation where you might want to create a Cursor from a Bitmap. – Walt D Jun 14 '13 at 02:31
  • There's more to a cursor than just a bitmap. The hotspot and masks are not going to fall from the sky. – Hans Passant Jun 14 '13 at 03:11
  • As Hans points out, the "possible duplicate" solution linked to by Romoku is incomplete because it does not show how to set the hotspot. I have posted a better answer below. – Walt D Jun 14 '13 at 05:33
  • What question is this a "duplicate" of? Just because a question has the same answer as another question, that doesn't mean it's the same question. – Walt D Jun 14 '13 at 14:42

1 Answers1

4

This answer is taken from this question. It allows you to both create a Cursor from a Bitmap object and set its hotspot.

public struct IconInfo
{
    public bool fIcon;
    public int xHotspot;
    public int yHotspot;
    public IntPtr hbmMask;
    public IntPtr hbmColor;
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetIconInfo(IntPtr hIcon, ref IconInfo pIconInfo);
[DllImport("user32.dll")]
public static extern IntPtr CreateIconIndirect(ref IconInfo icon);

/// <summary>
/// Create a cursor from a bitmap without resizing and with the specified
/// hot spot
/// </summary>
public static Cursor CreateCursorNoResize(Bitmap bmp, int xHotSpot, int yHotSpot)
{
    IntPtr ptr = bmp.GetHicon();
    IconInfo tmp = new IconInfo();
    GetIconInfo(ptr, ref tmp);
    tmp.xHotspot = xHotSpot;
    tmp.yHotspot = yHotSpot;
    tmp.fIcon = false;
    ptr = CreateIconIndirect(ref tmp);
    return new Cursor(ptr);
}


/// <summary>
/// Create a 32x32 cursor from a bitmap, with the hot spot in the middle
/// </summary>
public static Cursor CreateCursor(Bitmap bmp)
{
    int xHotSpot = 16;
    int yHotSpot = 16;

    IntPtr ptr = ((Bitmap)ResizeImage(bmp, 32, 32)).GetHicon();
    IconInfo tmp = new IconInfo();
    GetIconInfo(ptr, ref tmp);
    tmp.xHotspot = xHotSpot;
    tmp.yHotspot = yHotSpot;
    tmp.fIcon = false;
    ptr = CreateIconIndirect(ref tmp);
    return new Cursor(ptr);
}

Edit: As pointed out in the comments, when a Cursor is created from an IntPtr handle, disposing the cursor will not release the handle itself, which will create a memory leak unless you release it yourself manually using the DestroyIcon function:

[DllImport("user32.dll")]
private static extern bool DestroyIcon(IntPtr hIcon);

And then you can call the function like this:

DestroyIcon(myCursor.Handle);
Walt D
  • 4,491
  • 6
  • 33
  • 43
  • 1
    Cursor created from IntPtr handle does not release the handle when it's disposed. It results in memory leak, unless use manually release Cursor.Handle. – Ondrej Petrzilka Sep 30 '16 at 07:56
  • 1
    Good point, thanks for mentioning this! – Walt D Sep 30 '16 at 17:48
  • It's not a good point, it's a critical point. Can you show an example of how you ended up successfully addressing this memory-leak issue? – Jazimov Nov 19 '18 at 15:23
  • @Jazimov I've edited my answer with an example. – Walt D Nov 19 '18 at 19:34
  • Thanks. I've been working with this and now the problem becomes where exactly to carry out the DestroyIcon operation--do it too soon and the cursor won't show properly... – Jazimov Nov 19 '18 at 23:53