Есть ли способ заставить окно консоли мигать программно на панели задач?

В основном я сделал консольное приложение, которое выполняет некоторую задачу, которая занимает несколько минут. Я хотел бы, чтобы он запустился на панели задач, чтобы сообщить мне, когда это будет сделано.

Ответ 1

Используя ответ, который @Zack опубликовал и другой, чтобы найти дескриптор консольного приложения я придумал это, и он отлично работает.

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

Ответ 2

Я прочитал, что не удалось получить дескриптор окна окна консоли через какие-либо прямые средства, но, похоже, это довольно простой в .NET на самом деле. Итак, он почти такой же, как этот вопрос:

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

Ответ 3

Объединяя ответ в вопросе, связанный с комментарием @Zack, и получая hwnd окна консоли, используя это, я смог его получить за работой. Это класс, который я создал:

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

Он никогда не останавливается, пока он не закрывается, но это не важно для моих целей.

Ответ 4

Я посмотрел на проблему @Davy8, в которой мигание не прекращается. Решение было довольно простым, просто передайте константу FLASHW_STOP. Чтобы показать это, я добавил в статический класс @Davy8 функцию статической функции StopFlashing. Я также решил добавить комментарии на основе документации Microsoft, чтобы было легко понять, почему они применяются в С#.

    /// <summary>
    /// Class for flashing a console window
    /// <see cref="https://docs.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://docs.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://docs.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://docs.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);
        }
    }