【问题标题】:How to explicitly set taskbar icon?如何显式设置任务栏图标?
【发布时间】:2009-06-18 17:36:21
【问题描述】:

在 Visual Studio 中,我生成了一个普通的旧 Win32 应用程序并剥离了所有资源和生成的代码,因此我的应用程序包含以下内容:

#include "stdafx.h"
#include "IcoTest.h"

int APIENTRY _tWinMain(HINSTANCE hInstance,
                 HINSTANCE hPrevInstance,
                 LPTSTR    lpCmdLine,
                 int       nCmdShow)
{
    ::MessageBox( NULL, L"Testing", L"Test", MB_OK );
}

当我运行应用程序时,我看到的是这样的:

所以问题是我可以更改任务栏中的默认应用程序图标吗?如果是这样,需要添加什么代码来做到这一点?

编辑:

这就是我所做的,并且这种方法有效,但并不理想。新图标显示正常,但是 Vista 中的任务栏预览窗口不起作用,系统菜单也不起作用,所以我暂时不理会它。

HWND CreateDummyWindow(HINSTANCE hInstance, int iconId, LPCTSTR taskbarTitle)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style          = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc    = DefWindowProc;
wcex.cbClsExtra     = 0;
wcex.cbWndExtra     = 0;
wcex.hInstance      = hInstance;
wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(iconId));
wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground  = 0;
wcex.lpszMenuName   = 0;
wcex.lpszClassName  = taskbarTitle,
wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(iconId));
ATOM atom = RegisterClassEx(&wcex);
HWND wnd = ::CreateWindow( 
    wcex.lpszClassName, taskbarTitle, WS_ICONIC | WS_DISABLED,
  -1000, -1000, 1, 1, NULL, NULL, hInstance, NULL);
return wnd;
}

int APIENTRY _tWinMain(HINSTANCE hInstance,
                 HINSTANCE hPrevInstance,
                 LPTSTR    lpCmdLine,
                 int       nCmdShow)
{
    HWND wnd = CreateDummyWindow(hInstance, IDI_ICON1, _T("Test") );
    ::MessageBox( wnd, _T("Testing"), _T("Test"), MB_OK );
    ::DestroyWindow( wnd );
}

【问题讨论】:

    标签: c++ winapi taskbar


    【解决方案1】:

    任务栏上显示的图标取自窗口本身。如果唯一的窗口是标准的 Windows MessageBox,那么您将获得某种操作系统默认值。你必须创建自己的窗口并给它一个图标,然后 Windows 会使用它。

    【讨论】:

    • 您必须进行测试。我怀疑只要消息泵在主线程上,它就会 - 只是不要让表单在位置 -10000、-10000 或类似位置不可见。
    【解决方案2】:

    这看起来只是示例代码。如果实际代码是非控制台 Windows 应用程序,您可以这样做:

    通过调用SetIcon() 为您的应用程序的主窗口提供一个任务栏图标。然后在调用 MessageBox() 时,将第一个参数设置为应用程序主窗口的 HWND。

    【讨论】:

    • 其实我是故意这样制作样本的。我有一个显示窗口的 COM 对象。我的应用程序实际上并没有直接创建任何窗口。 com 对象窗口的任务栏中的图标很古怪。
    • 虽然,您的回答让我更加关注 SetIcon,结果我可以从 COM 对象获取窗口句柄并执行 ::SendMessage(wnd, WM_SETICON, FALSE, (LPARAM)hIcon) ;这行得通!
    • 不错。我知道 COM 创建了一个不可见的窗口,但我不知道你可以这样使用它。感谢您的更新。
    【解决方案3】:

    对于这种特殊情况(WinMain 函数中的一个MessageBox 调用),您可以挂钩消息框对话框的创建并在那里设置一个图标。像这样:

    HHOOK g_hMsgBoxHook;
    HINSTANCE g_hInstance;
    
    LRESULT CALLBACK CallWndProc(int nCode, WPARAM wParam, LPARAM lParam)
    {
        if(nCode == HC_ACTION)
        {
            CWPSTRUCT* pcwp = (CWPSTRUCT*)lParam;
    
            if(pcwp->message == WM_INITDIALOG)
            {
                HICON hIcon = NULL;
                HICON hIconBig = NULL;
    
                // Small icon.
                hIcon = (HICON)LoadImage(g_hInstance,
                               MAKEINTRESOURCE(IDI_MYICON),
                               IMAGE_ICON,
                               GetSystemMetrics(SM_CXSMICON),
                               GetSystemMetrics(SM_CYSMICON),
                               0);
                if(hIcon)
                {
                    SendMessage(pcwp->hwnd, WM_SETICON,
                        ICON_SMALL, (LPARAM)hIcon);
                }
    
                // Big icon.
                hIconBig = (HICON)LoadImage(g_hInstance,
                               MAKEINTRESOURCE(IDI_MYICON),
                               IMAGE_ICON,
                               GetSystemMetrics(SM_CXICON),
                               GetSystemMetrics(SM_CXICON),
                               0);
                if(hIconBig)
                {
                    SendMessage(pcwp->hwnd, WM_SETICON,
                        ICON_BIG, (LPARAM)hIconBig);
                }
            }
        }
    
        return CallNextHookEx(g_hMsgBoxHook, nCode, wParam, lParam); 
    }
    
    int CALLBACK wWinMain(
      HINSTANCE hInstance,
      HINSTANCE hPrevInstance,
      LPWSTR lpCmdLine,
      int nCmdShow
    )
    {
        g_hInstance = hInstance;
        g_hMsgBoxHook = SetWindowsHookEx(WH_CALLWNDPROC,
            CallWndProc, NULL, GetCurrentThreadId());
    
        MessageBoxW(NULL, L"Testing", L"Test", MB_OK);
    
        // ...
    
        UnhookWindowsHookEx(g_hMsgBoxHook);
    }
    

    IDI_MYICON 是您的图标资源的 ID。

    【讨论】:

      【解决方案4】:
      WNDCLASSEX wndclass;
      
      wndclass.cbSize        = sizeof(wndclass);
      // ..
      wndclass.hIconSm       = ExtractIconEx( ... );
      RegisterClassEx(&wndclass);
      
      HWDN wnd = CreateWindow(...)
      

      【讨论】:

        【解决方案5】:

        为什么不向 EXE 中添加图标资源?我很确定 Windows 会在回退到“通用”图标之前尝试这样做。

        【讨论】:

        • 我试过了。是否有一些特殊的方法来添加图标,以便您的建议可以工作?我无法让它工作。
        【解决方案6】:

        创建一个表单但从不显示它,然后为其分配一个图标并将其用作消息框的父级。

        这会隐藏图标:

        using (var f = new Form())
        {
            MessageBox.Show(f,"my message");
        }
        

        这将创建一个图标:

        using (var f = new Form())
        {
            f.Icon = Resources.IconUpload;
            f.Location=new Point(-1000,-1000);
            f.StartPosition = FormStartPosition.Manual;
            f.Show();
            MessageBox.Show(f,"my message");
        }
        

        【讨论】:

        • 这既不是 C++ 也不是针对 Windows API。
        猜你喜欢
        • 2012-09-16
        • 2010-09-18
        • 1970-01-01
        • 2011-05-02
        • 2012-09-08
        • 1970-01-01
        • 1970-01-01
        • 2018-06-12
        相关资源
        最近更新 更多