设置应用程序图标的问题

时间:2009-04-01 18:59:18

标签: c++ visual-studio-2008 icons

(我正在使用Visual Studio 2008,但我记得在旧版本中也存在类似的问题。)

我尝试了几种不同的方法(其中许多方法在this other question中提及),但我仍有一些奇怪的问题:

  1. 当包含图标作为资源时,它会立即显示为可执行文件的图标,但是为了显示在任务栏上的图标,我必须重新启动计算机。在那之前,它继续显示为以前的图标。清理解决方案,重新启动VS,没有任何影响。这不是一个非常大的问题,因为它不会影响已发布的exe,但是知道它将旧图标缓存在哪里以及如何摆脱它会很好。

  2. 无论我做什么,alt-tabbing时显示的图标是默认的应用程序图标(方形和白色以及通用)。这包括在可执行文件中嵌入图标,以及使用ICON_BIG设置WM_SETICON

  3. 至于第二个问题,我的代码看起来像:

       hIcon = (HICON)(
          LoadImage( NULL, szFilename, IMAGE_ICON, 32, 32, LR_LOADFROMFILE ) );
       if( hIcon )
          SendMessage( hWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon );
    

    然而,在发送WM_SETICON后,GetLastError()返回6,“句柄无效。”。 hWnd是一个有效的窗口句柄,hIcon似乎是一个有效的图标句柄。我已经尝试搜索WM_SETICON可能导致该错误的原因,并且至少要找出它认为无效的WHICH句柄,但还没有运气。我在调用SendMessage()之前立即清除了错误代码,因此必须在处理消息时将其设置在某处。

    我尝试了另一种方法,从exe本身加载图标,其中资源的ID为101(这是第一个也是唯一包含的资源):

       hIcon = (HICON)(
          LoadImage( GetModuleHandle( NULL ), MAKEINTRESOURCE( 101 ),
          IMAGE_ICON, 48, 48, 0 ) );
       if( hIcon )
          SendMessage( hWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon );
    

    ......但同样的事情发生了;致电SendMessage()后,GetLastError()会提供相同的错误状态。

    我尝试了不同的尺寸(例如48x48,所有这些尺寸都出现在图标文件中),但没有不同的效果。我知道这肯定是找到并加载图像,因为如果我指定一个不存在的大小或无效的资源ID或错误的文件名(取决于我如何加载它),它会在SendMessage()之前很久就失败

    奇怪的是,如果我指定ICON_SMALL而不是ICON_BIG,则调用成功且没有错误状态,但是从the docs,我需要使用ICON_BIG来设置图标在alt-tabbing时使用。另外,如果我使用ICON_BIG但加载了16x16图标,则我没有错误状态,但没有任何变化。

    有关可能导致WM_SETICON失败的原因的任何想法?我发布的任何代码都有严重错误(除了格式化/样式/投射问题,因为它简化为基础)?

5 个答案:

答案 0 :(得分:3)

我重新审视了这一点,看看能不能提出我的问题。我只是通过将其嵌入可执行文件中,无法将应用程序的图标显示在alt-tab列表中;它将显示在任务栏中,作为资源管理器中的文件图标,其他地方就好了。

我想我会尝试更简单的手动设置图标,而是使用LoadIcon()代替,如下面的代码所示:

HICON hIcon = LoadIcon( GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON1) );
if( hIcon )
{
   SendMessage( GetHandle(), WM_SETICON, ICON_BIG, (LPARAM)hIcon );
   DestroyIcon( hIcon );
}
// ... Same for ICON_SMALL

这似乎已经成功了。我真的不知道为什么,但到目前为止,它是唯一有效的变化。这真的不是我应该花费更多时间的问题,所以我会选择这个。

答案 1 :(得分:2)

我使用单个.ico文件,多个分辨率16x16,32x32,48x48,96x96没有问题,作为应用程序图标。然后Windows会选择合适的尺寸。

Windows shell有一个icon cache,有一个trick可以重新启动它,无需重启或从当前会话注销,或者从任务管理器中杀死explorer.exe。

答案 2 :(得分:2)

好的,这对我有用:

HICON hIconSmall =(HICON)LoadImage(handleToYourApplicationInstance, MAKEINTRESOURCE(IDI_ICON1), IMAGE_ICON,16, 16, 0);

HICON hIconLarge =(HICON)LoadImage(handleToYourApplicationInstance, MAKEINTRESOURCE(IDI_ICON1), IMAGE_ICON,256, 256, 0); // Big for task bar, small loaded otherwise.

SendMessage(yourWindowHandle, WM_SETICON, ICON_SMALL, (LPARAM)hIconSmall) ;

SendMessage(yourWindowHandle, WM_SETICON, ICON_BIG, (LPARAM)hIconLarge) ;

答案 3 :(得分:0)

如果找到了我的解决方案。我创建了一个不可见的CFrameWnd应用程序窗口,然后是一些其他主窗口(对话框窗口)。神奇的未记录规则是:您必须更改第一个创建的CFrameWnd中的大图标。虽然每个窗口都保留了自己的ICON_BIG实例,但它不会使用它们。因此,似乎无法在一个应用程序中为不同的窗口显示不同的任务栏图标。

答案 4 :(得分:0)

对于任何遇到同样困难的人,如果要更改ICON_BIG,必须首先使用ICON_SMALL发送WM_SETICON,然后继续进行ICON_BIG。

例如:

SetLastError(0);
SendMessage(windowHandle, WM_SETICON, ICON_SMALL, (LPARAM)iconsmallHandle);
[do error handling]
SetLastError(0);
SendMessage(windowHandle, WM_SETICON, ICON_BIG, (LPARAM)iconbigHandle);
[do error handling]

您需要在第一个SendMessage之后使用SetLastError来清除任何返回的错误。

如果您只是设置ICON_SMALL,则可以忽略ICON_BIG。无论出于何种原因,无论出于何种原因,在尝试更改ICON_BIG之前,无论该图标是否需要更改,都必须设置ICON_SMALL,否则您将始终收到错误代码0x6(句柄无效)。