Using Custom Colored Cursors in a C# Windows Application [closed]
Asked Answered
G

5

7

I am developing a SDG (Single Display Groupware) application, and for that I need multiple cursors (to the simplest of different colors) for the single window. I came to know that with C# you can just use black and white cursors, which does not solve my problem.

Geraldina answered 29/11, 2010 at 16:33 Comment(5)
Colour cursors work fine. How did you come to find out that you can only use black and white cursors?Malapropism
And will Windows let you have more than 1 cursor?Blase
I once needed to create dynamic cursors on the fly. This turned out to pose weird issues, especially since semitransparency would blend against black and make the cursors too dark. In the end I solved the problem with some help from the SO community and the whole solution is displayed here: https://mcmap.net/q/913072/-windows-forms-making-a-cursor-bitmap-partially-transparentGentleness
@Tim - I read in one of the C# forums that using the default Cursor class, you can only use black & white cursors (not even grayscale ones).Geraldina
@Henk - I am using a C# API called SDGToolkit (from University of Calgary), which does all the low level stuff of getting multiple inputs from keyboards and mice and even tablets.Geraldina
H
15

The Cursor class is rather poorly done. For some mysterious reason it uses a legacy COM interface (IPicture), that interface doesn't support colored and animated cursors. It is fixable with some fairly ugly elbow grease:

using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Reflection;

static class NativeMethods {
    public static Cursor LoadCustomCursor(string path) {
        IntPtr hCurs = LoadCursorFromFile(path);
        if (hCurs == IntPtr.Zero) throw new Win32Exception();
        var curs = new Cursor(hCurs);
        // Note: force the cursor to own the handle so it gets released properly
        var fi = typeof(Cursor).GetField("ownHandle", BindingFlags.NonPublic | BindingFlags.Instance);
        fi.SetValue(curs, true);
        return curs;
    }
    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    private static extern IntPtr LoadCursorFromFile(string path);
}

Sample usage:

this.Cursor = NativeMethods.LoadCustomCursor(@"c:\windows\cursors\aero_busy.ani");
Homogamy answered 29/11, 2010 at 18:51 Comment(1)
Thanks Hans you have been my hero recently. I just want to add some note that if someone loads that from inside a Control constructor with a path directory just like "aero_busy.ani" (assuming the .ani file is present in the root app directory) that will make the Designer to stop working, so in my case I returned nullptr instead of throwing the Win32Exception then only change the Cursor if it's different than nullptr.Unnerve
B
4

This thread is pretty old, but it's one of the first hits on Google, so here's the answer for VS 2019:

someControl.Cursor = new Cursor(Properties.Resources.somePNG.GetHicon());

You should add 'somePNG.png' with whatever transparency you like as a project resource.

Hope it helps someone in 2020.

Bethea answered 8/5, 2020 at 5:58 Comment(0)
G
3

I also tried something different and it seems to work with different colored cursors, but the only problem with this piece of code is that the Hotspot coordinates for the mouse cursors are not exact i.e. the are moved slightly to the right. But this can be fixed by considering an offset in the code.

The code is as follows:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.InteropServices;

namespace MID
{    
    public partial class CustomCursor : Form
    {
        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern IntPtr LoadCursorFromFile(string filename);

        public CustomCursor()
        {
            InitializeComponent();

            Bitmap bmp = (Bitmap)Bitmap.FromFile("Path of the cursor file saved as .bmp");
            bmp.MakeTransparent(Color.Black);
            IntPtr ptr1 = blue.GetHicon();

            Cursor cur = new Cursor(ptr1);
            this.Cursor = cur;

        }
    }
}
Geraldina answered 30/11, 2010 at 10:42 Comment(0)
S
1

You can load cursors from file dynamically like this:

var myCursor = new Cursor("myCursor.cur");

After you have loaded it, you can set the cursor of any control like this:

myControl.Cursor = myCursor;

The cursor also accepts a stream as a constructor parameter. This means that you can load from a resource embedded in your application, rather than from the file system.

Windows will not let you have more than one cursor, but you can draw more than one on your control. You can use the cursor object's Draw method like so:

myCursor.Draw(g, new Rectangle(...));

If you are using TCP/IP to send the cursor data between clients, then this should be enough to work.

However, there have been a few applications that have supported multiple input on a single PC. (For example, Rag Doll Kung Fu) For this, you are looking at something that the .NET framework doesn't support.

You will probably have to look into PInvoking some USB calls. (I don't have much experience here, so I can't ellaborate.)

Shortwave answered 29/11, 2010 at 16:37 Comment(1)
Thanks John, but I actually tried this but it did not work for me, and for the multiple mouse controls on my windows application, basically I am using a C# API called SDGToolkit which handles all the low level stuff.Geraldina
H
0

The only problem is that the hotspot will be in the centre of the file. So either:

Make the file twice as wide and twice as tall, and place the icon in the lower right quadrant.

Or

Use this complicated code to adjust the hotspot: Change Cursor HotSpot in WinForms / .NET

Hildegardehildesheim answered 9/5, 2020 at 19:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.