windows 如何在窗口上设置HICON(.ICO有多种大小)?

csga3l58  于 2023-06-07  发布在  Windows
关注(0)|答案(5)|浏览(909)

我想定义一个Win32窗口的应用程序图标,例如。通过使用GCL_HICON调用SetClassLong并传入一个图标的句柄(参见MSDN上的SetClassLong Function)。
这工作得很好,但我还没有弄清楚我应该如何加载图标(从ICO文件),以保持所有可用的大小(例如:16 x16、32 x32、48 x48和全尺寸PNG图标)。当我通过LoadImage将图标文件加载到内存中以获得HICON时,我必须指定所需的大小(请参阅我对相关问题的回复)。
我的ICO文件包含一个小尺寸的图像,应该用作窗口图标(标题栏的左上角),并且设计得非常清晰,但也有较大的变体,应该显示在Alt-Tab对话框中,但是...
1.加载16 x16图标会在标题栏中显示正确的图标,但是-当然-当我Alt-Tab时,它会出现一个丑陋的拉伸版本。而且任务栏里出现的那个也不是很漂亮。
1.加载48 x48图标时显示一个很好的图标,但在标题栏中显示的图标是模糊的,因为它是一个缩小版本的48 x48图标。
有没有什么方法可以告诉Windows我的Windows有一个多大小的图标?是否有一些明显的API我错过了?

rqenqsqc

rqenqsqc1#

.ICO文件中包含多个图像。但HICON只是其中之一如果您使用LR_DEFAULTSIZE,那么可能会有一些神奇的行为,保留到.ico文件的链接并使用其中的适当图像,但我对此表示怀疑。
如果这都不行,那就没办法了。

HICON hicon = LoadImage(NULL, "filename.ico", IMAGE_ICON, 
                        0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE);

一点背景。
当应用程序的资源中包含.ico文件时,该文件将被破解,文件中的每个图像都将成为一个 * 单独的 * 资源。修改文件头,使其成为ICON资源。因此,当LoadIcon/LoadImage被传递ICON资源的资源ID时,它实际上被传递了其他资源的目录。它选择适合请求的图像 * 在那个时间点 * 并将其转换为HICON。实际执行此操作的函数称为LookupIconIdFromDirectory
这就是为什么当你GetIconInfo一个HICON,你得到的只有一个单一的ICONINFO结构。

typedef struct _ICONINFO {
    BOOL fIcon;
    DWORD xHotspot;
    DWORD yHotspot;
    HBITMAP hbmMask;
    HBITMAP hbmColor;
} ICONINFO;
h5qlskok

h5qlskok2#

GCL_HICON设置“大”图标,GCL_HICONSM设置小图标(大小通常为32x32和16x16,但您应该使用GetSystemMetrics和SM_CXICON和SM_CXSMICON来查找实际大小(对于大图标,您也可以将LR_DEFAULTSIZE传递给LoadImage,大小为0))

wljmcqd8

wljmcqd83#

如果.ico文件不包含256 x256全尺寸PNG图标,Windows似乎很高兴,当我简单地写:

var assembly = typeof (Xyz).Assembly;
var stream   = assembly.GetManifestResourceStream ("Foo.Resources.Form.ico");
var icon     = new System.Drawing.Icon (stream);

form.Icon = icon;

有了这个,并且在我的程序集的Resources文件夹中放置了一个名为Form.ico的图标,该文件夹的默认名称空间为Foo,Windows将使用32 x32版本的图像用于任务栏和Alt-Tab任务切换,并使用16 x16版本的图像用于窗口标题。
所以,在使用WinForms的Form.Icon时要小心PNG图标。

dnph8jn4

dnph8jn44#

这个问题似乎在Visual Studio / Windows的现代版本中得到了解决。如果我通过LoadIcon加载,并在窗口类中设置小图标和普通图标,使用相同的多大小.ico文件,Shell似乎能够解决这个问题,并在Alt-Tab / Taskbar / Titlebar / Small / Medium / Big中加载适当的图标,甚至在Explorer中加载巨型图标。

yvfmudvl

yvfmudvl5#

HICON是一个单一大小的图标,但它也可以包含加载源信息。它必须有这样的信息,以便DrawIconEx调用(在标题栏/任务栏/alt-tab对话框中)可以选择更适合的图标,而不是调整大小。您可以通过调用GetIconInfoEx进行检查。

引用Raymond Chen的话:
如果您通过调用LoadIcon创建图标,窗口管理器会从您指定的模块中加载指定的图标,但它也会记住图标的来源。(此讨论也适用于光标,但我只讨论图标以避免awkardness。)当您将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或资源名称。这允许您在运行时创建图标,但它也允许您创建一个“扔掉”奖金信息的图标。

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功能来这样做,同时保持完全的保真度。另一方面,如果你使用像ExtractIconCreateIconFromResource这样的函数,那将没有奖励信息,并且发生的任何图标拉伸最终都会看起来非常丑陋。
https://devblogs.microsoft.com/oldnewthing/20080820-00/?p=21173https://devblogs.microsoft.com/oldnewthing/20080822-00/?p=21133

相关问题