如何在Windows中覆盖最大32x32鼠标大小,就像这个程序一样

时间:2012-12-03 17:03:58

标签: c# registry mouse accessibility

我希望我的程序能够覆盖32x32的最大强制鼠标大小,就像附图中的程序一样,光标如图所示为72x72。这是ProcMon的捕获,显示游标更改时发生的情况。

但是,如果我尝试自己更改游标文件的注册表值,然后使用

推送更改

SystemParametersInfo(SPI.SPI_SETCURSORS, 0, IntPtr.Zero, SPIF.SPIF_SENDCHANGE);

然后光标会改变,但它仍然限制在32x32的最大尺寸。这个程序如何能够绕过这个限制?此外,游标在程序结束后仍保留,因此它不能在运行时执行,但必须覆盖某处的设置。

enter image description here

感谢您的帮助,我无法在网上找到这样的任何内容,所以我甚至不知道是否有人会得到答案。

编辑:我看到一些名为C:\Windows\SysWOW64\Imageres.dll的文件的访问权限。它们只是读取,但也许这些游标存储在这里,或者它们以某种方式修改了这个文件。但我认为它可能会让一个比我更有经验的人走上正轨。

编辑2:我认为尺寸是由SM_CXCURSOR和SM_CYCURSOR变量决定的。如果我能找到一种方法来设置这些,我可能会做生意。要编写一个快速程序,在程序运行时使用巨大的鼠标光标在PC上获取这些值,看看它返回的内容......

编辑3:没有运气;带有巨大光标的PC为SM_CXCURSOR和SM_CYCURSOR返回32x32。

4 个答案:

答案 0 :(得分:7)

使用SetSystemCursor可以将光标设置为比标准光标大得多的图像。

这是我用于调整系统游标大小的类:

using System;
using System.Drawing;
using System.Reflection;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication1
{
    class SystemCursors
    {
        [DllImport("user32.dll")]
        static extern bool SetSystemCursor(IntPtr hcur, uint id);

        enum CursorShift
        {
            Centered,
            LowerRight,
        }

        public static void SetSystemCursorsSize(int newSize)
        {
            ResizeCursor(System.Windows.Forms.Cursors.AppStarting, newSize, CursorShift.LowerRight);
            ResizeCursor(System.Windows.Forms.Cursors.Arrow, newSize, CursorShift.LowerRight);
            ResizeCursor(System.Windows.Forms.Cursors.Cross, newSize, CursorShift.Centered);
            ResizeCursor(System.Windows.Forms.Cursors.Hand, newSize, CursorShift.LowerRight);
            ResizeCursor(System.Windows.Forms.Cursors.Help, newSize, CursorShift.LowerRight);
            ResizeCursor(System.Windows.Forms.Cursors.HSplit, newSize, CursorShift.Centered);
            ResizeCursor(System.Windows.Forms.Cursors.IBeam, newSize, CursorShift.Centered);
            ResizeCursor(System.Windows.Forms.Cursors.No, newSize, CursorShift.LowerRight);
            ResizeCursor(System.Windows.Forms.Cursors.NoMove2D, newSize, CursorShift.LowerRight);
            ResizeCursor(System.Windows.Forms.Cursors.NoMoveHoriz, newSize, CursorShift.LowerRight);
            ResizeCursor(System.Windows.Forms.Cursors.NoMoveVert, newSize, CursorShift.LowerRight);
            ResizeCursor(System.Windows.Forms.Cursors.PanEast, newSize, CursorShift.Centered);
            ResizeCursor(System.Windows.Forms.Cursors.PanNE, newSize, CursorShift.Centered);
            ResizeCursor(System.Windows.Forms.Cursors.PanNorth, newSize, CursorShift.Centered);
            ResizeCursor(System.Windows.Forms.Cursors.PanNW, newSize, CursorShift.Centered);
            ResizeCursor(System.Windows.Forms.Cursors.PanSE, newSize, CursorShift.Centered);
            ResizeCursor(System.Windows.Forms.Cursors.PanSouth, newSize, CursorShift.Centered);
            ResizeCursor(System.Windows.Forms.Cursors.PanSW, newSize, CursorShift.Centered);
            ResizeCursor(System.Windows.Forms.Cursors.PanWest, newSize, CursorShift.Centered);
            ResizeCursor(System.Windows.Forms.Cursors.SizeAll, newSize, CursorShift.Centered);
            ResizeCursor(System.Windows.Forms.Cursors.SizeNESW, newSize, CursorShift.Centered);
            ResizeCursor(System.Windows.Forms.Cursors.SizeNS, newSize, CursorShift.Centered);
            ResizeCursor(System.Windows.Forms.Cursors.SizeNWSE, newSize, CursorShift.Centered);
            ResizeCursor(System.Windows.Forms.Cursors.SizeWE, newSize, CursorShift.Centered);
            ResizeCursor(System.Windows.Forms.Cursors.UpArrow, newSize, CursorShift.Centered);
            ResizeCursor(System.Windows.Forms.Cursors.VSplit, newSize, CursorShift.Centered);
            ResizeCursor(System.Windows.Forms.Cursors.WaitCursor, newSize, CursorShift.LowerRight);
        }

        private static void ResizeCursor(System.Windows.Forms.Cursor cursor, 
            int newSize, CursorShift cursorShift)
        {
            Bitmap cursorImage = GetSystemCursorBitmap(cursor);
            cursorImage = ResizeCursorBitmap(cursorImage, new Size(newSize, newSize), cursorShift);
            SetCursor(cursorImage, getResourceId(cursor));
        }

        public static Bitmap GetSystemCursorBitmap(System.Windows.Forms.Cursor cursor)
        {
            Bitmap bitmap = new Bitmap(
                cursor.Size.Width, cursor.Size.Height,
                System.Drawing.Imaging.PixelFormat.Format32bppArgb);

            Graphics graphics = Graphics.FromImage(bitmap);

            cursor.Draw(graphics,
                new Rectangle(new Point(0, 0), cursor.Size));

            bitmap = Crop(bitmap);

            return bitmap;
        }

        private static Bitmap Crop(Bitmap bmp)
        {
            //code from http://stackoverflow.com/a/10392379/935052

            int w = bmp.Width;
            int h = bmp.Height;

            Func<int, bool> allWhiteRow = row =>
            {
                for (int i = 0; i < w; ++i)
                    if (bmp.GetPixel(i, row).A != 0)
                        return false;
                return true;
            };

            Func<int, bool> allWhiteColumn = col =>
            {
                for (int i = 0; i < h; ++i)
                    if (bmp.GetPixel(col, i).A != 0)
                        return false;
                return true;
            };

            int topmost = 0;
            for (int row = 0; row < h; ++row)
            {
                if (allWhiteRow(row))
                    topmost = row;
                else break;
            }

            int bottommost = 0;
            for (int row = h - 1; row >= 0; --row)
            {
                if (allWhiteRow(row))
                    bottommost = row;
                else break;
            }

            int leftmost = 0, rightmost = 0;
            for (int col = 0; col < w; ++col)
            {
                if (allWhiteColumn(col))
                    leftmost = col;
                else
                    break;
            }

            for (int col = w - 1; col >= 0; --col)
            {
                if (allWhiteColumn(col))
                    rightmost = col;
                else
                    break;
            }

            if (rightmost == 0) rightmost = w; // As reached left
            if (bottommost == 0) bottommost = h; // As reached top.

            int croppedWidth = rightmost - leftmost;
            int croppedHeight = bottommost - topmost;

            if (croppedWidth == 0) // No border on left or right
            {
                leftmost = 0;
                croppedWidth = w;
            }

            if (croppedHeight == 0) // No border on top or bottom
            {
                topmost = 0;
                croppedHeight = h;
            }

            try
            {
                var target = new Bitmap(croppedWidth, croppedHeight);
                using (Graphics g = Graphics.FromImage(target))
                {
                    g.DrawImage(bmp,
                      new RectangleF(0, 0, croppedWidth, croppedHeight),
                      new RectangleF(leftmost, topmost, croppedWidth, croppedHeight),
                      GraphicsUnit.Pixel);
                }
                return target;
            }
            catch (Exception ex)
            {
                throw new Exception(
                  string.Format("Values are topmost={0} btm={1} left={2} right={3} croppedWidth={4} croppedHeight={5}", topmost, bottommost, leftmost, rightmost, croppedWidth, croppedHeight),
                  ex);
            }
        }

        private static Bitmap ResizeCursorBitmap(Bitmap bitmap, Size size, CursorShift cursorShift)
        {
            if (size.Width > 32)
            {
                //shifting must occur
                Bitmap intermediateBitmap = new Bitmap(64, 64);
                Graphics intermediateGraphics = Graphics.FromImage(intermediateBitmap);
                if (cursorShift == CursorShift.LowerRight)
                    //place the mouse cursor in the lower right hand quadrant of the bitmap
                    intermediateGraphics.DrawImage(bitmap,
                        intermediateBitmap.Width / 2, intermediateBitmap.Height / 2);
                else if (cursorShift == CursorShift.Centered)
                    intermediateGraphics.DrawImage(bitmap,
                        intermediateBitmap.Width / 2 - bitmap.Width / 2,
                        intermediateBitmap.Height / 2 - bitmap.Height / 2);

                //now we have a shifted bitmap; use it to draw the resized cursor
                //Bitmap finalBitmap = new Bitmap(intermediateBitmap, size);    //normal quality
                Bitmap finalBitmap = new Bitmap(size.Width, size.Height);
                Graphics finalGraphics = Graphics.FromImage(finalBitmap);
                finalGraphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                finalGraphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                finalGraphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                finalGraphics.DrawImage(intermediateBitmap, 0, 0, finalBitmap.Width, finalBitmap.Height);
                return finalBitmap;
            }
            else
            {
                Bitmap newBitmap = new Bitmap(bitmap, size);
                return newBitmap;
            }
        }

        private static uint getResourceId(System.Windows.Forms.Cursor cursor)
        {
            FieldInfo fi = typeof(System.Windows.Forms.Cursor).GetField(
                "resourceId", BindingFlags.NonPublic | BindingFlags.Instance);
            object obj = fi.GetValue(cursor);
            return Convert.ToUInt32((int)obj);
        }

        private static void SetCursor(Bitmap bitmap, uint whichCursor)
        {
            IntPtr ptr = bitmap.GetHicon();
            bool retval = SetSystemCursor(ptr, whichCursor);
        }

    }
}

它的工作原理是获取System.Windows.Forms.Cursors中提供的当前系统光标并使用Cursor.Draw从中制作图像。然后将图像调整大小为所需大小。这需要将光标图像移动到右下角(如箭头指针)或将光标图像置于较大图像内(如Cross和IBeam)。

如果需要,您可以使用自己的图像作为光标,绕过所有调整大小的代码。只需将位图提供给SetCursor

新光标图像准备就绪后,所需的最后一段数据就是我们要替换的光标的ID。每个System.Windows.Forms.Cursor确实包含此信息,但在私有变量中,因此使用反射来获取值。如果您希望避免反射,则可以构建一个包含这些值的表。有关值列表,请参阅MSDN SetSystemCursor

要使用该课程,请致电

SystemCursors.SetSystemCursorsSize(128);

答案 1 :(得分:6)

如果您正在使用WPF,则可以创建自己的鼠标光标并进行分配。但这不是系统范围内的鼠标光标变化。这里有一些可以解决问题的代码。在下面的代码中,我创建一个50x50像素的光标。您可以在RenderTargetBitmap

上绘制自己的形状
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        Mouse.OverrideCursor = CreateCursor(50,50, Brushes.Gold, null);
    }

    Cursor CreateCursor(double rx, double ry, SolidColorBrush brush, Pen pen)
    {
        var vis = new DrawingVisual();
        using (var dc = vis.RenderOpen())
        {
            dc.DrawRectangle(brush, new Pen(Brushes.Black, 0.1), new Rect(0, 0, rx, ry));
            dc.Close();
        }
        var rtb = new RenderTargetBitmap(64, 64, 96, 96, PixelFormats.Pbgra32);
        rtb.Render(vis);

        using (var ms1 = new MemoryStream())
        {
            var penc = new PngBitmapEncoder();
            penc.Frames.Add(BitmapFrame.Create(rtb));
            penc.Save(ms1);

            var pngBytes = ms1.ToArray();
            var size = pngBytes.GetLength(0);

            //.cur format spec http://en.wikipedia.org/wiki/ICO_(file_format)
            using (var ms = new MemoryStream())
            {
                {//ICONDIR Structure
                    ms.Write(BitConverter.GetBytes((Int16)0), 0, 2);//Reserved must be zero; 2 bytes
                    ms.Write(BitConverter.GetBytes((Int16)2), 0, 2);//image type 1 = ico 2 = cur; 2 bytes
                    ms.Write(BitConverter.GetBytes((Int16)1), 0, 2);//number of images; 2 bytes
                }

                {//ICONDIRENTRY structure
                    ms.WriteByte(32); //image width in pixels
                    ms.WriteByte(32); //image height in pixels

                    ms.WriteByte(0); //Number of Colors in the color palette. Should be 0 if the image doesn't use a color palette
                    ms.WriteByte(0); //reserved must be 0

                    ms.Write(BitConverter.GetBytes((Int16)(rx / 2.0)), 0, 2);//2 bytes. In CUR format: Specifies the horizontal coordinates of the hotspot in number of pixels from the left.
                    ms.Write(BitConverter.GetBytes((Int16)(ry / 2.0)), 0, 2);//2 bytes. In CUR format: Specifies the vertical coordinates of the hotspot in number of pixels from the top.

                    ms.Write(BitConverter.GetBytes(size), 0, 4);//Specifies the size of the image's data in bytes
                    ms.Write(BitConverter.GetBytes((Int32)22), 0, 4);//Specifies the offset of BMP or PNG data from the beginning of the ICO/CUR file
                }

                ms.Write(pngBytes, 0, size);//write the png data.
                ms.Seek(0, SeekOrigin.Begin);
                return new Cursor(ms);
            }
        }
    }

}

答案 2 :(得分:1)

将这些导入添加到您的班级:

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern IntPtr LoadImage(IntPtr hinst, string lpszName, uint uType, int cxDesired, int cyDesired, uint fuLoad);

[DllImport("user32.dll")]
static extern bool SetSystemCursor(IntPtr hcur, uint id);

阅读有关LoadImageSetSystemCursor的msdn文章,尤其是有关他们使用的参数的文章。

然后在代码中使用函数:

// "cursor.cur" - cursor image of any size you want
// 2 == IMAGE_CURSOR (from Winuser.h)
// cxDesired = 0 and cyDesired = 0, using original image size
// 0x8010 == LR_DEFAULTCOLOR | LR_SHARED | LR_LOADFROMFILE (from Winuser.h)
var ptr = LoadImage(IntPtr.Zero, "cursor.cur", 2, 0, 0, 0x8010);
if(ptr != IntPtr.Zero)
{
    SetSystemCursor(ptr, 32512); // 32512 == OCR_NORMAL (from Winuser.h)
}

答案 3 :(得分:0)

我通过使用intrueder的方法来解决这个问题。补充,API LoadImage不能Load.png。使用System.drawing.BitMap.Like:Bitmap bmp = new Bitmap(str, true); IntPtr p = bmp.GetHicon(); SetSystemCursor(p, OCR_NORMAL);