如何获取Windows系统DPI缩放后的精确光标位图?
获取屏幕实际显示的精确光标位图解决方案
要解决高DPI环境下获取系统光标精确位图的问题,核心是处理DPI感知并获取对应分辨率的光标资源,以下是具体实现步骤:
1. 启用应用的DPI感知
只有让应用支持Per-Monitor DPI感知,才能避免系统自动缩放,获取到真实的光标尺寸。
- 通过应用清单配置(推荐):
<application xmlns="urn:schemas-microsoft-com:asm.v3"> <windowsSettings> <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware> </windowsSettings> </application> - 或在代码中动态设置(Windows 10 1703及以上版本):
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
2. 获取当前DPI下的光标真实尺寸
根据显示器DPI计算光标实际显示的尺寸:
// 获取系统DPI(或用GetDpiForWindow(hWnd)获取窗口所在显示器的DPI) UINT dpi = GetDpiForSystem(); // 获取当前DPI对应的光标宽高 int cursorWidth = GetSystemMetricsForDpi(SM_CXCURSOR, dpi); int cursorHeight = GetSystemMetricsForDpi(SM_CYCURSOR, dpi);
3. 绘制并获取精确的光标位图
创建带Alpha通道的32位DIB位图,在内存DC中绘制光标以保留透明效果和高分辨率:
// 初始化BITMAPINFO,创建32位带Alpha的DIB BITMAPINFO bmi = {0}; bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = cursorWidth; bmi.bmiHeader.biHeight = -cursorHeight; // 采用顶部向下的图像存储格式 bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 32; bmi.bmiHeader.biCompression = BI_RGB; void* pBitmapBits = nullptr; HBITMAP hCursorBitmap = CreateDIBSection(nullptr, &bmi, DIB_RGB_COLORS, &pBitmapBits, nullptr, 0); // 创建兼容内存DC并绑定DIB位图 HDC hMemDC = CreateCompatibleDC(nullptr); HGDIOBJ hOldBitmap = SelectObject(hMemDC, hCursorBitmap); // 获取当前光标句柄并绘制到内存DC HCURSOR hCurrentCursor = GetCursor(); DrawIconEx(hMemDC, 0, 0, hCurrentCursor, cursorWidth, cursorHeight, 0, nullptr, DI_NORMAL | DI_COMPAT); // 此时hCursorBitmap即为屏幕实际显示的精确光标位图,可用于后续像素操作 // 清理资源(使用完位图后再调用DeleteObject) SelectObject(hMemDC, hOldBitmap); DeleteDC(hMemDC); // DeleteObject(hCursorBitmap);
4. 替代方案:获取高分辨率光标资源
如果需要直接获取光标对应的高分辨率位图,可先将光标转换为对应DPI的版本,再提取位图:
// 将原始光标转换为当前DPI对应的高分辨率版本 HCURSOR hHiResCursor = CopyImage(hCursor, IMAGE_CURSOR, cursorWidth, cursorHeight, LR_COPYFROMRESOURCE); // 调用GetIconInfoExW获取高分辨率位图信息 ICONINFOEXW iconInfo = {0}; iconInfo.cbSize = sizeof(ICONINFOEXW); GetIconInfoExW(hHiResCursor, &iconInfo); // iconInfo.hbmColor即为高分辨率的彩色光标位图 // 使用完后清理资源 DeleteObject(iconInfo.hbmColor); DeleteObject(iconInfo.hbmMask); DestroyCursor(hHiResCursor);
关键注意事项
- 必须启用DPI感知,否则系统会对应用的DC进行缩放,导致绘制的光标为低分辨率放大版本。
- 采用32位带Alpha通道的DIB位图,才能正确保留光标的透明效果,避免绘制时出现透明像素失真。
DrawIconEx的DI_COMPAT标志确保高DPI环境下光标渲染符合系统缩放规则。
内容的提问来源于stack exchange,提问作者aeberharter
相关产品推荐
相关产品推荐

