For applications that perform long
operations or have some asynchronous operation such as a chat client or download manager, the standard way of alerting the user to the completion of a task, especially if the window is minimized, is to flash the taskbar button.
The .NET framework doesn't provide this facility in a managed class and so a bit of interop is needed to enable the use of the
FlashWindowEx method.
FlashWindowEx is the Win32 API call that controls the flashing of the taskbar buttons or window title bar. This method takes a single parameter, the FLASHWINFO structure that contains all the options for the flash operation. In order to use the method you have to create a p/invoke method wrapper for the FlashWindowEx method and recreate the FLASHWINFO structure so that it's usable by managed code.
Recreating FLASHWINFO
The
original Win32 FLASHWINFO structure is declared like so:
typedef struct {
UINT cbSize;
HWND hwnd;
DWORD dwFlags;
UINT uCount;
DWORD dwTimeout;
} FLASHWINFO,
*PFLASHWINFO;Recreating this for managed code we need to change the types in the original structure for equivalent .NET types. This provides the following:
[StructLayout(LayoutKind.Sequential)]
public struct FLASHWINFO
{
public UInt32 cbSize;
public IntPtr hwnd;
public Int32 dwFlags;
public UInt32 uCount;
public Int32 dwTimeout;
}
<StructLayout(LayoutKind.Sequential)> _
Public Structure FLASHWINFO
Public cbSize As UInt32
Public hwnd As IntPtr
Public dwFlags As Int32
Public uCount As UInt32
Public dwTimeout As Int32
End Structure 'FLASHWINFO
The flags set in the FLASHWINFO structure dictate how the window is flashed and so the set of constant values from winuser.h, the old Win32
header file,
can be brought into the .net world like so:
public enum FLASHWINFOFLAGS
{
FLASHW_STOP =0,
FLASHW_CAPTION =0x00000001,
FLASHW_TRAY =0x00000002,
FLASHW_ALL =(FLASHW_CAPTION | FLASHW_TRAY),
FLASHW_TIMER =0x00000004,
FLASHW_TIMERNOFG =0x0000000C
}
Public Enum FLASHWINFOFLAGS
FLASHW_STOP = 0
FLASHW_CAPTION = &H1
FLASHW_TRAY = &H2
FLASHW_ALL = FLASHW_CAPTION Or FLASHW_TRAY
FLASHW_TIMER = &H4
FLASHW_TIMERNOFG = &HC
End Enum 'FLASHWINFOFLAGS
To call the FlashWindowEx method the following code must be included in the form class. It creates a method wrapper for the Win32 API call.
[DllImport("user32.dll")]
public static extern int FlashWindowEx(ref FLASHWINFO pfwi);
<DllImport("user32.dll")> _
Public Shared Function FlashWindowEx(ByRef pfwi As FLASHWINFO) As Integer
End Function
Finally, to demonstrate the use of this API the code shown in the following listing is an application that handles the OnSizeChanged event of the form. The form runs a timer which expires after five seconds. Normally, this timer is turned off but when the form is minimized it is set running so that five seconds after the minimize is detected, the taskbar button for the application will begin to flash to remind you that it's there.
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Runtime.Interop
Services;
namespace FlashWindowDemo
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
[DllImport("user32.dll")]
public static extern int FlashWindowEx(ref FLASHWINFO pfwi);
private System.Windows.Forms.Timer timer1;
private System.Windows.Forms.Label label1;
private System.ComponentModel.IContainer components;
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not
modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.timer1 = new System.Windows.Forms.Timer(this.components);
this.label1 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// timer1
//
this.timer1.Enabled = true;
this.timer1.Interval = 5000;
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
//
// label1
//
this.label1.Location = new System.Drawing.Point(32, 40);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(232, 32);
this.label1.TabIndex = 0;
this.label1.Text = "Please minimise this window...";
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 273);
this.Controls.Add(this.label1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
bool active;
private void timer1_Tick(object sender, System.EventArgs e)
{
if(!active)
{
this.timer1.Enabled=false;
FLASHWINFO fw=new FLASHWINFO();
fw.cbSize=Convert.ToUInt32(Marshal.SizeOf(typeof(FLASHWINFO)));
fw.hwnd=this.Handle;
fw.dwFlags=(Int32)(FLASHWINFOFLAGS.FLASHW_ALL | FLASHWINFOFLAGS.FLASHW_TIMERNOFG);
fw.dwTimeout=0;
FlashWindowEx(ref fw);
}
}
protected override void OnActivated(EventArgs e)
{
active=true;
base.OnActivated (e);
}
protected override void OnDeactivate(EventArgs e)
{
this.timer1.Enabled=true;
active=false;
base.OnDeactivate (e);
}
}
public enum FLASHWINFOFLAGS
{
FLASHW_STOP =0,
FLASHW_CAPTION =0x00000001,
FLASHW_TRAY =0x00000002,
FLASHW_ALL =(FLASHW_CAPTION | FLASHW_TRAY),
FLASHW_TIMER =0x00000004,
FLASHW_TIMERNOFG =0x0000000C
}
[StructLayout(LayoutKind.Sequential)]
public struct FLASHWINFO
{
public UInt32 cbSize;
public IntPtr hwnd;
public Int32 dwFlags;
public UInt32 uCount;
public Int32 dwTimeout;
}
}