Shell_NotifyIcon PROTO dwMessage:DWORD ,pnid:DWORD
dwMessage
Es el tipo de mensaje a enviar al shell de Windows.
NIM_ADD Añade un icono al area
de estado.
NIM_DELETE Borra un icono del area de
estado.
NIM_MODIFY Modifica un icono en el area
de estado.
pnid
es el puntero a la estructura NOTIFYICONDATA
rellenada con valores apropiados
Si quieres añadir un icono
a la bandeja, usa el mensage NIM_ADD, si quieres borrar un icono , usa NIM_DELETE.
WM_SHELLNOTIFY
equ WM_USER+5
IDI_TRAY
equ 0
IDM_RESTORE
equ 1000
IDM_EXIT
equ 1010
WinMain
PROTO :DWORD,:DWORD,:DWORD,:DWORD
.data
ClassName
db "TrayIconWinClass",0
AppName
db "TrayIcon Demo",0
RestoreString
db "&Restore",0
ExitString
db "E&xit Program",0
.data?
hInstance
dd ?
note
NOTIFYICONDATA <>
hPopupMenu
dd ?
.code
start:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke WinMain, hInstance,NULL,NULL, SW_SHOWDEFAULT
invoke ExitProcess,eax
WinMain
proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
LOCAL hwnd:HWND
mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style, CS_HREDRAW or CS_VREDRAW or CS_DBLCLKS
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInst
pop wc.hInstance
mov wc.hbrBackground,COLOR_APPWORKSPACE
mov wc.lpszMenuName,NULL
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, addr wc
invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName,ADDR AppName,\
WS_OVERLAPPED+WS_CAPTION+WS_SYSMENU+WS_MINIMIZEBOX+WS_MAXIMIZEBOX+WS_VISIBLE,CW_USEDEFAULT,\
CW_USEDEFAULT,350,200,NULL,NULL,\
hInst,NULL
mov hwnd,eax
.while TRUE
invoke GetMessage, ADDR msg,NULL,0,0
.BREAK .IF (!eax)
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
.endw
mov eax,msg.wParam
ret
WinMain
endp
WndProc
proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
LOCAL pt:POINT
.if uMsg==WM_CREATE
invoke CreatePopupMenu
mov hPopupMenu,eax
invoke AppendMenu,hPopupMenu,MF_STRING,IDM_RESTORE,addr RestoreString
invoke AppendMenu,hPopupMenu,MF_STRING,IDM_EXIT,addr ExitString
.elseif uMsg==WM_DESTROY
invoke DestroyMenu,hPopupMenu
invoke PostQuitMessage,NULL
.elseif uMsg==WM_SIZE
.if wParam==SIZE_MINIMIZED
mov note.cbSize,sizeof NOTIFYICONDATA
push hWnd
pop note.hwnd
mov note.uID,IDI_TRAY
mov note.uFlags,NIF_ICON+NIF_MESSAGE+NIF_TIP
mov note.uCallbackMessage,WM_SHELLNOTIFY
invoke LoadIcon,NULL,IDI_WINLOGO
mov note.hIcon,eax
invoke lstrcpy,addr note.szTip,addr AppName
invoke ShowWindow,hWnd,SW_HIDE
invoke Shell_NotifyIcon,NIM_ADD,addr note
.endif
.elseif uMsg==WM_COMMAND
.if lParam==0
invoke Shell_NotifyIcon,NIM_DELETE,addr note
mov eax,wParam
.if ax==IDM_RESTORE
invoke ShowWindow,hWnd,SW_RESTORE
.else
invoke DestroyWindow,hWnd
.endif
.endif
.elseif uMsg==WM_SHELLNOTIFY
.if wParam==IDI_TRAY
.if lParam==WM_RBUTTONDOWN
invoke GetCursorPos,addr pt
invoke SetForegroundWindow,hWnd
invoke TrackPopupMenu,hPopupMenu,TPM_RIGHTALIGN,pt.x,pt.y,NULL,hWnd,NULL
invoke PostMessage,hWnd,WM_NULL,0,0
.elseif lParam==WM_LBUTTONDBLCLK
invoke SendMessage,hWnd,WM_COMMAND,IDM_RESTORE,0
.endif
.endif
.else
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.endif
xor eax,eax
ret
WndProc
endp
end
start
.if uMsg==WM_CREATE
invoke CreatePopupMenu
mov hPopupMenu,eax
invoke AppendMenu,hPopupMenu,MF_STRING,IDM_RESTORE,addr RestoreString
invoke AppendMenu,hPopupMenu,MF_STRING,IDM_EXIT,addr ExitString
Cuando
se crea la ventana principal, crea un menu emergente y le añade
dos elementos. AppendMenu tiene la siguiente sintaxis:
AppendMenu PROTO hMenu:DWORD, uFlags:DWORD, uIDNewItem:DWORD, lpNewItem:DWORDDespués de que es creado el menú emergente, la ventana principal espera pacientemente a que el usuario pulse el botón de minimizar.
- hMenu es el manejador (handle) del menú al que quieres añadir el elemento
- uFlags le dice a Windows sobre el elemento de menú a añadir al menú ,tanto si es un bitmap o una cadena o un elemento que se auto dibuja, activado, difuminado o desactivado etc. Puedes conseguir la lista completa en la referencia de la api de win32. En nuestro ejemplo, usamos MF_STRING, lo que significa que el elemento del menú es una cadena.
- uIDNewItem es el ID (identidad) del menu item. Este es un valor definido por el usuario que es usado para representar el elemento del menu.
- lpNewItem especifica el contenido del elemento, dependiendo de lo que especifiques en el miembro uFlags. Como nosotros hemos especificado MF_STRING en uFlags, lpNewItem deberá contener el puntero a la cadena a mostrar en el menú emergente.
.elseif uMsg==WM_SIZE
.if wParam==SIZE_MINIMIZED
mov note.cbSize,sizeof NOTIFYICONDATA
push hWnd
pop note.hwnd
mov note.uID,IDI_TRAY
mov note.uFlags,NIF_ICON+NIF_MESSAGE+NIF_TIP
mov note.uCallbackMessage,WM_SHELLNOTIFY
invoke LoadIcon,NULL,IDI_WINLOGO
mov note.hIcon,eax
invoke lstrcpy,addr note.szTip,addr AppName
invoke ShowWindow,hWnd,SW_HIDE
invoke Shell_NotifyIcon,NIM_ADD,addr note
.endif
Aprovechamos esta oportunidad para rellenar la estructura NOTIFYICONDATA. IDI_TRAY es una constante definida al principio del código fuente. Puedes ponerlo al valor que quieras. Esto no importa porque tienes un único icoo de bandeja. Pero si vas a poner varios iconos en la bandeja del sistema necesitarás un ID único para cada icono de bandeja. Especificamos todas las banderas en el miembro uFlags porque especificamos un icono (NIF_ICON), especificamos un mensaje común (NIF_MESSAGE) y especificamos el texto tooltip (NIF_TIP). WM_SHELLNOTIFY es un mensaje común definido como WM_USER+5. El valor actual no es importante siempre que sea único. Yo uso aquí el icono winlogo como icono de bandeja pero puedes usar cualquier icono en tu programa. Cárgalo desde el recurso con LoadIcon y pon el manejador (handle) devuelto en el miembro hIcon. Finalmente, rellenamos el szTip con el texto que queremos que muestre el shell cuando el ratón está sobre el icono.
Ocultamos la ventana padre para dar la ilusión de parecer minimizar al icono de bandeja.
Después podemos llamar a Shell_NotifyIcon con el mensage NIM_ADD para añadir el icono a la barra del sistema.
Ahora nuestra ventana principal está oculta y el icono está en la banedja del sistema. Si mueves el ratón sobre él verás el tooltip que muestra el texto que ponemos dentro del miembro szTip. Después, si haces una pulsación doble en el icono, la ventana principal reaparecerá y el icono de bandeja se irá.
.elseif uMsg==WM_SHELLNOTIFY
.if wParam==IDI_TRAY
.if lParam==WM_RBUTTONDOWN
invoke GetCursorPos,addr pt
invoke SetForegroundWindow,hWnd
invoke TrackPopupMenu,hPopupMenu,TPM_RIGHTALIGN,pt.x,pt.y,NULL,hWnd,NULL
invoke PostMessage,hWnd,WM_NULL,0,0
.elseif lParam==WM_LBUTTONDBLCLK
invoke SendMessage,hWnd,WM_COMMAND,IDM_RESTORE,0
.endif
.endif
Cuando ocurre algún evento de ratón sobre el icono de bandeja, tu ventana recibe el mensaje WM_SHELLNOTIFY que es el mensage común que especificas en el miembro uCallbackMessage. Vuelve a llamar a esta recibiendo el mensaje, wParam contiene la ID del icono de bandeja y lParam contiene el mensaje de ratón actual. En el código de arriba, primero chequeamos si este mensaje viene del icono de bandeja que nos interesa. Si esto ocurre, chequeamos el mensaje del ratón. Como estamos interesados únicamente en la pulsación derecha o en la doble pulsación izquierda, procesamos sólo los mensages WM_RBUTTONDOWN y WM_LBUTTONDBLCLK.
Si el mensaje de ratón es WM_RBUTTONDOWN llamamos a GetCursorPos para obtener las coordenadas actuales en la pantalla del ratón. Cuando la función vuelve, la estructura POINT es rellenada con las coordenadas en pantalla del ratón. Port coordenada de pantalla, quiero decir la coordenada de toda la pantalla sin considerar a ninguno de los bordes de ninguna ventana. Por ejemplo, si la resolución de la pantalla es 640*480, la esquina inferior derecha de la pantalla es x==639 e y==479. Si quieres convertir la coordenada de pantalla a coordenada de ventana usa la función ScreenToClient.
Como siempre,
para nuestro propósitos, queremos mostrar el menú emergente en
la posición actual del ratón con la llamada a TrackPopupMenu y
esto requiere coordenadas de pantalla, podemos usar las coordenadas rellenadas
directamente en GetCursorPos.
TrackPopupMenu
tiene la siguiente sintaxis:
invoke Shell_NotifyIcon,NIM_DELETE,addr note
mov eax,wParam
.if ax==IDM_RESTORE
invoke ShowWindow,hWnd,SW_RESTORE
.else
invoke DestroyWindow,hWnd
.endif
Cuando el
usuario selecciona el elemento del menú Restore, borramos el icono de
la bandeja llamando otra vez a Shell_NotifyIcon, ahora especificamos como mensaje
NIM_DELETE. Lo siguiente es restaurar la ventana principal a su estado original.
Si el usuario selecciona Exit en el menu, también borramos el icono de
la barra y destruimos la ventana principal llamando a DestroyWindow.
[Iczelion's Win32 Assembly HomePage]
n u M I T_o r's Programming Page
Este tutorial, original de Iczelion, ha sido traducido por JoTaKe, y revisado por: n u M I T_o r