Хотя я не могу точно объяснить, почему это происходит, я думаю, что могу показать, как это обойти.
Структура ICONINFO содержит два члена, hbmMask и hbmColor, которые содержат соответственно маску и цветные растровые изображения для курсора (официальную документацию см. На странице MSDN ICONINFO ).
Когда вы вызываете GetIconInfo () для курсора по умолчанию, структура ICONINFO содержит как действительные маски, так и цветные растровые изображения, как показано ниже (Примечание. Красная граница была добавлена для четкого отображения границ изображения):
Растровое изображение маски курсора по умолчанию
Цветовая карта курсора по умолчанию
Когда Windows рисует курсор по умолчанию, растровое изображение маски сначала применяется с растровой операцией AND, а затем растровое изображение цвета применяется с растровой операцией XOR. Это приводит к непрозрачному курсору и прозрачному фону.
Когда вы вызываете GetIconInfo () для курсора I-Beam, структура ICONINFO содержит только действительную битовую карту маски и не содержит цветовой битовой карты, как показано ниже (Примечание: снова была добавлена красная граница для четкого отображения границы изображения):
Растровое изображение маски курсора I-Beam
Согласно документации ICONINFO, курсор I-Beam является монохромным курсором. Верхняя половина битовой карты маски - это маска AND, а нижняя половина битовой карты маски - битовая карта XOR. Когда Windows рисует курсор I-Beam, верхняя половина этого растрового изображения сначала рисуется поверх рабочего стола с помощью растровой операции AND. Затем нижняя половина растрового изображения рисуется поверх растровой операции XOR. На экране курсор будет отображаться как инверсия содержимого позади него.
Один из комментариев к оригинальной статье, на которую вы ссылаетесь, упоминает об этом. На рабочем столе, поскольку растровые операции применяются к содержимому рабочего стола, курсор будет отображаться правильно. Однако, когда изображение рисуется без фона, как в опубликованном коде, растровые операции, выполняемые Windows, приводят к блеклому изображению.
При этом обновленный метод CaptureCursor () будет обрабатывать как цветные, так и монохромные курсоры, предоставляя изображение черного курсора, когда курсор монохромный.
static Bitmap CaptureCursor(ref int x, ref int y)
{
Win32Stuff.CURSORINFO cursorInfo = new Win32Stuff.CURSORINFO();
cursorInfo.cbSize = Marshal.SizeOf(cursorInfo);
if (!Win32Stuff.GetCursorInfo(out cursorInfo))
return null;
if (cursorInfo.flags != Win32Stuff.CURSOR_SHOWING)
return null;
IntPtr hicon = Win32Stuff.CopyIcon(cursorInfo.hCursor);
if (hicon == IntPtr.Zero)
return null;
Win32Stuff.ICONINFO iconInfo;
if (!Win32Stuff.GetIconInfo(hicon, out iconInfo))
return null;
x = cursorInfo.ptScreenPos.x - ((int)iconInfo.xHotspot);
y = cursorInfo.ptScreenPos.y - ((int)iconInfo.yHotspot);
using (Bitmap maskBitmap = Bitmap.FromHbitmap(iconInfo.hbmMask))
{
// Is this a monochrome cursor?
if (maskBitmap.Height == maskBitmap.Width * 2)
{
Bitmap resultBitmap = new Bitmap(maskBitmap.Width, maskBitmap.Width);
Graphics desktopGraphics = Graphics.FromHwnd(Win32Stuff.GetDesktopWindow());
IntPtr desktopHdc = desktopGraphics.GetHdc();
IntPtr maskHdc = Win32Stuff.CreateCompatibleDC(desktopHdc);
IntPtr oldPtr = Win32Stuff.SelectObject(maskHdc, maskBitmap.GetHbitmap());
using (Graphics resultGraphics = Graphics.FromImage(resultBitmap))
{
IntPtr resultHdc = resultGraphics.GetHdc();
// These two operation will result in a black cursor over a white background.
// Later in the code, a call to MakeTransparent() will get rid of the white background.
Win32Stuff.BitBlt(resultHdc, 0, 0, 32, 32, maskHdc, 0, 32, Win32Stuff.TernaryRasterOperations.SRCCOPY);
Win32Stuff.BitBlt(resultHdc, 0, 0, 32, 32, maskHdc, 0, 0, Win32Stuff.TernaryRasterOperations.SRCINVERT);
resultGraphics.ReleaseHdc(resultHdc);
}
IntPtr newPtr = Win32Stuff.SelectObject(maskHdc, oldPtr);
Win32Stuff.DeleteObject(newPtr);
Win32Stuff.DeleteDC(maskHdc);
desktopGraphics.ReleaseHdc(desktopHdc);
// Remove the white background from the BitBlt calls,
// resulting in a black cursor over a transparent background.
resultBitmap.MakeTransparent(Color.White);
return resultBitmap;
}
}
Icon icon = Icon.FromHandle(hicon);
return icon.ToBitmap();
}
Есть некоторые проблемы с кодом, которые могут или не могут быть проблемой.
- Проверка монохромного курсора просто проверяет, равна ли высота двойной ширине. Хотя это кажется логичным, документация ICONINFO не требует, чтобы этим определялся только монохромный курсор.
- Возможно, существует лучший способ визуализации курсора, который я использовал комбинацией вызовов методов BitBlt () - BitBlt () - MakeTransparent ().