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

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

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

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

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

在此处输入图像描述

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

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

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

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

使用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 allWhiteRow = row => { for (int i = 0; i < w; ++i) if (bmp.GetPixel(i, row).A != 0) return false; return true; }; Func 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图像。 然后将图像resize为所需大小。 这需要将光标图像移动到右下角(如箭头指针)或将光标图像置于较大图像内(如Cross和IBeam)。

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

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

要使用该类只需调用

 SystemCursors.SetSystemCursorsSize(128); 

如果您正在使用WPF,则可以创建自己的鼠标光标并进行分配。 但这不是系统范围内的鼠标光标变化。 这里有一些代码可以解决问题。 在下面的代码中,我创建一个50×50像素的光标。 您可以在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); } } } } 

将这些导入添加到您的类:

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

阅读有关LoadImage和SetSystemCursor的 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) } 

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