Is there a way to make a console window flash in the task bar programmatically
Asked Answered
H

4

17

Basically I made console app that performs some task that takes a few minutes. I'd like to have it flash in the taskbar to let me know when it's done doing its thing.

Hoar answered 27/5, 2010 at 17:11 Comment(1)
Here's a solution that may be of some help: #73662Anticoagulant
E
22

Using the answer that @Zack posted and another one to find the handle of a console app I came up with this and it works great.

class Program
{
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool FlashWindowEx(ref FLASHWINFO pwfi);

    [StructLayout(LayoutKind.Sequential)]
    public struct FLASHWINFO
    {
        public UInt32 cbSize;
        public IntPtr hwnd;
        public UInt32 dwFlags;
        public UInt32 uCount;
        public Int32 dwTimeout;
    }

    public const UInt32 FLASHW_ALL = 3;

    static void Main(string[] args)
    {
        Console.WriteLine("Flashing NOW");
        FlashWindow(Process.GetCurrentProcess().MainWindowHandle);
        Console.WriteLine("Press any key to continue");
        Console.ReadKey();
    }

    private static void FlashWindow(IntPtr hWnd)
    {
        FLASHWINFO fInfo = new FLASHWINFO();

        fInfo.cbSize = Convert.ToUInt32(Marshal.SizeOf(fInfo));
        fInfo.hwnd = hWnd;
        fInfo.dwFlags = FLASHW_ALL;
        fInfo.uCount = UInt32.MaxValue;
        fInfo.dwTimeout = 0;

        FlashWindowEx(ref fInfo);
    }
}
Exude answered 27/5, 2010 at 17:35 Comment(2)
Looks like 3 different ways of getting the window handle but I like yours best since it doesn't PInvoke to do it so accepting it.Hoar
Wow. I used the P/Invoke method to get the Window Handle of the console window, lol. msdn.microsoft.com/en-us/library/ms683175(VS.85).aspxAnticoagulant
H
6

Combining the answer in the question linked in @Zack's comment and getting the hwnd of a console window using this I was able to get it working. This is the class I created:

public static class FlashWindow
{
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool FlashWindowEx(ref FLASHWINFO pwfi);
    [DllImport("kernel32.dll")]
    static extern IntPtr GetConsoleWindow();

    [StructLayout(LayoutKind.Sequential)]
    public struct FLASHWINFO
    {
        public UInt32 cbSize;
        public IntPtr hwnd;
        public UInt32 dwFlags;
        public UInt32 uCount;
        public UInt32 dwTimeout;
    }

    public const UInt32 FLASHW_ALL = 3;

    public static void Flash()
    {
        FLASHWINFO fInfo = new FLASHWINFO();

        fInfo.cbSize = Convert.ToUInt32(Marshal.SizeOf(fInfo));
        fInfo.hwnd = GetConsoleWindow();
        fInfo.dwFlags = FLASHW_ALL;
        fInfo.uCount = UInt32.MaxValue;
        fInfo.dwTimeout = 0;

        FlashWindowEx(ref fInfo);
    }
}

It doesn't ever stop flashing until it's closed but that wasn't important for my purposes.

Hoar answered 27/5, 2010 at 17:36 Comment(2)
I could not find Process.GetCurrentProcess().MainWindowHandle , maybe because im using .NET Core, but this worked fine.Kendrick
GetConsoleWindow() seems to be the most correct way to get console window, since Windows uses separate process to host console window, and Process.GetCurrentProcess().MainWindowHandle doesn't work since the window doesn't belong to application process.Stan
D
5

I read that it wasn't possible to get the window handle of a console window through any direct means, but it seems to be pretty simple in .NET actually. So, it's pretty much the same as this question:

class Program
{
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool FlashWindowEx(ref FLASHWINFO pwfi);

    [StructLayout(LayoutKind.Sequential)]
    public struct FLASHWINFO
    {
        public UInt32 cbSize;
        public IntPtr hwnd;
        public UInt32 dwFlags;
        public UInt32 uCount;
        public UInt32 dwTimeout;
    }

    public const UInt32 FLASHW_STOP = 0;
    public const UInt32 FLASHW_CAPTION = 1;
    public const UInt32 FLASHW_TRAY = 2;
    public const UInt32 FLASHW_ALL = 3;
    public const UInt32 FLASHW_TIMER = 4;
    public const UInt32 FLASHW_TIMERNOFG = 12; 

    static void Main(string[] args)
    {
        // Give you a few seconds to alt-tab away :)
        Thread.Sleep(2000);

        // Flash on the task bar, until the window becomes the foreground window.
        // Constants for other behaviors are defined above.
        FLASHWINFO fInfo = new FLASHWINFO();
        fInfo.cbSize = Convert.ToUInt32(Marshal.SizeOf(fInfo));
        fInfo.hwnd = Process.GetCurrentProcess().MainWindowHandle;
        fInfo.dwFlags = FLASHW_TRAY | FLASHW_TIMERNOFG;
        fInfo.uCount = UInt32.MaxValue;
        fInfo.dwTimeout = 0;
        FlashWindowEx(ref fInfo);

        // Wait for input so the app doesn't finish right away.
        Console.ReadLine();
    }
}
Dragon answered 27/5, 2010 at 17:36 Comment(1)
This part was important for me: fInfo.dwFlags = FLASHW_TRAY | FLASHW_TIMERNOFG; This make the window stop flashing on gaining focus.Eyelash
P
1

I looked into the issue @Davy8 had in which the flashing doesn't stop. The solution was pretty simple, just pass the FLASHW_STOP constant. To show this, I further augmented @Davy8's static class to include a StopFlashing static function. I also decided to add comments based on the Microsoft Documentation such that it is easy to see why these are applied in C#.

    /// <summary>
    /// Class for flashing a console window
    /// <see cref="https://learn.microsoft.com/en-us/windows/desktop/api/winuser/ns-winuser-flashwinfo"/>
    /// </summary>
    public static class FlashWindow
    {
        /// <summary>
        /// Flashes the specified window. It does not change the active state of the window.
        /// </summary>
        /// <param name="pwfi">FLASHWINFO</param>
        /// <see cref="https://learn.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-flashwindowex"/>
        /// <returns>If the window caption was drawn as active before the call, the return value is nonzero. Otherwise, the return value is zero.</returns>
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool FlashWindowEx(ref FLASHWINFO pwfi);

        /// <summary>
        /// Retrieves the window handle used by the console associated with the calling process.
        /// </summary>
        /// <see cref="https://learn.microsoft.com/en-us/windows/console/getconsolewindow"/>
        /// <returns>The return value is a handle to the window used by the console associated with the calling process or NULL if there is no such associated console.</returns>
        [DllImport("kernel32.dll")]
        static extern IntPtr GetConsoleWindow();

        /// <summary>
        /// Contains the flash status for a window and the number of times the system should flash the window.
        /// <see cref="https://learn.microsoft.com/en-us/windows/desktop/api/winuser/ns-winuser-flashwinfo"/>
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct FLASHWINFO
        {
            /// <summary>
            /// The size of the structure, in bytes
            /// </summary>
            public UInt32 cbSize;

            /// <summary>
            /// A handle to the window to be flashed. The window can be either opened or minimized.
            /// </summary>
            public IntPtr hwnd;

            /// <summary>
            /// The flash status. This parameter can be one or more of the following values.
            /// </summary>
            public UInt32 dwFlags;

            /// <summary>
            /// The number of times to flash the window.
            /// </summary>
            public UInt32 uCount;

            /// <summary>
            /// The rate at which the window is to be flashed, in milliseconds. If dwTimeout is zero, the function uses the default cursor blink rate.
            /// </summary>
            public UInt32 dwTimeout;
        }

        /// <summary>
        /// Flash both the window caption and taskbar button. This is equivalent to setting the FLASHW_CAPTION | FLASHW_TRAY flags.
        /// </summary>
        public const UInt32 FLASHW_ALL = 0x00000003;

        /// <summary>
        /// Flash the window caption.
        /// </summary>
        public const UInt32 FLASHW_CAPTION = 0x00000001;

        /// <summary>
        /// Stop flashing. The system restores the window to its original state.
        /// </summary>
        public const UInt32 FLASHW_STOP = 0x00000004;

        /// <summary>
        /// Flash continuously, until the FLASHW_STOP flag is set.
        /// </summary>
        public const UInt32 FLASHW_TIMER = 4;

        /// <summary>
        /// Flash continuously until the window comes to the foreground.
        /// </summary>
        public const UInt32 FLASHW_TIMERNOFG = 0x0000000C;

        /// <summary>
        /// Flash the taskbar button.
        /// </summary>
        public const UInt32 FLASHW_TRAY = 0x00000002;


        /// <summary>
        /// Create an instance of the FLASHWINFO structure
        /// </summary>
        /// <param name="flashwConstant">One of the provided FLASHW contant values</param>
        /// <param name="uCount">uCount to initialize the struct</param>
        /// <param name="dwTimeout">dwTimeout to initalize the struct</param>
        /// <returns>A fully instantiated FLASHWINFO struct</returns>
        private static FLASHWINFO GetFLASHWINFO(UInt32 flashwConstant, UInt32 uCount = UInt32.MaxValue, UInt32 dwTimeout = 0)
        {
            FLASHWINFO fInfo = new FLASHWINFO
            {
                hwnd = GetConsoleWindow(),
                dwFlags = flashwConstant,
                uCount = uCount,
                dwTimeout = dwTimeout
            };
            fInfo.cbSize = Convert.ToUInt32(Marshal.SizeOf(fInfo));
            return fInfo;
        }

        /// <summary>
        /// Flashes the console window (continues indefinitely)
        /// </summary>
        public static void Flash()
        {
            FLASHWINFO fInfo = GetFLASHWINFO(FLASHW_ALL);
            FlashWindowEx(ref fInfo);
        }

        /// <summary>
        /// Stops the flashing of the console window
        /// </summary>
        public static void StopFlash()
        {
            FLASHWINFO fInfo = GetFLASHWINFO(FLASHW_STOP);
            FlashWindowEx(ref fInfo);
        }
    }
Penninite answered 20/5, 2019 at 21:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.