Poner un icono en la TrayIcon con WinAPI
March 17th, 2007¿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…

