Question

In Visual Studio I generated a plain old Win32 application and stripped all the resources and generated code so that my application consists of this:

#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 );
}

When I run the application, this is what I see:

screenshot

So the question is can I change that default application icon in the taskbar? If so, what code needs to be added to do it?

Edit:

Here's what I did, and this kind of works but it isn't ideal. The new icon shows up alright, but the taskbar preview window in Vista doesn't work and the system menu doesn't work so I'm just going to leave it alone for now.

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 );
}
Was it helpful?

Solution

The icon shown on the task bar is taken from the window itself. If the only window is the standard Windows MesssageBox, then you'll get some sort of OS default. You have to create your own window and give it an icon, then Windows will use that.

OTHER TIPS

This looks like just sample code. If the real code is a non-console Windows application, you can do this:

Give your application's main window a task bar icon by calling SetIcon(). Then when you call MessageBox(), set the first parameter to the HWND of your application's main window.

For this particular case (one MessageBox call in the WinMain function) you could hook the message box dialog creation and set an icon there. Like this:

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);
}

Where IDI_MYICON is the ID of your icon resource.

WNDCLASSEX wndclass;

wndclass.cbSize        = sizeof(wndclass);
// ..
wndclass.hIconSm       = ExtractIconEx( ... );
RegisterClassEx(&wndclass);

HWDN wnd = CreateWindow(...)

Why not just add an icon resource to the EXE? I'm pretty sure Windows will try that before falling back to the "generic" icons.

Create a form but never show it then assign it an icon and use that as the parent of your message box.

This hides the icon:

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

This will create an icon:

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");
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top