:: El Monstruillo wARfeando ::

Poner un icono en la TrayIcon con WinAPI

¿Cómo hacer lo mismito que hace el Messenger o el Skype para poner su iconcico en ese rectangulito al lado de la hora en la barra de Windows (a partir de ahora ‘TrayIcon’, para abreviar)?

Hace poco vi en GetAFreeLancer.com la petición de alguien para hacer un programa que entre otras cosas se “iconificara” en la trayicon y me pregunté ¿cómo haría yo eso? así que me puse a investigar un poco (¡viva google y las MSDN!) y esto es lo que saqué en claro:

Lo primero que se necesita para poder poner el icono de una aplicación en la trayicon es tener una aplicación con icono… :P.

Para poner un icono vamos a necesitar unas estructuras de datos y unas funciones que se encuentran en shell32.lib (o shel32.dll si os van más las dlls) con los prototipos de las funciones en shellapi.h, de modo que hay que hacer que el compilador enlace esta librería y hay que añadir el include para . Además vamos a necesitar definirnos un mensaje para que se comuniquen el iconillo en el trayicon y nuestra aplicación, esto podemos hacerlo así:

#define MSG_TRAYICON WM_USER + 1

Mediante este mensaje el icono del trayicon le notificará a la aplicación los eventos de ratón que se hagan en su área (no se si le notificará más eventos, como alguno de teclado, he leido tanto que no lo hará como que sí, pero no lo he probado me queda pendiente hacerlo).

Vamos a suponer que tenemos un botoncico que al hacer click sobre él, la aplicación se nos iconifica en el trayicon y que luego, al hacer doble click con el botón derecho sobre el icono la aplicación vuelve a mostrarse y el iconillo del trayicon desaparece. Y vamos a suponer que el botoncico tiene un identificador tal que así: IDICONIFICAR.

Entonces, en la función de gestión el bucle de mensajes principal (WndProc) después de capturar el mensaje de el WM_COMMAND (donde se caputra el click en los botones) tendríamos algo así para capturar el click en IDICONIFICAR:

switch(LOWORD(wParam)) {

case IDICONIFICAR:

NOTIFYICONDATA data;

data.cbSize = sizeof(data);
data.hWnd = hWnd;
data.uID = 10001;
data.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICONCILLO));
data.uFlags = NIF_ICON|NIF_TIP | NIF_MESSAGE;
strcpy(data.szTip, “Estoy iconificao, hazme doble click”);
data.uCallbackMessage = MSG_TRAYICON;

Shell_NotifyIcon(NIM_ADD, &data);
ShowWindow(hWnd, SW_HIDE);
break;

// … demás botones

}

Con la estructura NOTIFYICONDATA preparamos el iconillo que pondremos en el trayicon:data.cbSize es para proveer algo de seguridad a la hora de leer luego la estructura (si no se pone, no funciona porque no leera nada), data.hWnd es ventana de la aplicación que se iconificará, data.uID es un identificador para el icono en el trayicon, data.hIcon es el manejador del icono que se pondrá en el trayicon, data.hTip es el mensaje que se mostrará al dejar el puntero del ratón sobre el icono durante un momentito, data.uCallbackMessage es el mensaje que hemos creado para que se comuniquen el icono en la trayicon y la aplicación y data.uFlags indica a que campos de la estructura data se va a hacer caso, en este caso al icono, al tip y al mensaje que compartirán.

Una vez cargada la estructura usamos Shell_NotifyIcon() para actuar sobre trayicon, se usa esta función tanto para añadir (NIM_ADD), como para modificar el icono (NIM_MODIFY) o para quitarlo (NIM_DELETE). Como veis se le pasa la acción (NIM_*) y la estructura. Después de esto, o antes, según os apetezca se esconde la aplicación (poner el icono en el trayicon no hace que la aplicación desaparezca de la pantalla, hay que quitarla) con ShowWindow(hWnd, SW_HIDE).

Vale, en este punto la aplicación ya es capaz de “iconificarse”, pero ¿cómo hacemos para volverla mostrar cuando hago doble click con el botón izquierdo sobre el icono (por poner un ejemplo)?

Pues en la misma función de control del bucle de mensajes (WndProc, por ejemplo), cuando se capturan los mensajes (switch(message)) como WM_COMMAND, WM_INITDIALOG, etc… Aquí podemos añadir algo así:

case MSG_TRAYICON:

NOTIFYICONDATA data;

data.cbSize = sizeof(data);
data.hWnd = hWnd;
data.uID = 10001;

// El mensaje enviado por el icono está en lParam
switch (lParam) {
case WM_LBUTTONDBLCLK:
Shell_NotifyIcon(NIM_DELETE, &data);
ShowWindow(hWnd, SW_SHOW);

}
break;

}

Ale, así de simple…

This entry (Permalink) was posted on Saturday, March 17th, 2007 at 13:23 and is filed under WinAPI. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response , or trackback from your own site.

Leave a Reply

You must be logged in to post a comment.