5

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 );
}
Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Skrymsli
  • 5,173
  • 7
  • 34
  • 36

6 Answers6

3

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.

Paul Alexander
  • 31,970
  • 14
  • 96
  • 151
  • That you'd have to test. I suspect that it would as long as the message pump is on the main thread - just don't make the form invisible just at location -10000,-10000 or something like that. – Paul Alexander Jun 18 '09 at 17:53
3

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.

John Dibling
  • 99,718
  • 31
  • 186
  • 324
  • Actually, I made the sample this way on purpose. I have a COM object that displays a window. My application doesn't actually create any windows directly. The icon in the taskbar from the com object's window is wacky. – Skrymsli Jun 18 '09 at 19:19
  • Although, your answer made me look harder at SetIcon and it turns out that I can get the window handle from the COM object and do ::SendMessage(wnd, WM_SETICON, FALSE, (LPARAM)hIcon); and that works! – Skrymsli Jun 18 '09 at 20:33
  • Nice. I knew COM created an invisible window, but I did not know you could use it in this way. Thanks for the update. – John Dibling Jun 18 '09 at 21:11
2

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.

Alex Blekhman
  • 3,875
  • 2
  • 19
  • 18
0
WNDCLASSEX wndclass;

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

HWDN wnd = CreateWindow(...)
rtn
  • 127,556
  • 20
  • 111
  • 121
0

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.

ChrisV
  • 3,363
  • 16
  • 19
  • I tried that. Is there some particular way to add the icon so that what you are suggesting will work? I couldn't get it to work. – Skrymsli Jun 18 '09 at 19:20
-3

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");
}
Emad
  • 4,110
  • 5
  • 30
  • 35