C# 如何在不使用互操作的情况下创建动态鼠标光标.NET?

C# 如何在不使用互操作的情况下创建动态鼠标光标.NET?,c#,.net,bitmap,cursor,mouse-cursor,C#,.net,Bitmap,Cursor,Mouse Cursor,我有一个应用程序,我对最终移植到mono感兴趣,所以我试图避免使用p/invoke来完成这项任务 我想动态加载一个光标,因为我有一个在应用程序中动态生成的位图。据我所知,不使用p/invoke最安全的方法是创建一个.cur文件,然后将其加载到内存流并使用构造函数。但是,我不知道如何创建.cur文件 我在Microsoft知识库中找到了这篇文章,它在某种程度上解释了格式,但我不确定在没有互操作调用的情况下如何使用它 其他人是否有我可以用来完成此任务的托管解决方案?很简单:你不能-你要求的功能不是.

我有一个应用程序,我对最终移植到mono感兴趣,所以我试图避免使用p/invoke来完成这项任务

我想动态加载一个光标,因为我有一个在应用程序中动态生成的位图。据我所知,不使用p/invoke最安全的方法是创建一个.cur文件,然后将其加载到内存流并使用构造函数。但是,我不知道如何创建.cur文件

我在Microsoft知识库中找到了这篇文章,它在某种程度上解释了格式,但我不确定在没有互操作调用的情况下如何使用它


其他人是否有我可以用来完成此任务的托管解决方案?

很简单:你不能-你要求的功能不是.NET framework的一部分,因此你需要使用本机

如果您的应用程序需要移植到mono,请将此代码隔离在一个类中,这样您就可以像使用编译器开关一样关闭它-这并不难。

我参考了以下文章:

您可以创建一个静态光标数组,并使用计时器对其进行更改

使动态鼠标光标产生效果

从位图创建静态光标非常简单,无需使用互操作

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        Icon icon = this.Icon;
        Bitmap bmp = icon.ToBitmap();
        Cursor cur = new Cursor(bmp.GetHicon());

        this.Cursor = cur;
    }
}

下面是VB.NET中动态创建位图并将其转换为光标的示例。不确定这将在7年以上的时间里帮助谁,但以下是:

Private Function GetCircleCursor(iDiameter As Integer) As Cursor
Dim oBitmap As Bitmap = New Bitmap(Convert.ToInt32(iDiameter), Convert.ToInt32(iDiameter), System.Drawing.Imaging.PixelFormat.Format32bppArgb)

    Using g As System.Drawing.Graphics = Graphics.FromImage(oBitmap)
        g.Clear(Color.Transparent)

        g.DrawEllipse(New System.Drawing.Pen(Color.White, 3), New Rectangle(0, 0, iDiameter, iDiameter))
        g.DrawEllipse(New System.Drawing.Pen(Color.Black, 1), New Rectangle(0, 0, iDiameter, iDiameter))
    End Using

    Return New Cursor(oBitmap.GetHicon)
End Function

下面的代码创建了一个以.cur格式填充数据的流,我用Mono在Ubuntu中成功地测试了它。但是,在自定义游标中不使用Win32 API的.NET:

游标类不支持动画游标(.ani文件)或非黑白颜色的游标

因此,在使用Mono的Unix中,一个光标会

  • 仅显示黑色和白色
  • 没有半透明像素,只有完全不透明/完全透明的像素
“”\_(ツ)_/“”

使用系统;
使用系统图;
使用系统、绘图、成像;
使用System.IO;
使用System.Linq;
使用System.Runtime.InteropServices;
使用System.Windows.Forms;
名称空间堆栈溢出示例
{
公共静态类CursorHelper
{
公共静态光标CreateCursor(位图bmp,点热点)
{
// https://en.wikipedia.org/wiki/ICO_(文件格式)
var bmpData=bmp.LockBits(新矩形(默认值为bmp.Size)、ImageLockMode.ReadOnly、PixelFormat.Format32bppArgb);
尝试
{
int numBytes=bmpData.Stride*bmpData.Height;
var bgraValues=新字节[numBytes];
封送处理副本(bmpData.Scan0,bgraValues,0,numBytes);
int max=Math.max(bmp.Width,bmp.Height);
如果(最大值>256)
抛出新的NotSupportedException();
字节iconSizeByte=_size.FirstOrDefault(s=>s>=max);//0表示256
int iconSizeI=iconSizeByte==0?256:iconSizeByte;
const int bytesperpoixel=4;
常量int bytesPerPixelSource=4;
byte[]emptyPixel=新字节[字节/像素];
使用(var stream=new MemoryStream())
使用(var writer=newbinarywriter(流))
{
writer.Write((ushort)0);//idReserved
writer.Write((ushort)2);//idType,1=.ico 2=.cur
writer.Write((ushort)1);//idCount
writer.Write(iconSizeByte);
writer.Write(iconSizeByte);
writer.Write((字节)0);//colorCount
writer.Write((字节)0);//保留
writer.Write((ushort)hospot.X);
writer.Write((ushort)hospot.Y);
var pixelsunt=iconSizeI*iconSizeI;
var xorLength=像素点云*字节/像素;
var和length=pixelsunt/8*2;
writer.Write((uint)(40+xorLength+andLength));//大小字节
writer.Write((uint)stream.Position+sizeof(uint));//fileOffset=22=0x16
writer.Write(40u);//cursorInfoHeader.biSize
writer.Write((int)iconSizeI);//cursorinfo头.biWidth
writer.Write((int)iconSizeI*2);//cursorinfo header.biHeight
writer.Write((ushort)1);//cursorinfo.biPlanes
Write.Write((ushort)(8*bytesperpoixel));//cursorinfo头.bibittcount
writer.Write(0u);//cursorinfo.biCompression
writer.Write(0u);//cursorinfo.biSizeImage
writer.Write(0);//cursorinfo头.biXPelsPerMeter;
writer.Write(0);//cursorinfo头.biYPelsPerMeter;
writer.Write(0u);//cursorinfo header.biclrued=binaryReader2.ReadUInt32();
writer.Write(0u);//cursorinfo header.biclremential=binaryReader2.ReadUInt32();
使用(var和mask=新内存流(和长度))
{
字节def=255;
对于(int j=0;j0)
courbyte=(字节)(courbyte&