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. Thi
If you are working with WPF, you can create your own Mouse cursor and assign it. But this is not a system wide mouse cursor change. Here's some code that would do the trick. In the code below I am creating a cursor 50x50 pixels. You can draw your own shape on to the 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);
}
}
}
}
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);
}
}
}
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).
You can use your own image for the cursor if desired, bypassing all the resizing code. Just supply the Bitmap to SetCursor
.
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.
To use the class just call
SystemCursors.SetSystemCursorsSize(128);
Add these imports to your class:
[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);
read msdn articles about LoadImage and SetSystemCursor, especially about parameters they use.
Then use functions in your code:
// "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)
}
I Solve this problem by Useing intrueder's way.Supplement, the API LoadImage cannot Load.png. Use System.drawing.BitMap.Like this:Bitmap bmp = new Bitmap(str, true);
IntPtr p = bmp.GetHicon();
SetSystemCursor(p, OCR_NORMAL);