Ventanas parpadeantes con FlashWindowEx (I)

Entre las diversas tareas que una aplicación debe realizar, a veces se encuentran ciertos procesos que pueden tomar un considerable tiempo en completarse. Ante este tipo de situaciones resulta una inestimable ayuda para el usuario la posibilidad de disponer de algún tipo de indicación visual, que le notifique cuándo ha terminado el proceso de ejecutarse.


Un recurso que podemos utilizar para conseguir este objetivo consiste en realizar una llamada a la función FlashWindowEx, perteneciente a la API de Windows, cuya finalidad consiste en hacer parpadear la ventana sobre la que se aplica esta función.


En las dos partes que componen el presente artículo describiremos -en esta primera parte- las características de esta función, así como la forma en que debemos declararla en nuestro código para poder llamarla posteriormente. En la segunda parte ilustraremos con varios ejemplos prácticos su modo de uso dentro de una aplicación.


El efecto de parpadeo conseguido mediante FlashWindowEx puede estar condicionado por diversos factores que nos permiten establecer su comportamiento; de esta forma podemos especificar, entre otras características, el número de veces en que se producirá el parpadeo, la frecuencia entre los mismos, la finalización del efecto, etc.


Elementos relacionados con FlashWindowEx


Para poder enviar toda la información necesaria a FlashWindowEx, esta función recibe como parámetro una estructura denominada FLASHWINFO en la documentación de Windows. Respecto al valor de retorno de FlashWindowEx, consiste en un dato numérico que nos indica el estado que originalmente tenía la ventana antes de realizar la llamada. La firma de esta función en la documentación es la siguiente.


BOOL WINAPI FlashWindowEx(__in PFLASHWINFO pfwi);


Volviendo a la estructura FLASHWINFO, la siguiente tabla describe cada uno de los miembros que la componen.



























Miembro de estructura Tipo de dato Finalidad
cbSize int Tamaño de la estructura.
hwnd IntPtr Manipulador de la ventana a la que se aplicará el parpadeo.
dwFlags int Tipo de efecto a aplicar. Combinación de una o más constantes que se describirán seguidamente.
uCount int Número de veces que se producirá el parpadeo.
dwTimeout int Intervalo, en milisegundos, en que se producirá el efecto. En caso de que este valor sea cero, se utilizará el mismo intervalo que el cursor de escritura.

Como acabamos de observar, el elemento dwFlags de esta estructura admite una serie de valores, que pueden ser representados mediante un conjunto de constantes, cuyos nombres -tal y como aparecen en la documentación de Windows- se muestran relacionados a continuación.































Constante Valor Finalidad
FLASHW_ALL 0X00000003 Hace parpadear tanto la barra de título de la ventana como el botón asociado situado en la barra de tareas de Windows. Este valor es igual al uso combinado de las constantes FLASHW_CAPTION y FLASHW_TRAY.
FLASHW_CAPTION 0X00000001 Hace parpadear la barra de título de la ventana. En Windows Vista, el efecto  se hará extensible a todo el borde de la ventana, incluyendo su parte de sombreado.
FLASHW_STOP 0 Detiene el parpadeo.
FLASHW_TIMER 0X00000004 Establece un parpadeo por tiempo indefinido hasta que hagamos uso de la constante FLASHW_STOP.
FLASHW_TIMERNOFG 0X0000000C Establece un parpadeo constante hasta que el usuario traiga la ventana a primer plano.
FLASHW_TRAY 0X00000002 Hace parpadear el botón de la ventana situado en la barra de tareas de Windows.

Como fuente oficial de referencia, en los siguientes enlaces tenemos disponible la información tanto de FlashWindowEx como de FLASHWINFO, así como de otra función, FlashWindow, que abordaremos en la segunda parte del artículo.


Preparando el código


Y llegamos al momento de poner en práctica toda la teoría explicada anteriormente, para lo cual iniciaremos Visual Studio y crearemos un nuevo proyecto de tipo «Aplicación WPF» que utilizaremos como banco de pruebas. Todos los ejemplos aquí explicados resultan igualmente aplicables a un programa Windows Forms tradicional, con alguna ligera variante que puntualizaremos allá donde sea necesario.


En primer lugar vamos a declarar la estructura FLASHWINFO, cuyo código escribiremos en el mismo archivo de clase que la ventana del proyecto, a fin de simplificar este ejemplo.


namespace VentanasParpadeantes_CS
{
public struct FLASHWINFO
{
public int cbSize;
public IntPtr hwnd;
public int dwFlags;
public int uCount;
public int dwTimeout;
}
//….
}

Continuaremos con las constantes que necesita el miembro dwFlags de esta estructura para poder aplicar el tipo de efecto adecuado. Estos valores podemos implementarlos de dos maneras: declarando las constantes dentro de la clase de la ventana.


public partial class Window1 : Window
{
//….
private const int FLASHW_CAPTION = 0x00000001;
private const int FLASHW_TRAY = 0x00000002;
private const int FLASHW_ALL = (FLASHW_CAPTION | FLASHW_TRAY);
private const int FLASHW_STOP = 0;
private const int FLASHW_TIMER = 0x00000004;
private const int FLASHW_TIMERNOFG = 0x0000000C;
//….
}

O bien, dado que se trata de un conjunto de valores relacionados, creando una enumeración e incluyéndolos como miembros de la misma.


namespace VentanasParpadeantes_CS
{
//….
public enum FlashStatus : int
{
FLASHW_CAPTION = 0x00000001,
FLASHW_TRAY = 0x00000002,
FLASHW_ALL = (FLASHW_CAPTION | FLASHW_TRAY),
FLASHW_STOP = 0,
FLASHW_TIMER = 0x00000004,
FLASHW_TIMERNOFG = 0x0000000C
}
//….

Para terminar con esta parte del ejemplo declararemos la función FlashWindowEx aplicándole el atributo DllImport, al que pasaremos como parámetro una cadena con el nombre de la librería de la API de Windows a utilizar, en este caso user32.dll, ya que es la que contiene la función a emplear. Igualmente será necesario declarar el espacio de nombres InteropServices, como vemos a continuación.


using System.Runtime.InteropServices;
//….
namespace VentanasParpadeantes_CS
{
//….
public partial class Window1 : Window
{
//….
[DllImport(«user32.dll»)]
public static extern int FlashWindowEx(ref FLASHWINFO pfwi);
//….

Nótese que la estructura FLASHWINFO debe pasarse a FlashWindowEx por referencia, para lo cual emplearemos la palabra clave ref junto a la estructura.


En el caso de encontrarnos trabajando con VB, además de poder declarar la función con el atributo DllImport, podemos emplear también la palabra clave Declare; ambos modos de declaración en este lenguaje se muestran a continuación.


<DllImport(«user32.dll»)> _
Public Shared Function FlashWindowEx(ByRef pfwi As FLASHWINFO) As Integer
End Function

Declare Function FlashWindowEx Lib «user32.dll» (ByRef pfwi As FLASHWINFO) As Integer


Una vez finalizados todos estos pasos, ya nos encontramos en disposición de usar esta función en nuestra ventana, para lo que añadiremos a la misma varios botones que nos sirvan para poner en funcionamiento los diversos ejemplos a ilustrar. El aspecto de la ventana podemos verlo en la siguiente imagen.



El código XAML utilizado para definir la interfaz de usuario lo vemos a continuación.


<Window xmlns:my1=»clr-namespace:System.Windows.Controls;assembly=PresentationFramework»
xmlns:my=»clr-namespace:System.Windows.Controls;assembly=PresentationFramework»
x:Class=»VentanasParpadeantes_CS.Window1″
xmlns=»http://schemas.microsoft.com/winfx/2006/xaml/presentation»
xmlns:x=»http://schemas.microsoft.com/winfx/2006/xaml»
Title=»Pruebas con FlashWindowEx»
Height=»220″ Width=»300″
Loaded=»Window_Loaded»
StateChanged=»Window_StateChanged»>

<my:StackPanel Background=»LightYellow»>
<my1:Button Name=»btnBasico» Margin=»10″ Width=»110″ Click=»btnBasico_Click»>Básico</my1:Button>
<my1:Button Name=»btnComenzar» Margin=»10″ Width=»110″ Click=»btnComenzar_Click»>Comenzar</my1:Button>
<my1:Button Name=»btnTerminar» Margin=»10″ Width=»110″ Click=»btnTerminar_Click»>Terminar</my1:Button>
</Window>


Y llegados a este punto terminamos la primera parte de este artículo; en la siguiente entrega abordaremos con varios ejemplos la manera de implementar esta función dentro de un programa.


No obstante, pensando en los más impacientes, vamos a proporcionar los enlaces con el código fuente de los ejemplos en C# y VB.


Un saludo.


 

5 Comentarios

  1. vargas

    El problema es el mal uso que se le suele dar y al final te encuentras un número considerable de aplicaciones que hacer esto por que mola…

  2. lmblanco

    Hola Vargas

    Gracias por tu opinión, y estoy de acuerdo en que recursos de este tipo hay que utilizarlos con mesura, ya que su abuso puede ser contraproducente.

    Un saludo.
    Luismi

  3. anonymous

    Muy interesate!

  4. lmblanco

    Hola Jhonatan

    Gracias por tu opinión.

    Un saludo.
    Luismi

  5. novatitoincsharp

    Hola, aunqe este post sea muy antiguo, sige siendo muy interesante..
    veras, Seguí tu ejemplo a pie de letra, pero No se qe estaré haciendo mal!!
    algunos codigos marcan error :S
    estos son algunos :
    *Timer tmrTemporizador;
    *TimeSpan tsComienzo;
    *moFlashwInfo.hwnd = new WindowInteropHelper(Application.Current.MainWindow).Handle;

    *hwndManipVentana = new WindowInteropHelper(Application.Current.MainWindow).Handle;

    stoy haciendo una aplicacion en c# con visual studio 2010!

    Tal vez sabes cual es mi error porfavor, respondeme

    Ojala pudieras ayudarme 😉
    Gracias de antemano…

Responder a Cancelar respuesta

Tema creado por Anders Norén