HICON 是一个单一大小的图标,但它也可以包含源信息,以便知道从哪里加载。它必须具有这样的信息,以便 DrawIconEx 调用(在标题栏/任务栏/alt-tab 对话框中)可以选择更合适的图标而不是调整大小。您可以通过调用 GetIconInfoEx 来检查。
引用 Raymond Chen 的话:
如果您通过调用 LoadIcon 创建图标,则窗口管理器会从指定的模块中加载指定的图标,但它还记得图标来自何处。(这个讨论同样适用于光标,但我只谈论图标,以避免尴尬。)当您向 CopyImage 函数传递 LR_COPYFROMRESOURCE 标志时,窗口管理器会返回到原始图标源以创建您请求的副本,而不是盲目地拉伸您传入的图标像素。
请记住,ICO文件不仅代表一个图标,而是一组图标(称为“图标组”),每个图标具有不同的大小或颜色深度。意图是图标组中的每个图标都描绘相同的基础图像,只是针对特定设置进行了调整。(现在,请注意,没有强制执行此意图。如果您将16×16图像设为微笑脸,将32×32图像设为狗叫声,那么这就是您的问题。)例如,单个ICO文件可能包含16×16图像、32×32图像和48×48图像。如果有人要求某个尺寸的图标,则使用相应的图像。另一方面,如果有人要求24×24图像,则窗口管理器将取出32×32图像并将其拉伸到必要的大小。
您可以使用GetIconInfoEx函数(适用于Windows Vista)恢复此“隐藏的源信息”。如果按序号加载图标,则szResName为空字符串,并将序号放置在wResID成员中。如果按名称加载图标,则wResID为零,szResName包含资源名称。
我们已经知道,图标和光标知道它们来自何处,窗口管理器在您要求更改图标大小时使用此信息。但并非所有图标都携带此信息,只有通过传递 HINSTANCE 和资源名称创建的图标才能携带。
如果您想销毁与图标关联的模块和资源信息,可以利用这一点。例如,CreateIconIndirect 函数从原始位图信息创建图标,不参考 HINSTANCE 或资源名称。这允许您在运行时创建图标,但也允许您创建一个“丢弃”额外信息的图标。
HICON CopyIconWithoutResourceInfo(HICON hicoSrc)
{
ICONINFO ii;
HICON hico = NULL;
if (GetIconInfo(hicoSrc, &ii)) {
hico = CreateIconIndirect(&ii);
if (ii.hbmMask) DeleteObject(ii.hbmMask);
if (ii.hbmColor) DeleteObject(ii.hbmColor);
}
return hico;
}
现在,丢弃这些信息是一种绝望的举动,因为它会阻止窗口管理器在调整图标大小时使用原始资源信息,导致图标被拉伸变形。
你甚至可能会错误地丢弃这些信息。例如,如果你的程序被要求生成一个图标,最好使用像LoadImage这样的函数加载图标,因为它记录了额外的信息;如果调用者决定调整图标大小,可以使用CopyImage函数来保持完全的保真度。另一方面,如果你使用像ExtractIcon或CreateIconFromResource这样的函数,那么它将没有额外的信息,任何图标拉伸都会变得非常丑陋。
https://devblogs.microsoft.com/oldnewthing/20080820-00/?p=21173
https://devblogs.microsoft.com/oldnewthing/20080822-00/?p=21133
SetClassLongPtr
来应用正确的大小到大和小。 - Noitidart