如何在窗口上设置HICON(多种尺寸的.ICO)?
我想定义 Win32 窗口的应用程序图标,例如通过使用 GCL_HICON
调用 SetClassLong
并传入图标的句柄(请参阅 SetClassLong 函数(MSDN 上)。
这很好用,但我还没有弄清楚应该如何加载图标(从 ICO 文件)以保留所有可用尺寸(例如 16x16、32x32、48x48 和全尺寸 PNG 图标)。当我通过 LoadImage
将图标文件加载到内存中以获得 HICON
时,我必须指定我想要的大小(请参阅我的 回复相关问题)。
我的 ICO 文件包含一个小尺寸图像,应用作窗口图标(标题栏的左上角),并且设计得非常清晰,但也包含应显示在 Alt-Tab 对话框中的较大变体,但是...
加载 16x16 图标会在标题栏中显示正确的图标,但是,当然,当我按 Alt-Tab 时,它会出现丑陋的拉伸版本。任务栏中显示的图标也不是很漂亮。
加载 48x48 图标时,当我按 Alt-Tab 时,会显示一个漂亮的图标,但标题栏中显示的图标很模糊,因为它是 48x48 图标的缩小版本。
有什么方法可以告诉 Windows 我的 Windows 有一个多尺寸图标吗?是否有一些我错过的明显的 API?
I would like to define the application icon of a Win32 window, e.g. through a call to SetClassLong
with GCL_HICON
and passing in a handle to an icon (see SetClassLong Function on MSDN).
This works great, but I have not figured out how I should load an icon (from an ICO file) in order to keep all available sizes (e.g. 16x16, 32x32, 48x48 and full size PNG icon). When I load the icon file through LoadImage
into memory to get the HICON
, I have to specify which size I want (see my reply to a related question).
My ICO file contains a small sized image which should be used as the window icon (top left corner of the title bar) and has been designed to be very crisp, but also larger variants which should show up in the Alt-Tab dialog, but...
Loading the 16x16 icon shows the proper icon in the title bar, but - of course - an ugly stretched version of it when I Alt-Tab. And the one showing up in the task bar is not very pretty either.
Loading the 48x48 icon shows a nice icon when I Alt-Tab, but the icon which shows up in the title bar is blurry, since it is a scaled down version of the 48x48 icon.
Is there any means of telling Windows that my Windows has a multi-sized icon? Is there some obvious API which I have missed?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
.ICO 文件中包含多个图像。但 HICON 只是这些图像中的一个。如果您使用 LR_DEFAULTSIZE,那么可能会出现一些神奇的行为,保留 .ico 文件的链接并使用其中的适当图像,但我对此表示怀疑。
如果这不起作用,那么什么也做不了。
一点背景。
当 .ico 文件包含在应用程序的资源中时,该文件将被破解,文件中的每个图像都会成为一个单独资源。文件头被修改,成为ICON资源。因此,当向 LoadIcon/LoadImage 传递 ICON 资源的资源 id 时,它实际上是向其他资源的目录传递的。它选择适合当时的请求的图像,并将其转换为 HICON。实际执行此操作的函数称为 LookupIconIdFromDirectory
这这就是为什么当您 GetIconInfo 获取 HICON 时,您仅返回单个 ICONINFO 结构。
an .ICO file has multiple images in it. but a HICON is only one of those images. if you use LR_DEFAULTSIZE, then there may be some magical behavior that preserves a link to the .ico file and uses the appropriate image from it, but I doubt it.
If this doesn't do it, then nothing will.
A little background.
When a .ico file is included in a application's resources, the file is cracked open and each image from the file becomes a separate resource. The file header is modified and it becomes the ICON resource. So when LoadIcon/LoadImage is passed the resource id of an ICON resource, it's really being passed a directory of other resources. It chooses the image that fits the request at that point in time and turns it into an HICON. The function that actually does this is called LookupIconIdFromDirectory
This is why when you GetIconInfo for an HICON, you get back only a single ICONINFO structure.
GCL_HICON 设置“大”图标,GCL_HICONSM 设置小图标(大小通常为 32x32 和 16x16,但您应该使用 GetSystemMetrics 和 SM_CXICON 和 SM_CXSMICON 来查找实际大小(对于大图标,您也可以将 LR_DEFAULTSIZE 传递给 LoadImage 0 尺寸))
GCL_HICON sets the "big" icon, GCL_HICONSM sets the small icon (Sizes are normally 32x32 and 16x16, but you should use GetSystemMetrics with SM_CXICON and SM_CXSMICON to find the actual size (For the large icon, you can also just pass LR_DEFAULTSIZE to LoadImage with 0 size))
如果
.ico
文件不包含 256x256 全尺寸 PNG 图标,当我简单地编写以下内容时,Windows 似乎很高兴:有了它,并且有一个名为
Form.ico
的图标> 放置在我的程序集的Resources
文件夹中,该文件夹以Foo
作为默认命名空间,Windows 将使用 32x32 版本的图像作为任务栏并使用 Alt 进行任务切换-Tab,以及窗口标题的 16x16 版本。因此,在将 PNG 图标与 WinForms 的
Form.Icon
一起使用时要小心...If the
.ico
file does not contain the 256x256 full size PNG icon, Windows seems to be happy when I simply write:With that in place, and an icon named
Form.ico
placed in aResources
folder of my assembly, which hasFoo
as its default namespace, Windows will be using the 32x32 version of the image for the taskbar and task switching with Alt-Tab, and the 16x16 version for the title of the window.So, beware of the PNG icon when using it with WinForms'
Form.Icon
...这个问题似乎在现代版本的 Visual Studio / Windows 中得到了解决。如果我通过 LoadIcon 加载并使用相同的多尺寸 .ico 文件在窗口类中设置小图标和普通图标,Shell 似乎能够弄清楚这一点并在 Alt-Tab / 中加载适当的图标资源管理器中的任务栏/标题栏/小/中/大甚至巨型图标。
This problem seem to be fixed in modern versions of Visual Studio / Windows. If I load via
LoadIcon
and set both small and normal icon in window class with the same multi-size .ico file, Shell seems to be able to figure this out and load appropriate icon in Alt-Tab / Taskbar / Titlebar / Small / Medium / Big and even Giant icons in Explorer.HICON 是一个单一大小的图标,但它也可以包含加载它的源信息。它必须具有此类信息,以便 DrawIconEx 调用(在标题栏/任务栏/alt-tab 对话框中)可以选择更适合的图标而不是调整大小。您可以通过调用 GetIconInfoEx 进行检查。
只是引用Raymond Chen的话:
如果你通过调用LoadIcon创建一个图标,窗口管理器会从你指定的模块加载指定的图标,但它也会记住图标的来源。 (这个讨论也适用于光标,但我只讨论图标以避免尴尬。)当您将 LR_COPYFROMRESOURCE 标志传递给 CopyImage 函数时,窗口管理器返回到原始图标源来创建您请求的副本,而不是盲目地拉伸您传入的图标的像素。
请记住,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 或资源名称。这允许您在运行时创建图标,但它也允许您创建一个“丢弃”奖金信息的图标。
现在,扔掉这些信息是一个绝望之举,因为它会阻止窗口管理器在调整图标大小时使用原始资源信息,从而导致丑陋的拉伸图标。
您甚至可能错误地丢弃了这些信息。例如,如果您的程序被要求生成一个图标,那么最好使用像 LoadImage 这样的函数加载该图标,因为它记录了奖励信息;如果调用者决定调整图标大小,则可以使用 CopyImage 函数来执行此操作,同时保持完全保真度。另一方面,如果您使用像 ExtractIcon 或 CreateIconFromResource 这样的函数,则不会有额外的信息,并且发生的任何图标拉伸最终都会看起来非常难看。
https://devblogs.microsoft.com/oldnewthing/20080820-00/? p=21173
https://devblogs.microsoft.com/oldnewthing/20080822-00/? p=21133
HICON is a single sized icon, but it can also contain source information where it was loaded from. It must have such info so DrawIconEx call (in titlebar/taskbar/alt-tab dialog) may choose better fit icon instead of resizing. You can check that by a call to GetIconInfoEx.
Just quoting Raymond Chen:
If you create an icon by calling LoadIcon, the window manager loads the specified icon from the module you specified, but it also remembers where the icon came from. (This discussion also applies, mutatis mutandis to cursors, but I will just talk about icons to avoid awkardness.) When you pass the LR_COPYFROMRESOURCE flag to the CopyImage function, the window manager goes back to the original icon source to create the copy you requested rather than blindly stretching the pixels of the icon you passed in.
Remember that an ICO file represents not just one icon but rather a collection of icons (known as an “icon group”), each at a different size or color depth. The intent is that each icon in the icon group depicts the same underlying image, just tuned for particular settings. (Now, mind you, there is no enforcement of this intent. If you make your 16×16 image a smiling-face and your 32×32 image a barking dog, well, then that’s your problem.) For example, a single ICO file might contain a 16×16 image, a 32×32 image, and a 48×48 image. If somebody asks for the icon at one of those sizes, then the corresponding image is used. On the other hand, if somebody asks for, say, the 24×24 image, the window manager will take the 32×32 image and stretch it to the necessary size.
You can recover this “hidden source information” with the GetIconInfoEx function (new for Windows Vista). If the icon was loaded by ordinal, then the szResName is an empty string and the ordinal is placed in the wResID member. If the icon was loaded by name, then wResID is zero and szResName contains the resource name.
We’ve seen that icons and cursors know where they came from, and the window manager uses this information when you ask it to change the size of an icon. But not all icons carry this information, only icons created by passing a HINSTANCE and a resource name.
You can use this to your advantage if you want to destroy the module and resource information associated with an icon. For example, the CreateIconIndirect function creates an icon from raw bitmap information without reference to an HINSTANCE or a resource name. This allows you to create icons at runtime, but it also allows you to create an icon that “throws away” the bonus information.
Now, throwing away this information is a desperation move, because it prevents the window manager from using the original resource information when resizing an icon, resulting in ugly stretched icons.
You might even be throwing this information away by mistake. For example, if your program is asked to produce an icon, it’s best if you load the icon with a function like LoadImage because that records the bonus information; if the caller decides to resize the icon, it can do so with the CopyImage function while retaining full fidelity. On the other hand, if you use a function like ExtractIcon or CreateIconFromResource, that will not have the bonus information, and any icon stretching that takes place will end up looking pretty ugly.
https://devblogs.microsoft.com/oldnewthing/20080820-00/?p=21173
https://devblogs.microsoft.com/oldnewthing/20080822-00/?p=21133