Guide e Tutorials:indexed
La funzione InsertMenuItem (Tutorial completo)

La funzione in questione aggiunge semplicemente una voce ad un menu. La figura sottostante mostra l'esempio di un progetto nel quale abbiamo una barra-menu composta da due voci: "Menu1" e "Menu2". Applicando la funzione InsertMenuItem siamo risusciti a posizionatre la voce "Menu 1/2" tra "Menu1" e "Menu2":


Naturalmente come molti si aspetteranno, è possibile non solo inserire stringhe alfanumeriche, ma anche altri oggetti che vedremo in seguito.
Prima di tutto vediamo come si dichiara la funzione InsertMenuItem:

Declare Function InserMenuItem Lib "user32.dll" Alias "InsertMenuItemA" _
(ByVal hMenu As Long, ByVal fByPosition As Long, ByVal lpmii As MENUITEMINFO) _
As Long

La dichiarazione che abbiamo appena visto si presta ad un'ampia analisi che ci permette di ritornare sopra l'argomento trattato nella lezione "La dichiarazione delle API". InsertMenuItem dichiarata così come abbiamo fatto, necessita di ben tre parametri in forma numerica (infatti sia hMenu che fByPosition che lpmii, sono dichiarati As Long ossia come numeri interi a 32 bit) i cui valori sono passati ByVal alla funzione. E questa ritornerà alla fine un quarto intero. E' interessante notare la voce: Alias InsertMenuItemA che richiama ciò che abbiamo detto nella lezione DICHIARARE LE API. Trascriviamo qui di seguito il paragrafo che ci interessa, tanto per rinfrescarci la memoria:

alias_funzione
[...] Questa voce è opzionale. Corrisponde al nome "ufficiale" della funzione come appare nel file .DLL. E' importante perchè quasi tutte le API aventi una stringa come parametro hanno due versioni: la versione ANSI (utilizzata dalla maggior parte delle lingue comunemente parlate) e la versione Unicode a caratteri estesi (utilizzata ad esempio dal Cinese). Quando una funzione è presente in un file .DLL con entrambe le sue versioni, il suo nome è leggermente diverso: la versione ANSI terminerà con la lettera A (Ansi) e la versione Unicode con la lettera W (Wide-character, ossia carattere esteso). Ad esempio se andiamo a vedere quel file di estensione .DLL che contiene la funzione API CompareString, vedremo che le due versioni saranno chiamate CompareStringA e CompareStringW. [...]

Terminata l'analisi della struttura dell'API, andiamo a scoprire in dettaglio che operazione può compiere. Come già visto InsertMenuItem non fa altro che aggiungere un oggetto-menu (dove come già spiegato oggetto-menu è uno tra i tanti oggetti che possono comporre una voce di un menu: una stringa alfanumerica, una linea di interruzione, una bitmap e così via) ad un menu già esistente. Tramite la manipolazione della funzione è inoltre possibile determinare la posizione nella quale inserire il nostro oggetto-menu. Analizzando inoltre il valore ritornato, si può scoprire a priori se la funzione ha ottenuto l'effetto desiderato. Se infatti InsertMenuItem ritorna un valore diverso da 0, allora è tutto a posto. Avere un valore pari a 0 determina l'errore. Errore che si rivela molto meno pesante di quello che si verifica utilizzando la funzione GetSystemMenu che come già visto nella lezione GETSYTEMMENU, dà come risultato il numero che identifica il menu della finestra. Dunque la probabilità di un crash del sistema sarà molto minore.

Una cosa importante da tenere a mente è che nel momento in cui si aggiunge una nuova voce al menu, non è possibile per Visual Basic creare una sottoprocedura (o routine) legata all'evento. Questo significa in poche parole che se ad esempio, premendo un tasto, l'utente farà comparire una nuova voce nel menu principale della finestra, la pressione di tale voce non produrrà alcun effetto in quanto non esisterà nel codice alcuna sottoprocedura ad essa associata. E non potrà nemmeno essere aggiunta a priori in quanto si riceverà un messaggio di errore (in quanto l'oggetto è inizialmente non definito). Sarà allora necessario processare manualmente il messaggio (del tipo WM_COMMAND o WM_SYSCOMMAND) che proviene dalla pressione della voce del menu.

I parametri necessari all'operare della funzione sono i seguenti:

hMenu E' l'indicatore del menu nel quale si intende aggiungere l'oggetto-menu. Per curiosità e per rendersi conto di che valore assuma tale indicatore, provare ad inserire in un modulo la dichiarazione della funzione GETMENU o della funzione GETSYSTEMMENU:
Declare Function GetMenu Lib "user32.dll" (ByVal hWnd As Long) _
As Long
e nella form, all'interno della sottoprocedura che preferite, scrivere:
Dim RetVal As Long
RetVal = GetMenu (Form1.hWnd)
MsgBox RetVal
dove RetVal è il Return Value, ossia il valore che la funzione ritorna.
uItem Identifica l'oggetto-menu che appare immediatamente prima della posizione nella quale si vuole aggiungere il nuovo oggetto-menu. uItem può indicare una posizione, la posizione occupata dall'oggetto-menu, oppure l'identificatore dell'oggetto-menu: la cosa dipende da fByPosition.
fByPosition Se questo parametro ha un valore strettamente diverso da 0, allora la posizione dell'oggetto-menu indicato da uItem è calcolata partendo dal valore 0 (quindi la prima voce avrà posizione 0, la seconda 1, e così via). Se invece fByPosition è proprio 0, allora uItem rappresenta l'identificatore dell'oggetto-menu
lpmii Descrive la tipologia di oggetto-menu da inserire. Per sapere quali tipi di oggetti-menu sono a disposizione, fare riferimento alla lezione LA STRUTTURA MENUITEMINFO.


Adesso passiamo all'esempio. Vogliamo aggiungere la voce "&Menu1/2" tra due voci già esistenti, ossia "&Menu1 e "&Menu2". Nel modulo inseriamo allora la struttura MENUITEMINFO, la dichiarazione della GetMenu e la dichiarazione della funzione InsertMenuItem:

Type MENUITEMINFO
cbSize As Long
fMask As Long
fType As Long
fState As Long
wID As Long
hSubMenu As Long
hbmpChecked As Long
hbmpUnchecked As Long
dwItemData As Long
dwTypeData As String
cch As Long
End Type
Public Const MIIM_STATE = &H1
Public Const MIIM_ID = &H2
Public Const MIIM_TYPE = &H10
Public Const MFT_SEPARATOR = &H800
Public Const MFT_STRING = &H0
Public Const MFS_ENABLED = &H0
Public Const MFS_CHECKED = &H8
Declare Function GetMenu Lib "user32.dll" (ByVal hWnd As Long) As Long
Declare Function InserMenuItem Lib "user32.dll" Alias "InsertMenuItemA" _
(ByVal hMenu As Long, ByVal fByPosition As Long, ByVal lpmii As MENUITEMINFO) _
As Long

Sempre all'interno del modulo inseriamo la funzione creata da noi, alla quale passeremo il numero che identifica il menu all'interno del quale vogliamo inserire l'oggetto-menu (hMenu):

Sub InserisciOggetto (ByVal hMenu As Long)
End Sub

al cui interno dichiareremo a variabile che c'interessa manipolare prima di passarla alla funzione API InsertMenuItem ossia mii:

Dim mii As MENUITEMINFO

Adesso impostiamo le proprietà di mii. Per avere una visione più completa di quali sono le proprietà che possono essere associate al parametro, fare riferimento alla lezione MENUITEMINFO:

With mii
.cbSize = Len(mii)
.fMask = MIIM_STATE Or MIIM_TYPE Or MIIM_SUBMENU
.dwTypeData = "&Menu 1/2"
.fType = MFT_STRING
End With

cosa che può essere agevolmente fatta in modo equivalente ma questa volta senza l'utilizzo di With, in questo modo:

mii.cbSize = Len(mii)
mii.fMask = MIIM_STATE Or MIIM_TYPE Or MIIM_SUBMENU
mii.dwTypeData = "&Menu1/2"
mii.fType = MFT_STRING

per finire richiamiamo la funzione InsertMenuItem con un bel:

Call InsertMenuItem(hMenu, 1, 1, mii)

Ecco come si presenterà dunque il modulo completo:

Type MENUITEMINFO
cbSize As Long
fMask As Long
fType As Long
fState As Long
wID As Long
hSubMenu As Long
hbmpChecked As Long
hbmpUnchecked As Long
dwItemData As Long
dwTypeData As String
cch As Long
End Type
Public Const MIIM_STATE = &H1
Public Const MIIM_ID = &H2
Public Const MIIM_TYPE = &H10
Public Const MFT_SEPARATOR = &H800
Public Const MFT_STRING = &H0
Public Const MFS_ENABLED = &H0
Public Const MFS_CHECKED = &H8
Declare Function GetMenu Lib "user32.dll" (ByVal hWnd As Long) As Long
Declare Function InserMenuItem Lib "user32.dll" Alias "InsertMenuItemA" _
(ByVal hMenu As Long, ByVal fByPosition As Long, ByVal lpmii As MENUITEMINFO) _
As Long

Sub InserisciOggetto (ByVal hMenu As Long)
Dim mii As MENUITEMINFO
With mii
.cbSize = Len(mii)
.fMask = MIIM_STATE Or MIIM_TYPE Or MIIM_SUBMENU
.dwTypeData = "&Menu1/2"
.fType = MFT_STRING
End With
Call InsertMenuItem(hMenu, 1, 1, mii)
End Sub

infine nell'evento Load della Form:

Option Explicit
Private Sub Form_Load()
Dim hMenu As Long
hMenu = GetMenu(Form1.hWnd)
InserisciOggetto hMenu
End Sub

che determina il valore identificativo del menu principale di Form1 e lo passa alla funzione GetMenu. Infine si richiama la nostra procedura InserisciOggetto, passando anche a lei il parametro hMenu.
Il risultato è che, nonostante si siano impostate due voci nella barra-menu principale, ossia "&Menu1" e "&Menu2", comparirà una terza voce posta in mezzo alle precedenti, cioè "&Menu1/2". La posizione nella quale far comparire la voce può essere agevolmente modificata tramite il parametro uItem.

Archivio:ndexed
Lezioni Commenta questa lezione Invia la tua guida Avviso per le nuove lezioni
Proponi un argomento

Visual Basic Italia© copyright 2000 - tutti i diritti riservati
E-mail:
vbitalia@libero.it