Using Custom Colored Cursors in a C# Windows Application

十年热恋 提交于 2019-11-26 23:08:58

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");

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;

        }
    }
}

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.)

Pedery

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:

Windows Forms: Making a cursor bitmap partially transparent

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!