加载光标和混合 DPI 多显示器

问题描述 投票:0回答:3

当使用

LoadCursor
函数从资源加载光标时,生成的
HCURSOR
可以在不同的显示器上使用,并且始终以正确的大小显示。

即:通常:

  • 在 96 dpi 显示器上使用 32x32 资源,
  • 在 192 dpi 显示器上使用 64x64 资源。

但是,当以编程方式从内存创建光标时(例如使用

LookupIconIdFromDirectoryEx
CreateIconFromResourceEx
),生成的光标具有固定的分辨率。这意味着它在混合 DPI 多显示器设置中的至少一台显示器上显示为错误的尺寸。

我还检查了

LoadCursorFromFile
,它也提供了像
LoadCursor
这样的动态分辨率行为。

有没有一种方法可以以编程方式创建一个光标,根据它显示的显示器动态切换?让加载了

LoadCursor
的光标以不同的方式工作,幕后发生了什么魔法?

windows winapi hidpi
3个回答
3
投票

经过大量实验,我终于发现,如果使用

scaleWithDpi
选项,WPF 可以从资源和内存流加载游标并获得正确的 DPI 行为:

public Cursor(Stream cursorStream, bool scaleWithDpi)

查看参考源,它最终出现在函数

LoadFromStream
中,该函数通过将流写入临时文件并从文件加载来加载流。 查看来源

总结一下:

  • 获取像这样的动态 DPI 光标的唯一方法似乎是使用 Win32 本机资源加载函数并从文件加载。您似乎无法通过这种行为直接从内存加载光标。
  • 此行为的“动态 dpi”部分似乎与传递给
    LR_DEFAULTSIZE
    函数的
    LoadImage
    标志有关。

0
投票

使用 LoadCursor 加载的光标以不同方式工作的幕后发生了什么魔法?

提供

hInst/MAKEINTRESOURCE(resId)

LR_LOADFROMFILE
 标志的 
LoadImage
LoadCursorFromFile API 确实在返回的
HCURSOR
/
HICON
中保存附加信息。

DrawIconEx

DI_DEFAULTSIZE
CopyImage
LR_COPYFROMRESOURCE
,也许其他 API 正在使用此信息从资源源获取最适合当前监视器/窗口的 DPI 相关大小的图标图像。

可以使用自 Windows Vista 起可用的 szModName 结构的

wResID
/
szResName
/
ICONINFOEX
成员中的
GetIconInfoEx
手动获取此图标源信息。

CreateIconFromResourceEx 不会设置此信息,因为它只接收指向图标/光标位的内存指针。在这种情况下,简单的图像缩放应用于

DrawIconEx
调用。

除了使用文件/exe/dll 的加载之外,似乎没有其他方法可以使用这种 DPI 感知绘制机制。

Raymond Chen 博客中有关此主题的一些信息:

PS:作为解决方法我认为可以处理 WM_SETCURSOR 窗口消息,计算窗口的 DPI 感知光标大小(使用

wParam
GetDpiForWindowGetSystemMetricsForDpi
SM_CXCURSOR
/
 SM_CYCURSOR
)加载相应的
HCURSOR
并用它调用SetCursor函数。

Windows 10 中还有一个新的用户光标大小设置也可能会被考虑在内。它保存在

CursorBaseSize
注册表下的
HKEY_CURRENT_USER\Control Panel\Cursors
中。 这是一些 Qt 代码,它处理它并返回正确的光标大小。


0
投票

从 Windows 10 1607 开始有一个新的 API 可能会有所帮助:SetThreadCursorCreationScaling

© www.soinside.com 2019 - 2024. All rights reserved.