📜  免费统一鼠标外观 - C# (1)

📅  最后修改于: 2023-12-03 15:22:32.635000             🧑  作者: Mango

免费统一鼠标外观 - C#

你是否曾遇到过自己购买了多款不同的鼠标,想要将它们的外观统一,却又不想花费大量的金钱去购买特定的鼠标外壳?

本篇文章将为您介绍如何使用C#语言编写一个免费的鼠标外观统一软件,以方便你在不同的场合下使用不同的鼠标,却仍能让它们的外观保持一致。

需求分析

在开始前,我们需要先明确几个需求:

  1. 能够读取当前使用的鼠标的ID号码;

  2. 能够将鼠标外观替换为统一的外观;

  3. 能够在程序关闭前,恢复原来鼠标的外观。

编写步骤
1. 引入命名空间
using System;
using System.Runtime.InteropServices;
using Microsoft.Win32;
2. 获取当前使用的鼠标ID
[DllImport("user32.dll")]
static extern bool GetCursorInfo(out CURSORINFO pci);

[StructLayout(LayoutKind.Sequential)]
struct POINT
{
    public int x;
    public int y;
}

[StructLayout(LayoutKind.Sequential)]
struct CURSORINFO
{
    public Int32 cbSize;
    public Int32 flags;
    public IntPtr hCursor;
    public POINT ptScreenPos;
}

// 获取当前使用的鼠标ID
int GetCursorId()
{
    CURSORINFO pci;
    pci.cbSize = Marshal.SizeOf(typeof(CURSORINFO));
    if (!GetCursorInfo(out pci))
    {
        throw new Exception("GetCursorInfo API failed!");
    }

    var id = pci.hCursor.ToInt32();
    if (id == 65538 || id == 65539)
    {
        return 0; // 0为系统默认
    }
    else
    {
        return id;
    }
}
3. 替换鼠标外观
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SystemParametersInfo(uint uiAction, uint uiParam, IntPtr pvParam, uint fWinIni);

// 替换鼠标外观
bool ReplaceCursorImage(string fileName)
{
    var result = SystemParametersInfo(0x0057, 0, Marshal.StringToHGlobalUni(fileName), 0x01 | 0x02);
    if (!result)
    {
        throw new Exception("SetCursor API failed!");
    }

    return true;
}
4. 恢复鼠标原来的外观
private const string RegPath = @"Control Panel\Cursors";
private readonly string[] _cursorNames = { "Arrow", "Help", "AppStarting", "Wait", "Crosshair", "IBeam", "SizeNS", "SizeWE", "SizeNWSE", "SizeNESW", "UpArrow", "No" };

[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SystemParametersInfo(uint uiAction, uint uiParam, IntPtr pvParam, uint fWinIni);

[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool SetSystemCursor(IntPtr hcur, uint id);

// 恢复鼠标原来的外观
bool ResetCursorImage()
{
    var baseKey = Registry.CurrentUser.OpenSubKey(RegPath, true);
    if (baseKey == null)
    {
        throw new Exception($"Cannot open {RegPath} registry key.");
    }

    foreach (var name in _cursorNames)
    {
        var file = baseKey.GetValue(name) as string;
        if (!string.IsNullOrEmpty(file))
        {
            var fullPath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), file);
            SetSystemCursor(System.Windows.Forms.Cursors.Default.Handle, (uint)Enum.Parse(typeof(System.Windows.Forms.Cursors), name));
        }
    }

    return true;
}
5. 整合代码

将以上三个方法整合到一个程序里:

class Program
{
    static void Main(string[] args)
    {
        try
        {
            var id = GetCursorId();
            var image = "new_cursor_file.cur";

            Console.WriteLine($"Current cursor ID: {id}");
            ReplaceCursorImage(image);
            Console.WriteLine($"Replaced cursor ID: {GetCursorId()}");

            Console.ReadKey(true);
            ResetCursorImage();
            Console.WriteLine($"Reset cursor ID: {GetCursorId()}");
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

    [DllImport("user32.dll")]
    static extern bool GetCursorInfo(out CURSORINFO pci);

    [DllImport("user32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool SystemParametersInfo(uint uiAction, uint uiParam, IntPtr pvParam, uint fWinIni);

    [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern bool SetSystemCursor(IntPtr hcur, uint id);

    [StructLayout(LayoutKind.Sequential)]
    struct POINT
    {
        public int x;
        public int y;
    }

    [StructLayout(LayoutKind.Sequential)]
    struct CURSORINFO
    {
        public Int32 cbSize;
        public Int32 flags;
        public IntPtr hCursor;
        public POINT ptScreenPos;
    }

    bool ReplaceCursorImage(string fileName)
    {
        var result = SystemParametersInfo(0x0057, 0, Marshal.StringToHGlobalUni(fileName), 0x01 | 0x02);
        if (!result)
        {
            throw new Exception("SetCursor API failed!");
        }

        return true;
    }

    int GetCursorId()
    {
        CURSORINFO pci;
        pci.cbSize = Marshal.SizeOf(typeof(CURSORINFO));
        if (!GetCursorInfo(out pci))
        {
            throw new Exception("GetCursorInfo API failed!");
        }

        var id = pci.hCursor.ToInt32();
        if (id == 65538 || id == 65539)
        {
            return 0;
        }
        else
        {
            return id;
        }
    }

    private const string RegPath = @"Control Panel\Cursors";
    private readonly string[] _cursorNames = { "Arrow", "Help", "AppStarting", "Wait", "Crosshair", "IBeam", "SizeNS", "SizeWE", "SizeNWSE", "SizeNESW", "UpArrow", "No" };

    bool ResetCursorImage()
    {
        var baseKey = Registry.CurrentUser.OpenSubKey(RegPath, true);
        if (baseKey == null)
        {
            throw new Exception($"Cannot open {RegPath} registry key.");
        }

        foreach (var name in _cursorNames)
        {
            var file = baseKey.GetValue(name) as string;
            if (!string.IsNullOrEmpty(file))
            {
                var fullPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), file);
                SetSystemCursor(Cursors.Default.Handle, (uint)Enum.Parse(typeof(Cursors), name));
            }
        }

        return true;
    }
}
总结

到此,我们已经完成了本篇文章的编写,成功实现了一个免费的鼠标外观统一软件。本文所讲述的代码已经实现了所提到的三个需求,并且较为简单易懂,希望能够对大家有所帮助。如果您在使用过程中遇到了问题,欢迎留言,我们会在最短的时间内回复您,祝大家使用愉快!