Shell_NotifyIcon PROTO dwMessage:DWORD ,pnid:DWORD
dwMessage
est le type de message à envoyer au Shell.
NIM_ADD ajoute une icône au secteur de statut.
NIM_DELETE supprime une icône du secteur de statut.
NIM_MODIFY modifie une icône dans le secteur de statut.
pnid
est le pointer qui est sur la structure
Si vous voulez ajouter une icône dans le 'System Tray', vous devez utiliser le message NIM_ADD, si vous voulez enlever l'icône, il faut employer 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
Quand la fenêtre principale est créée, on crée un menu popup et on y ajouter deux Items (deux sous-menu). La fonction 'AppendMenu' a la syntaxe suivante :
AppendMenu PROTO hMenu:DWORD, uFlags:DWORD, uIDNewItem:DWORD, lpNewItem:DWORDAprès que le menu popup est été créé, la fenêtre principale attend patiemment que l'utilisateur appuie sur le bouton de réduction (minimum).
- hMenu est l'handle du menu auquel vous voulez ajouter l'Item.
- uFlags indique à Windows que l'Item du menu qui doit y être ajouté est un bitmap ou une chaîne de caractères ou bien encore un Item possédant d'autres sous-Items, activé (enable), grisé (gray) ou désactivé (disable) etc. Vous pouvez obtenir la liste complète avec la référence api win32. Dans notre exemple, nous employons MF_STRING ce qui signifie que l'Item du menu est une simple chaîne de caractères.
- uIDNewItem est l'ID de l'Item du menu. C'est une valeur définie par l'utilisateur, elle est employée pour représenter l'Item du menu.
- lpNewItem est le contenu de l'Item, d'après ce que vous avez spécifié dans le membre uFlags. Puisque nous mettons MF_STRING dans le membre uFlags, lpNewItem doit contenir le pointer de la chaîne de caractères qui doit être affichée dans le menu popup.
.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
Nous profitons de cette occasion pour remplir la structure NOTIFYICONDATA. 'IDI_tray' est juste une constante définie au début du code source. Vous pouvez lui donner la valeur que vous souhaitez. Ce n'est pas important puisque on a seulement un seul 'Tray Icon'. Mais si on en avait plusieurs dans notre 'System Tray', on aurait besoin d'IDs uniques pour chaque 'tray icon'. On définit tous les flags suivants dans le membre uFlags parce que nous spécifions une icône (NIF_ICON), nous spécifions un (message sur mesure NIF_MESSAGE et nous spécifions le texte tooltip (NIF_TIP) (Le texte qui est pésenté dans une bulle). WM_SHELLNOTIFY est seulement un message sur mesure (custum) défini comme WM_USER+5. La valeur réelle n'est pas importante tant qu'elle reste unique. Ici, j'emploie l'icône winlogo comme 'tray icon' mais vous pouvez employer n'importe quelle icône dans votre programme. Chargez-le juste en ressource avec LoadIcon et mettez l'handle renvoyé dans le membre hIcon. Finalement, nous mettons (dans szTip) le texte que nous voulons que la bulle affiche lorsque la souris passe au dessus de notre icône.
Nous cachons la fenêtre principale pour donner l'illusion de sa disparition en la "réduisant au minimum en une icône du 'System Tray'".
Ensuite nous appelons Shell_NotifyIcon avec le message NIM_ADD pour ajouter une icône au system tray.
Maintenant notre fenêtre principale est cachée et l'icône est réduite dans le 'System Tray'. Si vous passez la souris au-dessus, vous verrez un tooltip (une bulle) qui montre le texte que nous avons mis dans le membre szTip. Ensuite, si vous double cliquez sur l'icône, la fenêtre principale réapparaîtra et le 'tray icon' disparaîtra.
.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
Quand un événement souris arrive au tray icon (un clique de souris sur notre icône), notre fenêtre reçoit le message WM_SHELLNOTIFY qui est le message fait sur mesure que nous avons déclaré dans le membre uCallbackMessage. Rappelons-nous qu'à la réception de ce message, wParam contient l'ID du 'tray icon' et lParam contient le message actuel de la souris. Dans le code ci-dessus, nous vérifions d'abord si ce message vient du 'tray icon' auquel nous nous intéressons. Si c'est le cas, on vérifie le message actuel de la souris. Puisque nous sommes uniquement intéressés au 'clique droit de la souris' et au "double clique gauche", on s'occupe seulement des messages WM_RBUTTONDOWN et WM_LBUTTONDBLCLK.
Si le message de la souris est WM_RBUTTONDOWN, nous appelons GetCursorPos pour obtenir les coordonnées actuelles du curseur de la souris sur l'écran. Après avoir reçu les données renvoyées par cette fonction, la structure POINT est remplie des coordonnées du curseur de la souris. Par les coordonnées, je veux dire les coordonnées entières sans qu'il n'y ait aucune frontière de fenêtre (on parle vraiment de l'écran dans sa totalité). Par exemple, si la résolution de votre écran est 640*480, le coin 'inférieur droit' de l'écran est x = 639 et y = 479. Si vous voulez convertir les coordonnées de l'écran en coordonnées de fenêtre, utilisez la fonction ScreenToClient.
Cependant, pour notre but, nous voulons afficher le menu popup à la position actuelle du curseur de la souris avec l'appel TrackPopupMenu et cette fonction exige des coordonnées d'écran, nous pouvons donc directement utiliser les coordonnées remplies par GetCursorPos.
TrackPopupMenu
a la syntaxe suivante :
invoke Shell_NotifyIcon,NIM_DELETE,addr note
mov eax,wParam
.if ax==IDM_RESTORE
invoke ShowWindow,hWnd,SW_RESTORE
.else
invoke DestroyWindow,hWnd
.endif
Quand l'utilisateur sélectionne l'Item de 'restoration' du menu, nous enlevons le 'tray icon' en appelant à nouveau Shell_NotifyIcon, cette fois nous spécifions NIM_DELETE comme message. Ensuite, nous rétablissons la fenêtre principale à son état d'origine. Si l'utilisateur choisit l'Item 'de Sortie' du menu, nous enlevons aussi l'icône du 'System tray' et détruisons la fenêtre principale en appelant DestroyWindow.