如何在 C# 中渲染鼠标光标纹理?

How can I render the mouse cursor texture in c#?

这是我目前的情况:

[StructLayout(LayoutKind.Sequential)]
struct CursorInfo
{
  public Int32 cbSize;
  public Int32 flags
  public IntPtr hCursor;
  public POINT ptScreenPos;
}

[DllImport("user32.dll")]
static extern int GetSystemMetrics(SystemMetric smIndex);

public enum SystemMetric
{
  SM_CXICON              = 11, // 0x0B
  SM_CYICON              = 12, // 0x0C
}


[DllImport("user32.dll", SetLastError = true)]
static extern bool DrawIconEx(IntPtr hdc,
  int xLeft,
  int yTop,
  IntPtr hIcon,
  int cxWidth,
  int cyHeight,
  int istepIfAniCur,
  IntPtr hbrFlickerFreeDraw,
  int diFlags);

const int DI_MASK = 0x0001;
const int DI_IMAGE = 0x0002;
const int DI_NORMAL = 0x0003;
const int DI_COMPAT = 0x0004;
const int DI_DEFAULTSIZE = 0x0008;
const int DI_NOMIRROR = 0x0010;

public struct IconInfo
{
  public bool fIcon;
  public int xHotspot;
  public int yHotspot;
  public IntPtr hbmMask;
  public IntPtr hbmColor;
}

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetIconInfo(IntPtr hIcon, ref IconInfo pIconInfo);



Bitmap GetCursorBitmap()
{
  CursorInfo ci = new CursorInfo ();
    ci.cbSize = Marshal.SizeOf (typeof(CursorInfo));

  if (!GetCursorInfo (ref ci)) {
    throw new Exception("Failed to get cursor info");
  }

  IntPtr cursorPointer = ci.hCursor;

  int iconWidth = GetSystemMetrics (SystemMetric.SM_CXICON);
  int iconHeight = GetSystemMetrics (SystemMetric.SM_CYICON);

  Bitmap bmp;
  bmp = new System.Drawing.Bitmap(iconWidth, iconHeight, PixelFormat.Format32bppRgb);
  bmp.MakeTransparent();

  Graphics gfxBmp = Graphics.FromImage(bmp);       

  IntPtr hdcBitmap = gfxBmp.GetHdc();

  DrawIconEx(hdcBitmap, 0, 0, cursorPointer, iconWidth, iconHeight, 0, IntPtr.Zero, DI_NORMAL);

  // DrawIcon(hdcBitmap, 0, 0, cursorPointer); has the same problem

  IconInfo hotSpotInfo = new IconInfo ();
  GetIconInfo(cursorPointer, ref hotSpotInfo);

  Point hotSpot = new Point(hotSpotInfo.xHotspot, hotSpotInfo.yHotspot)

  gfxBmp.ReleaseHdc(hdcBitmap);               
  gfxBmp.Dispose();

  return bmp;
}

(我在别处使用热点信息,但我省略了那部分,因为这里重要的是获取该信息)。

这工作了很长一段时间,但最终我收到一条错误消息

A null reference or invalid value was found [GDI+ status: InvalidParameter]

来自

IntPtr hdcBitmap = gfxBmp.GetHdc();

我相当确定这是由于内存泄漏造成的。我在我的应用程序中的每个更新步骤(大约每秒 30 步)调用此方法,所以我相信如果有一个它会很快出现,就像这个一样。内存泄漏在哪里?还是这里有其他问题?

public IntPtr hbmMask;
public IntPtr hbmColor;

这两个字段在调用 GetIconInfo() 后最终包含位图句柄,并且必须通过 p/invoke 调用 DeleteObject().

来释放这些句柄

不要忘记在调用者中处理 bmp