Zoom Icon

Tutorial 8: I Menu

From UIC

Tutorial 8: I Menu

Contents


Tutorial 8: I Menu
Author: Iczelion
Email: Traduttore: -NeuRaL_NoiSE
Website: Mirror
Date: 01/01/2001 (dd/mm/yyyy)
Level: Working brain required
Language: Italian Flag Italian.gif
Comments:



Introduzione

In questo tutorial, impareremo come incorporare un menu nella nostra finestra.

Preliminari

Il Menu e' uno dei componenti piu' importanti nella vostra finestra. Il menu presenta una lista dei servizi che il programma offre all'utente. L'utente non deve necessariamente leggere il manuale incluso con il programma per poterlo usare, puo' sperimentare con i menu per avere una visione generale delle capacita' di un determinato programma, e pertanto cominciare a sfruttarlo immediatamente. Dal momento che un menu e' un mezzo per mettere l'utente a suo agio e fargli cominciare subito ad utilizzare il programma, dovreste seguire gli standard. In poche parole, i primi due menu items dovrebbero essere File ed Edit e l'ultimo dovrebbe essere Help. Potete inserire i vostri menu tra Edit ed Help. Se un menu item chiama una dialog box, dovreste aggiungere dei puntini sospensivi (...) alla stringa con il nome del menu. I menu sono una specie di resource (risorsa, NdT). Ci sono diversi tipi di resources, come il dialog box, la string table, le icone, i bitmap, i menu ecc. Le resources sono definite in un file separato chiamato "resource file", che normalmente ha un'estensione .rc. Voi quindi combinate le resources con il codice al momento del link. Il prodotto finale e' un file eseguibile che contiene sia le istruzioni che le resources. Potete scrivere scripts per le resources usando qualsiasi editor di testo. Essi sono composti di frasi che descrivono l'aspetto e altri attributi delle resources usate in un determinato programma. Nonostante possiate utilizzare un editor di testo per scrivere i resource scripts, cio' e' abbastanza difficile. Una scelta migliore e' quella di utilizzare un editor di risorse (resource editor), che vi permette di creare visualmente qualsiasi resource con semplicita'. I resource editors sono spesso inclusi nei package dei compilatori, come nel Visual C++, Borland C++, ecc. Essi scrivono il resource file per voi. Descrivete una menu resource in questo modo:

MyMenu MENU
{
[qui va la lista dei menu]
}

Chi programma in C potrebbe riconoscere che il procedimento e' simile alla dichiarazione di una structure. MyMenu e' il menu name, seguito dalla keyword MENU e la lista dei menu tra parentesi graffe. In alternativa, potete usare BEGIN e END invece delle parentesi graffe, se volete. Questa sintassi e' piu' consona a chi programma in Pascal. La lista dei menu puo' contenere sia statements MENUITEM che statements POPUP. Lo statement MENUITEM definisce una barra di menu che non chiama un menu di popup quando viene selezionato. La sintassi e' la seguente:

MENUITEM "&testo", ID [,opzioni]

Si comincia con la keyword MENUITEM seguita dal testo che volete usare come nome del menu. Notate l'amperstand (il simbolo "&", NdT). Esso fa si che il carattere successivo sia sottolineato. Dopo la stringa di testo, c'e' la ID del menu item. La ID e' un numero che verra' usato per identificare il menu item nel messaggio inviato alla window procedure quando il menu item viene selezionato. Pertanto, le ID di menu devono essere uniche tra di loro. Le opzioni sono opzionali ( :-), NdT). Le opzioni disponibili sono queste:

  • GRAYED Il menu item e' disattivato, e non genera un messaggio WM_COMMAND. Il testo e' grigio (per intenderci, quello dei menu non selezionabili, NdT).
  • INACTIVE Il menu item e' disattivato, e non genera un messaggio WM_COMMAND. Il testo viene mostrato normalmente.
  • MENUBREAK Questo item e gli items successivi appaiono su una linea nuova nel menu.
  • HELP Questo item e gli items successivi sono giustificati a destra.

Potete usare una delle opzioni di cui sopra o combinarle con l'operatore "or". Ricordatevi pero' che INACTIVE e GRAYED non possono essere combinati. Lo statement POPUP ha la seguente sintassi:

POPUP "&testo" [,opzioni]
{
[lista dei menu]
}

Lo statement POPUP definisce una barra di menu che, quando selezionata, apre una lista di menu items in una piccola finestra di popup. La lista dei menu puo' essere di tipo MENUTIEM o POPUP. C'e' un tipo speciale di statement MENUITEM, e cioe' MENUITEM SEPARATOR, che disegna una linea orizzontale nella finestra di popup. Il passo successivo, una volta terminato il menu resource script, e' di riferirvisi dal vostro programma. Potete farlo in due posti diversi del programma.

  • Nel membro lpszMenuName della struttura WNDCLASSEX. Ad esempio, se avete un menu chiamato "FirstMenu", potete assegnare il menu alla vostra finestra in questo modo:
.DATA
MenuName db "FirstMenu",0
. . .
. . .
.CODE
. . .
mov wc.lpszMenuName, OFFSET MenuName
. . .
  • Nel parametro "menu handle" di CreateWindowEx, in questo modo:
.DATA
MenuName db "FirstMenu",0
hMenu HMENU ?
. . .
. . .
.CODE
. . .
invoke LoadMenu, hInst, OFFSET MenuName
mov hMenu, eax
invoke CreateWindowEx,NULL,OFFSET ClsName,\
OFFSET Caption, WS_OVERLAPPEDWINDOW,\
CW_USEDEFAULT,CW_USEDEFAULT,\
CW_USEDEFAULT,CW_USEDEFAULT,\
NULL,\
hMenu,\
hInst,\
NULL\
. . .

A questo punto potreste chiedervi, qual'e' la differenza tra questi due metodi ?
Quando riferite un menu nella struttura WNDCLASSEX, il menu diventa il menu predefinito, di "default", per la window class. Ogni finestra di quella class avra' lo stesso menu. Se volete che ogni finestra creata dalla stessa class abbia menu diversi, dovete scegliere il secondo metodo. In questo caso, qualsiasi finestra a cui e' passato un menu handle nella funzione CreateWindowEx avra' un menu che "sovrascrive" il menu di default definito nella struttura WNDCLASSEX. Successivamente esamineremo in che modo un menu notifica alla window procedure che l'utente seleziona un menu item. Quando l'utente seleziona un menu item, la window procedure ricevera' un messaggio WM_COMMAND. La low word di wParam contiene la menu ID del menu item selezionato. A questo punto abbiamo abbastanza informazioni per creare ed usare un menu. Facciamolo.

Contenuto

Il primo esempio mostra come creare ed usare un menu specificando il nome del menu nella window class.

include windows.inc <br>
includelib user32.lib <br>
includelib kernel32.lib <br>
includelib gdi32.lib <br>
.data <br>
ClassName db "SimpleWinClass",0 <br>
AppName db "Our First Window",0 <br>
MenuName db "FirstMenu",0 //; Il nome del nostro menu nel resource file. <br>
Test_string db "You selected Test menu item",0 <br>
Hello_string db "Hello, my friend",0 <br>
Goodbye_string db "See you again, bye",0 <br>
.data? <br>
hInstance HINSTANCE ? <br>
CommandLine LPSTR ? <br>
.const <br>
IDM_TEST equ 1 //; le Menu IDs <br>
IDM_HELLO equ 2 <br>
IDM_GOODBYE equ 3 <br>
IDM_EXIT equ 4 <br>
.code <br>
start: <br>
invoke GetModuleHandle, NULL <br>
mov hInstance,eax <br>
invoke GetCommandLine <br>
invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT <br>
invoke ExitProcess,eax <br>
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:SDWORD <br>
LOCAL wc:WNDCLASSEX <br>
LOCAL msg:MSG <br>
LOCAL hwnd:HWND <br>
mov wc.cbSize,SIZEOF WNDCLASSEX <br>
mov wc.style, CS_HREDRAW or CS_VREDRAW <br>
mov wc.lpfnWndProc, OFFSET WndProc <br>
mov wc.cbClsExtra,NULL <br>
mov wc.cbWndExtra,NULL <br>
push hInstance <br>
pop wc.hInstance <br>
mov wc.hbrBackground,COLOR_WINDOW+1 <br>
mov wc.lpszMenuName,OFFSET MenuName //; Mettete il nostro nome qui<br>
mov wc.lpszClassName,OFFSET ClassName <br>
invoke LoadIcon,NULL,IDI_APPLICATION <br>
mov wc.hIcon,eax <br>
mov wc.hIconSm,0 <br>
invoke LoadCursor,NULL,IDC_ARROW <br>
mov wc.hCursor,eax <br>
invoke RegisterClassEx, addr wc <br>

invoke CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\ <br>
WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\ <br>
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\ <br>
hInst,NULL <br>

mov hwnd,eax <br>
invoke ShowWindow, hwnd,SW_SHOWNORMAL <br>
invoke UpdateWindow, hwnd <br>
.WHILE TRUE <br>
invoke GetMessage, ADDR msg,NULL,0,0 <br>
.BREAK .IF (!eax) <br>
invoke DispatchMessage, ADDR msg <br>
.ENDW <br>
mov eax,msg.wParam <br>
ret <br>
WinMain endp <br>
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM <br>
mov eax,uMsg <br>
.IF eax==WM_DESTROY <br>
invoke PostQuitMessage,NULL <br>
.ELSEIF eax==WM_COMMAND <br>
mov eax,wParam <br>
.IF ax==IDM_TEST <br>
invoke MessageBox,NULL,ADDR Test_string,OFFSET AppName,MB_OK <br>
.ELSEIF ax==IDM_HELLO <br>
invoke MessageBox, NULL,ADDR Hello_string, OFFSET AppName,MB_OK <br>
.ELSEIF ax==IDM_GOODBYE <br>
invoke MessageBox,NULL,ADDR Goodbye_string, OFFSET AppName, MB_OK <br>
.ELSE <br>
invoke DestroyWindow,hWnd <br>
.ENDIF <br>
.ELSE <br>
invoke DefWindowProc,hWnd,uMsg,wParam,lParam <br>
ret <br>
.ENDIF <br>
xor eax,eax <br>
ret <br>
WndProc endp <br>
end start <br>


//***********************
Menu.rc
//***********************
&#35;define IDM_TEST 1
&#35;define IDM_HELLO 2
&#35;define IDM_GOODBYE 3
&#35;define IDM_EXIT 4
FirstMenu MENU
{
POPUP "&PopUp"
{
MENUITEM "&Say Hello",IDM_HELLO
MENUITEM "Say &GoodBye", IDM_GOODBYE
MENUITEM SEPARATOR
MENUITEM "E&xit",IDM_EXIT
}
MENUITEM "&Test", IDM_TEST
}

Analizziamo prima il resource file.

&#35;define IDM_TEST 1 ///* uguale a IDM_TEST equ 1*/
&#35;define IDM_HELLO 2
&#35;define IDM_GOODBYE 3
&#35;define IDM_EXIT 4

Queste righe definiscono le menu IDs usate dal menu script. Potete assegnare qualsiasi valore alle ID sempre che tale valore sia unico nel menu.

FirstMenu MENU

Dichiara il vostro menu con la keyword MENU.

POPUP "&PopUp"
{
MENUITEM "&Say Hello",IDM_HELLO
MENUITEM "Say &GoodBye", IDM_GOODBYE
MENUITEM SEPARATOR
MENUITEM "E&xit",IDM_EXIT
}

Definiscono un menu a popup con quattro menu items, di cui il terzo e' un menu separator.

MENUITEM "&Test", IDM_TEST

Definisce una barra di menu nel menu principale.
Successivamente esamineremo il codice:

MenuName db "FirstMenu",0 //; Il nome del nostro menu nel resource file.
Test_string db "You selected Test menu item",0
Hello_string db "Hello, my friend",0
Goodbye_string db "See you again, bye",0

MenuName e' il nome del menu nel resource file. Notate che potete definire piu' di un menu nel resource file, pertanto dovete specificare quale menu usare. Le restanti tre righe definiscono le stringe testuali che devono essere mostrate in message boxes, che vengono chiamate quando l'appropriato menu item viene selezionato dall'utente.

IDM_TEST equ 1 //; Le Menu IDs
IDM_HELLO equ 2
IDM_GOODBYE equ 3
IDM_EXIT equ 4

Definiscono le menu IDs per poterle utilizzare nella window procedure. Questi valori DEVONO essere identici a quelli definiti nel resource file.

.ELSEIF eax==WM_COMMAND
mov eax,wParam
.IF ax==IDM_TEST
invoke MessageBox,NULL,ADDR Test_string,OFFSET AppName,MB_OK
.ELSEIF ax==IDM_HELLO
invoke MessageBox, NULL,ADDR Hello_string, OFFSET AppName,MB_OK
.ELSEIF ax==IDM_GOODBYE
invoke MessageBox,NULL,ADDR Goodbye_string, OFFSET AppName, MB_OK
.ELSE
invoke DestroyWindow,hWnd
.ENDIF

Nella window procedure, elaboriamo i messaggi WM_COMMAND. Quando l'utente seleziona un menu item, la menu ID di quel menu item e' inviata alla window procedure nella low word di wParam assieme al messaggio WM_COMMAND. Pertanto quando salviamo il valore di wParam in eax, compariamo il valore in ax alle menu IDs che abbiamo definito in precedenza e ci comportiamo di conseguenza. Nei primi tre casi, quando l'utente sceglie i menu items Test, Say Hello, e Say GoodBye, noi mostreremo semplicemente una stringa di testo in una message box. Se l'utente seleziona il menu item Exit, chiamiamo DestroyWindow con l'handle della nostra finestra come parametro, il che chiudera' la nostra finestra. Come potete vedere, specificare un nome di menu in una window class e' un'operazione abbastanza semplice e diretta. Comunque potete anche utilizzare un metodo alternativo per caricare un menu nella vostra finestra. Non vi mostrero' l'intero codice qui. Il resource file e' identico con entrambi i metodi. Ci sono solo alcuni piccoli cambiamenti nel file sorgente che vi mostrero' qui sotto.

.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
hMenu HMENU ? //; handle del nostro menu

Definisce una variabile di tipo HMENU per conservare l'handle del nostro menu.

invoke LoadMenu, hInst, OFFSET MenuName
mov hMenu,eax
INVOKE CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\
WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,hMenu,\
hInst,NULL

Prima di chiamare CreateWindowEx, chiamiamo LoadMenu con l'instance handle e un puntatore al nome del nostro menu. LoadMenu restituisce l'handle del nostro menu nel resource file che poi passiamo a CreateWindowEx.


Note finali

Questi tutorials erano presenti nel sito di RingZero. Li rimettiamo a disposizione a chiunque voglia poter leggerli nella loro traduzione in italiano che fu curata da NeuralNoise.

phobos


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.