5

i'm not interested in changing the actual icon in the EXE that shows up in windows explorer, but just the icon that shows up in the top left of the console window. Already i set the icon in the visual studio project and i'm getting it nicely in windows explorer, and also that icon is showing up in the console window, i just want to be able to change it in the console windows at runtime. I.e lets say i wanted to put an icon that shows there are new emails or something.

klumsy
  • 4,081
  • 5
  • 32
  • 42

2 Answers2

7

Following on Leniel's answer, I wanted to do this in a C# winforms app.. The link he posted to is C++.. Essentially here is the code you need if you want to do this in C#:

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool SetConsoleIcon(IntPtr hIcon);

and call it like this:

public static void SetConsoleIcon(System.Drawing.Icon icon)
        {
            SetConsoleIcon(icon.Handle);
        }

I have a ConsoleWindow class I use in a winforms app that gives the the ability to show a console window aswell. Here is the full class def

 class ConsoleWindow
    {
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool AllocConsole();

        [DllImport("kernel32.dll")]
        static extern bool AttachConsole(int dwProcessId);
        private const int ATTACH_PARENT_PROCESS = -1;

        [DllImport("kernel32.dll")]
        static extern IntPtr GetConsoleWindow();

        [DllImport("user32.dll")]
        static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern bool SetWindowText(IntPtr hwnd, String lpString);

        [DllImport("user32.dll")]
        static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);

        [DllImport("user32.dll")]
        static extern bool EnableMenuItem(IntPtr hMenu, uint uIDEnableItem, uint uEnable);

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool SetConsoleIcon(IntPtr hIcon);

        const int SW_HIDE = 0;
        const int SW_SHOW = 5;

        const int SC_CLOSE = 0xF060;
        const int MF_GRAYED = 1;

        public static void AttachConsoleWindow()
        {
            // redirect console output to parent process;
            // must be before any calls to Console.WriteLine()
            AttachConsole(ATTACH_PARENT_PROCESS);
        }

        public static void ShowConsoleWindow()
        {
            var handle = GetConsoleWindow();

            if (handle == IntPtr.Zero)
            {
                AllocConsole();
            }
            else
            {
                ShowWindow(handle, SW_SHOW);
            }
        }

        public static void HideConsoleWindow()
        {
            var handle = GetConsoleWindow();

            ShowWindow(handle, SW_HIDE);
        }

        public static void SetWindowText(string text)
        {
            var handle = GetConsoleWindow();

            SetWindowText(handle, text);
        }

        public static void DisableCloseButton()
        {
            var handle = GetConsoleWindow();

            var hmenu = GetSystemMenu(handle, false);

            EnableMenuItem(hmenu, SC_CLOSE, MF_GRAYED);
        }

        public static void SetConsoleIcon(System.Drawing.Icon icon)
        {
            SetConsoleIcon(icon.Handle);
        }
    }
Ocean Airdrop
  • 2,793
  • 1
  • 26
  • 31
  • Does this work on Win7? Can I use it to change the icon in the taskbar of say firefox? – Noitidart Jul 04 '14 at 00:29
  • Hi Noitidart. Erm, yes I guess so. You would need to pinvoke a couple more windows api's. Take a look at EnumDesktopWindows and GetWindowText. http://www.pinvoke.net/default.aspx/user32/EnumDesktopWindows.html There is some sample code on that page that even calls through to GetWindowText so it looks like all the heavy lifting has been done for you.. On each iteration of the desktop windows you could call GetWindowText to get the title of the window.. When you find the window you are interested in, once you have its window handle you could use that to change the icon of the window. – Ocean Airdrop Jan 24 '15 at 09:09
  • Thanks @adrian :) I tried doing this but Firefox isn't console right? I'm a noob at WinAPI still trying to do this :P Or would pinvoke'ing it get around that problem? – Noitidart Jan 24 '15 at 14:16
  • 1
    Hi Noitidart. Yes your right. You would need to call the API SendMessage. e.g: SendMessage(yourwnd, WM_SETICON, ICON_SMALL, hIcon) to change a GUI app icon. It looks like this StackOverflow post has your answer: http://stackoverflow.com/questions/9199523/is-there-a-way-to-have-my-app-push-its-icon-to-other-apps – Ocean Airdrop Jan 25 '15 at 10:57
  • Thanks very much @adrian for go so far as finding a solution for me! :) – Noitidart Jan 25 '15 at 11:03
1

Since the comment referred to in Josh's answer seems to have gone away, here is the C++ code to do it:

HMODULE hKernel32 = ::LoadLibrary(_T("kernel32.dll"));
typedef BOOL (_stdcall * SetConsoleIconFunc)(HICON);
SetConsoleIconFunc setConsoleIcon
    = (SetConsoleIconFunc)::GetProcAddress(hKernel32, "SetConsoleIcon");
if (setConsoleIcon != NULL)
    setConsoleIcon(m_hIcon);
::FreeLibrary(hKernel32);
ulatekh
  • 1,311
  • 1
  • 14
  • 19