如何像这个程序一样在 Windows 中覆盖最大 32x32 鼠标大小 [英] How to override maximum 32x32 mouse size in Windows like this program can

查看:19
本文介绍了如何像这个程序一样在 Windows 中覆盖最大 32x32 鼠标大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望我的程序能够像附加图片中的程序一样覆盖 32x32 的最大强制鼠标尺寸,图中的光标是 72x72.这是来自 ProcMon 的捕获,显示了光标更改时发生的情况.

I'd like for my program to be able to override the maximum imposed mouse size of 32x32 much like the program in the picture attached does, the cursor pictured is 72x72. This is a capture from ProcMon showing what's going on when the cursors change.

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

However, if I try to change the registry values for the cursor files myself and then push the changes using

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

然后光标会改变,但它仍然限于 32x32 的最大尺寸.这个程序是如何绕过这个限制的?此外,光标在程序结束后仍然存在,因此它不能是运行时正在执行的操作,而必须覆盖某处的设置.

then the cursor will change, but it's still limited to the 32x32 maximum size. How was this program able to get around that restriction? Also, the cursors remain after the program ends, so it can't be something it's doing while running, but must override a setting somewhere.

谢谢你的帮助,我在网上找不到这样的东西,所以我什至不知道有没有人会回答.

Thanks for your help, I haven't been able to find ANYTHING like this on the net, so I don't even know if anyone will have the answer.

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

I see some access to a file called C:WindowsSysWOW64Imageres.dll. They're only reads, but maybe these cursors are stored in here, or they modified this file somehow. But I figured it might get someone with more experience than myself off on the right track.

编辑 2:我相信大小是由 SM_CXCURSOR 和 SM_CYCURSOR 变量决定的.如果我能找到一种方法来设置这些,我可能会做生意.打算编写一个快速程序,在程序运行和巨大的鼠标光标的情况下在 PC 上获取这些值,然后看看它返回什么......

EDIT 2: I believe the sizes are dictated by the SM_CXCURSOR and SM_CYCURSOR variables. If I could find a way to set these, I might be in business. Going to write a quick program to get me those values on the PC with the program running and huge mouse cursor and see what it returns...

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

EDIT 3: No luck; the PC with the huge cursor returns 32x32 for it's SM_CXCURSOR and SM_CYCURSOR.

推荐答案

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

Using SetSystemCursor it is possible to set a cursor to an image of much larger size than the standard cursor.

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

Here is a class I have for resizing the system cursors:

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

It works by getting the current system cursor as provided in System.Windows.Forms.Cursors and making an image from it with Cursor.Draw. The image is then resized to the desired size. This requires shifting the cursor image, either to the lower right hand corner (like for arrow pointers) or centering the cursor image inside the larger image (like for Cross and IBeam).

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

You can use your own image for the cursor if desired, bypassing all the resizing code. Just supply the Bitmap to SetCursor.

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

Once the new cursor image is ready, the last piece of data needed is the ID of the cursor we are trying to replace. Each System.Windows.Forms.Cursor does contain this information, but in a private variable, so reflection is used to get the value. If you prefer to avoid reflection, you could build a table of these values instead. See MSDN SetSystemCursor for a list of values.

要使用该类,只需调用

SystemCursors.SetSystemCursorsSize(128);

这篇关于如何像这个程序一样在 Windows 中覆盖最大 32x32 鼠标大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆