Tutorial 23: Tray Icon
From UIC
Tutorial 23: Tray Icon
Contents |
| Tutorial 23: Tray Icon | |
|---|---|
| Author: | Iczelion |
| Email: | Translate: nOtEtA |
| Website: | Mirror |
| Date: | 24/02/2009 (dd/mm/yyyy) |
| Level: |
|
| Language: | Italian |
| Comments: | Formattazione Wiki: Antelox |
Introduzione
In questo tutorial, impareremo come mettere le icone nel system tray e come creare/usare un popup menù.
Tools
Essay
Il system tray è la regione rettangolare nella taskbar dove parecchie icone risiedono. Normalmente, vedrete almeno un orologio digitale. Potete anche mettere delle icone nel system tray. Sotto sono riportate le operazione che dovete effettuare per mettere un'icona nel system tray:
1) Riempire una struttura NOTIFYCONDATA che ha i seguenti membri:
- cbSize La dimensione di questa struttura.
- hwnd Handle della finestra che riceverà le notifiche quando un evento del mouse si presenterà sopra l'icona nel tray.
- uID Una costante che è usata come ID dell'icona. Siete voi a decidere questo valore. Nel caso abbiate più di un' icona nel tray, potrete controllare da quale icona nel tray la notifica del mouse proviene.
- uFlags Specifica quali membri di questa struttura sono validi:
■ NIF_ICON Il membro hIcon è valido.
■ NIF_MESSAGE Il membro uCallbackMessage è valido.
■ NIF_TIP Il membro szTip è valido.
- uCallbackMessage Il messaggio da noi dichiarato che Window trasmetterà alla finestra specificata nel membro hwnd quando un' evento del mouse si presenterà sopra l'icona nel tray. Dichiarate voi questo messaggio.
- hIcon L' handle dell'icona che desiderate mettere nel system tray
- szTip Un array di 64-byte che contiene la stringa di testo che sarà usata come tooltip quando il mouse si fermerà sopra l'icona nel tray.
2) Chiamare Shell_NotifyIcon che è definita in shell32.inc. Questa funzione ha il seguente prototipo:
dwMessage è il tipo di messaggio che trasmettete alla shell:
- NIM_ADD Aggiunge un'icona alla status area.
- NIM_DELETE Cancella un'icona dalla status area.
- NIM_MODIFY Modifica un'icona nella status area.
pnid è il puntatore ad una struttura NOTIFYICONDATA riempita di valori adeguati.
Se desiderate aggiungere un'icona al tray, usate il messaggio NIM_ADD, se desiderate rimuovere l'icona, usate NIM_DELETE.
Questo è tutto ciò che si deve conoscere. Ma la maggior parte delle volte, non sarete soddisfatti di mettere appena un'icona nel system tray. Vorrete poter rispondere agli eventi del mouse sopra l'icona nel tray. Potete fare questo elaborando il messaggio che avete specificato nel membro uCallbackMessage della struttura NOTIFYICONDATA. Questo messaggio ha i seguenti valori in wParam ed in lParam (grazie mille a s__d per l'Info):
- wParam contiene l'ID dell'icona. E' lo stesso valore che mettete nel membro uID della struttura NOTIFYICONDATA.
- lParam la low word contiene il messaggio del mouse. Per esempio, se l'utente clicca il tasto destro del mouse sull'icona, lParam conterrà WM_RBUTTONDOWN.
La maggior parte delle icone nel tray, tuttavia, visualizzano un popup menù quando l' utente clicca il tasto destro su di esse. Possiamo implementare questa funzione creando un popup menù e quindi chiamando TrackPopupMenu per visualizzarlo. I punti sono descritti qui sotto:
- Creare un popup menù chiamando CreatePopupMenu. Questa funzione crea un menù vuoto. Restituisce l' handle del menù in eax se riuscita.
- Aggiungere le voci di menù ad esso con AppendMenu, InsertMenu o InsertMenuItem.
- Se desiderate visualizzare il popup menù dove si trova il cursore del mouse, chiamate GetCursorPos per ottenere le coordinate del cursore nello schermo e quindi chiamate TrackPopupMenu per visualizzare il menù. Quando l'utente seleziona una voce del menù, Window trasmette il messaggio WM_COMMAND alla vostra procedura per la finestra come una selezione normale da un menù.
Nota: Attenti a due comportamenti anomali quando usate un popup menù con un'icona nel tray:
- Quando il popup menù è visualizzato, se cliccate dovunque fuori dal menù, il popup menù non sparirà immediatamente come dovrebbe. Questo comportamento accade perché la finestra che riceve le notifiche dal popup menù DEVE essere la finestra dalla priorità più alta. La chiamata di SetForegroundWindow correggerà il problema.
- Dopo aver chiamato SetForegroundWindow, verificherete che in un primo momento il popup menù sarà visualizzato, funzionà bene ma nei momenti successivi, il popup menù si mostrerà e si chiuderà immediatamente. Questo comportamento è " intenzionale ", cito da MSDN. Il passaggio di esecuzione al programma che è il proprietario dell'icona nel tray nell' immediato futuro è necessario per risolvere il problema. Potete forzare questo passaggio di esecuzione postando un messaggio alla finestra del programma. Usate PostMessage, non SendMessage!
Esempio
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\shell32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\shell32.lib
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
Analisi
Il programma visualizzerà una finestra semplice. Quando premerete il tasto di minimizzazione, essa si nasconderà e metterà un'icona nel system tray. Quando farete un doppio-click sull'icona, la finestra si rimostrerà e rimuoverà l'icona dal system tray. Quando farete un click con il pulsante destro sull' icona, un popup menù sarà visualizzato. Potrete scegliere se rivisualizzare la finestra o uscire da esso.
invoke CreatePopupMenu
mov hPopupMenu,eax
invoke AppendMenu,hPopupMenu,MF_STRING,IDM_RESTORE,addr RestoreString
invoke AppendMenu,hPopupMenu,MF_STRING,IDM_EXIT,addr ExitString
Quando la finestra principale è stata creata, il programma creerà un popup menù e collegherà due voci di menù. AppendMenu ha la seguente sintassi:
- hMenu è l' handle del menù a cui desiderate collegare la voce di menù
- uFlags dice a Window se la voce di menù che deve essere collegata sarà una bitmap o una stringa o una voce owner-draw, abilitata, oscurata o inattiva ecc. Potete ottenere la lista completa dal riferimento win32 api. Nel nostro esempio, usiamo MF_STRING che significa che la voce di menù è una stringa.
- uIDNewItem è l'ID della voce di menù. Questo è un valore dichiarato dal programmatore che è usato per rappresentare la voce di menù.
- lpNewItem specifica il contenuto della voce di menù, in base a cosa specificate nel membro uFlags. Poiché specifichiamo MF_STRING nel membro uFlags, lpNewItem deve contenere il puntatore alla stringa da visualizzare nel popup menù.
Dopo che il popup menù è stato creato, la finestra principale aspetta pazientemente che l'utente prema il tasto minimizza. Quando una finestra è minimizzata, riceve il messaggio WM_SIZE con il valore SIZE_MINIMIZED in wParam.
.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
Usiamo questa occasione per riempire la struttura NOTIFYICONDATA. IDI_TRAY è una costante definita all'inizio del codice sorgente. Potete settarla con qualunque valore gradite. Non è importante perché avete soltanto un' icona nel tray. Ma se metteste parecchie icone nel system tray, avreste bisogno di un ID unico per ogni icona del tray. Impostiamo tutti i flags nel membro uFlags perché specifichiamo un'icona (NIF_ICON), specifichiamo un nostro messaggio (NIF_MESSAGE) e specifichiamo il testo del tooltip (NIF_TIP). WM_SHELLNOTIFY è giusto un nostro messaggio definito come WM_USER+5. Il valore reale non è importante a condizione che sia unico. Nell' esempio uso l'icona winlogo per il tray ma potete usare qualsiasi icona del vostro programma. Carichiamo essa dalle risorse con LoadIcon e mettiamo l' handle restituita nel membro hIcon. Infine, riempiamo szTip con il testo che desideriamo che la shell visualizzi quando il mouse è sopra l'icona. Nascondiamo la finestra principale per dare l'illusione di una " minimizzazione-a-icona-nel tray ". Successivamente chiameremo Shell_NotifyIcon con il messaggio NIM_ADD per aggiungere l'icona al system tray.
Ora la nostra finestra principale è nascosta e l'icona è nel system tray. Se passate il mouse sopra ad essa, vedrete un tooltip che visualizza il testo che abbiamo messo nel membro szTip. Successivamente, se fate un doppio-click sull' icona, la finestra principale riapparirà e l'icona nel tray sparirà.
.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
Quando un evento del mouse si presenta sopra l'icona nel tray, la vostra finestra riceve il messaggio WM_SHELLNOTIFY che è il messaggio che avete specificato nel membro uCallbackMessage. Ricordatevi che alla ricezione di questo messaggio, wParam contiene l'ID dell'icona nel tray e lParam contiene il messaggio reale del mouse. Nel codice qui sopra, controlliamo in primo luogo se il messaggio che proviene dall'icona che è nel tray ci interessa. Se è così, controlliamo il messaggio reale del mouse. Poiché siamo soltanto interessati al click destro e al doppio-click-sinistro del mouse, elaboriamo soltanto i messaggi WM_RBUTTONDOWN e WM_LBUTTONDBLCLK. Se il messaggio del mouse è WM_RBUTTONDOWN, chiamiamo GetCursorPos per ottenere le coordinate correnti del cursore del mouse nello schermo. Quando la funzione ritorna, la struttura POINT contiene le coordinate del cursore del mouse nello schermo. Per coordinate nello schermo, intendo le coordinate dell' intero schermo senza considerare nessun contorno di finestra. Per esempio, se la risoluzione dello schermo è 640*480, l' angolo di destra-più basso dello schermo è x==639 e y==479. Se desiderate convertire le coordinate nello schermo in coordinate della finestra, usate la funzione ScreenToClient. Tuttavia, per il nostro scopo, desideriamo visualizzare il popup menù all' attuale posizione del cursore del mouse con la chiamata di TrackPopupMenu che richiede le coordinate nello schermo, noi possiamo usare le coordinate restituite direttamente da GetCursorPos. TrackPopupMenu ha la seguente sintassi:
- hMenu è l' handle del popup menù da visualizzare;
- uFlagsspecifica le opzioni della funzione. Come dove posizionare il menù in relazione alle coordinate specificate successivamente e quale tasto del mouse sarà utilizzato per richiamare il menù. Nel nostro esempio, usiamo TPM_RIGHTALIGN per posizionare il popup menù alla sinistra delle coordinate.
- x e y specificano la posizione del menù nelle coordinate dello schermo.
- nReserved deve essere NULL
- hWnd è l' handle della finestra che riceverà i messaggi dal menù.
- prcRect è il rettangolo nello schermo in cui è possibile cliccare senza far sparire il menù. Normalmente noi mettiamo NULL qui così quando l'utente clicca dovunque fuori dal popup menù, il menù sparisce.
Quando l' utente fa' un doppio-click sull'icona nel tray, noi trasmettiamo il messaggio WM_COMMAND alla nostra finestra specificando IDM_RESTORE per emulare la seleziona della voce di menù Restore da parte dell' utente e quindi rivisualizzare la finestra principale e rimuovere l'icona dal system tray. Per poter ricevere il messaggio di doppio click, la finestra principale deve avere lo stile CS_DBLCLKS.
mov eax,wParam
.if ax==IDM_RESTORE
invoke ShowWindow,hWnd,SW_RESTORE
.else
invoke DestroyWindow,hWnd
.endif
Quando l'utente seleziona la voce di menù Restore, rimuoviamo l'icona dal tray chiamando ancora Shell_NotifyIcon, questo volta però specifichiamo NIM_DELETE come messaggio. Quindi, ristabiliamo la finestra principale alla relativa condizione originale. Se l'utente seleziona la voce di menù Exit, rimuoviamo ancora l'icona dal tray e distruggiamo la finestra principale chiamando DestroyWindow.
Disclaimer
I documenti qui pubblicati sono da considerarsi pubblici e liberamente distribuibili, a patto che se ne citi la fonte di provenienza. Tutti i documenti presenti su queste pagine sono stati scritti esclusivamente a scopo di ricerca, nessuna di queste analisi è stata fatta per fini commerciali, o dietro alcun tipo di compenso. I documenti pubblicati presentano delle analisi puramente teoriche della struttura di un programma, in nessun caso il software è stato realmente disassemblato o modificato; ogni corrispondenza presente tra i documenti pubblicati e le istruzioni del software oggetto dell'analisi, è da ritenersi puramente casuale. Tutti i documenti vengono inviati in forma anonima ed automaticamente pubblicati, i diritti di tali opere appartengono esclusivamente al firmatario del documento (se presente), in nessun caso il gestore di questo sito, o del server su cui risiede, può essere ritenuto responsabile dei contenuti qui presenti, oltretutto il gestore del sito non è in grado di risalire all'identità del mittente dei documenti. Tutti i documenti ed i file di questo sito non presentano alcun tipo di garanzia, pertanto ne è sconsigliata a tutti la lettura o l'esecuzione, lo staff non si assume alcuna responsabilità per quanto riguarda l'uso improprio di tali documenti e/o file, è doveroso aggiungere che ogni riferimento a fatti cose o persone è da considerarsi PURAMENTE casuale. Tutti coloro che potrebbero ritenersi moralmente offesi dai contenuti di queste pagine, sono tenuti ad uscire immediatamente da questo sito.
Vogliamo inoltre ricordare che il Reverse Engineering è uno strumento tecnologico di grande potenza ed importanza, senza di esso non sarebbe possibile creare antivirus, scoprire funzioni malevole e non dichiarate all'interno di un programma di pubblico utilizzo. Non sarebbe possibile scoprire, in assenza di un sistema sicuro per il controllo dell'integrità, se il "tal" programma è realmente quello che l'utente ha scelto di installare ed eseguire, né sarebbe possibile continuare lo sviluppo di quei programmi (o l'utilizzo di quelle periferiche) ritenuti obsoleti e non più supportati dalle fonti ufficiali.