Le API co VB - Alla directory superiore

Transcript

Le API co VB - Alla directory superiore
Collana online "i .pdf DI VISUAL BASIC ITALIA"
GUIDA COMPLETA ALLE API: DAI CONCETTI BASE A QUELLI AVANZATI
Collana online "i .pdf DI VISUAL BASIC ITALIA"
Q u e s t o corso come t u t t i quelli pubblicati d a Visual Basic Italia
è disponibile in formato html al sito Visual Basic Italia.
I diritti sui contenuti s p e t t a n o perciò all'a u t o r e degli stessi.
GUIDA COMPLETA ALLE API: DAI CONCETTI BASE A QUELLI AVANZATI
Q u e s t a guida h a lo scopo di fornire u n o s t r u m e n t o di studio molto chiaro
e semplice su concetti spesso a s t r a t t i e n o n immediati come s o n o le API.
Sono stati già scritti molti articoli a riguardo (i più validi sicuramente in
lingua inglese) ma molto spesso ci si t r o v a davanti a testi incomprensibili
che d e n o t a n o u n o scarso approfondimento dell'a r g o m e n t o . Lo scopo
di u n articolo d o v r e b b e essere infatti quello di r e n d e r e i concetti
accessibili a t u t t i ma n o n è sempre così.
1. LE A P I: SGUARDO GENERALE
Che cosa sono?
I n definitiva che cosa s o n o le API? API s t a p e r Application Programming I nterface, e chiaramente laddove
s o n o s t a t e sviluppate n o n h a n n o il ridicolo significato che acquistano nella lingua Italiana. I n pratica come il
t a s t o della calcolatrice che usiamo q u o t i d i a n a m e n t e è l'interfaccia della calcolatrice s t e s s a , le API s o n o le
interfacce a d esempio del sistema operativo. Dove n a t u r a l m e n t e creare u n 'interfaccia significa m e t t e r e in
correlazione l'u t e n t e con (nell'esempio che si è f a t t o ) il sistema operativo. Le API di u n sistema operativo
s o n o la ragione principale p e r cui esiste incompatibilità t r a i vari sistemi presenti sul mercato, basti p e n s a r e
al s o f t w a r e s u p p o r t a t o d a u n sistema operativo p e r Machintosh e quello s u p p o r t a t o d a W i n d o w s . E' possibile
p e r ò r e n d e r e q u e s t o compatibile con quello s o l t a n t o tramite u n emulatore, u n vero e proprio t r a d u t t o r e e d
i n t e r p r e t e delle le API di u n sistema nelle relative API di u n secondo sistema.
A cosa servono?
Le API s o n o le caratteristiche componenti di u n livello di programmazione a v a n z a t o , livello in cui
g e n e r a l m e n t e l'applicazione che creiamo n o n e s e g u e le istruzioni d a solo ma si fa aiutare (o addirittura
d e m a n d a ) d a altri programmi, dicendo loro che cosa d e v o n o fare. Nel caso specifico dei sistemi operativi se
a d esempio sviluppiamo u n 'applicazione allo scopo di scrivere dei dati su u n disco, il n o s t r o programma n o n
completerà le operazioni di scrittura (o e v e n t u a l m e n t e l e t t u r a , ricerca...) dei dati, ma dirà al sistema
operativo p r e s e n t e sulla n o s t r a macchina di scrivere sul disco u n a certa q u a n t i t à di dati (indicandogli
n a t u r a l m e n t e quali). Quali s o n o i v a n t a g g i di u n a soluzione così s t r u t t u r a t a ? I v a n t a g g i s o n o davvero t a n t i .
I n n a n z i t u t t o chi sviluppa u n programma n o n d e v e preoccuparsi di problematiche s t r e t t a m e n t e tecniche come
a d esempio l'accesso al disco, l'allocazione della memoria, e così via, risparmiando alla fine u n a g r a n q u a n t i t à
di t e m p o e riducendo le dimensioni del programma. I n secondo luogo supponiamo che v e n g a sviluppato u n
sistema innovativo di accesso al disco rigido (ma gli esempi p o s s o n o essere di g r a n lunga più banali e quindi
più probabili e frequenti). I n q u e s t o caso il p r o g r a m m a t o r e d o v r e b b e ogni volta procedere all'a g g i o r n a m e n t o
della propria applicazione, d o p o aver s t u d i a t o in m o d o completo come la n u o v a tecnica funziona. Il problema
è risolto dalle API: se il sistema operativo è rinnovato p e r includere anche q u e s t o rivoluzionario accesso ai
dati, qualsiasi programma che utilizzi le API n e t r a r r à grossi v a n t a g g i .
Che cosa fanno?
I n poche parole le API fanno t u t t o ciò che p u ò fare W i n d o w s (o in generale u n sistema operativo). Ed anche
se nei programmi che normalmente sviluppiamo n o n usiamo in m o d o esplicito alcuna funzione del g e n e r e , il
linguaggio di programmazione (in q u e s t o caso Visual Basic), si p e r m e t t e r à di richiamare alcune API p e r
permetterci di o t t e n e r e i risultati che speravamo.
Dove sono?
I n pratica ogni funzione API di W i n d o w s è s i t u a t a in u n file DLL (D ynamic Link Library) a s u a volta p o s t o nella
directory C: \ W i n d o w s \ S y s t e m s o più in gererale laddove è posizionata la directory del sistema operativo.
Q u e s t o file di formato .DLL n o n fanno altro che importare le funzioni API immagazzinandole d e n t r o di sè,
rubandole in poche parole al sistema operativo e rendendole disponibili anche al di fuori. Q u e s t o p e r m e t t e di
utilizzare t u t t e le funzioni del sistema operativo in maniera relativamente semplice, senza bisogno di
difficoltose procedure di accesso al sistema operativo. Il grosso delle funzioni si p o s s o n o t r o v a r e nei files
user32.dll (funzioni di interfaccia u t e n t e ), kernel32.dll (le funzioni principali del sistema operativo), gdi32.dll (le
funzioni di impostazione s t r e t t a m e n t e grafica) e shell32.dll (le funzioni shell).
D a cosa sono composte?
Sebbene ci si riferisca alle API come " funzioni", le funzioni s o n o solo u n a p a r t e delle API di W i n d o w s . La lista
che s e g u e identifica infatti t u t t i gli o g g e t t i che le compongono:
Funzioni
come già accennato le funzioni sono il nucleo delle API di Windows in quanto rappresentano
il modo più potente per svolgere tutte le operazioni messe a disposizione dal sistema
operativo. Come già detto sono racchiuse in files di estensione .dll.
Strutture
Le strutture (come MENUITEMINFO). non fanno altro che raggruppare e conservare gruppi di
informazioni. Questo per permettere alle singole funzioni di poter accedere a tali dati senza
dover essere caricate di un numero eccessivo di parametri.
Costanti
Le API di Windows spesso utilizzano codici numerici per
le informazioni. Dichiarare e nominare tali costanti
corrisponde ad un sistema più veloce e chiaro di fare
riferimento alle informazioni. Spesso le costanti vengono
utilizzate come flags: ogni costante può cioè essere un
flag binario o multiplo, permettendo in questo modo di
archiviare il maggior numero possibile di informazioni.
Funzioni 'callback', di ritorno o di richiamo
In poche parole una chiamata di una funzione è l'opposto di
tale funzione API e viene da essa chiamata in causa
quando esegue i propri comandi.
Messaggi
I messaggi sono particolari costanti: nonostante siano
anch'essi nomi assegnati a particolari valori numerici, si
comportano differentemente. Essi infatti sono inviati agli
oggetti per dire loro di comportarsi in un certo modo.
Mandare un messaggio per se stesso non provoca
nessuna reazione apparente. L'oggetto sarà però istruito a
comportarsi in un determinato modo.
2. LE A P I: R I F E R I M E N T I AD OGGETTI, P U N T A T O R I E COSTANTI (flags)
Gli handles o riferimenti
Come si p u ò indicare al sistema o in m o d o indiretto all'applicazione a quale o g g e t t o riferirsi? Con u n
riferimento a d u n o g g e t t o , cosiddetto handle dell'o g g e t t o . Le API utilizzano tali riferimenti p e r t e n e r e u n a
m a p p a di t u t t i gli o g g e t t i presenti nel p r o g e t t o (ma n o n solo). I n realtà ogni o g g e t t o p r e s e n t e sullo schermo
anche n o n in fase di p r o g e t t a z i o n e h a u n n u m e r o di riferimento. E ciò r a p p r e s e n t a p e r u n p r o g r a m m a t o r e
l'unica possibilità di gestire e manipolare gli o g g e t t i nonchè lo s t a n d a r d disponibile, anche perchè q u e s t o è il
sistema comunemente utilizzato d a W i n d o w s .
I n realtà gli handles s o n o s t r u t t u r e interne a W i n d o w s che al loro interno custodiscono t u t t e le informazioni e
le proprietà di u n o g g e t t o . La loro s t r u t t u r a è composta d a u n n u m e r o intero a 3 2 bit, utilizzato nelle
chiamate API. I n ogni caso, nel m o d o in cui è concepito Visual Basic, n o n c'è grossa differenza in fase iniziale
t r a u n riferimento a d u n o g g e t t o e u n qualsiasi altro semplice intero a 3 2 bit: i riferimenti acquistano valore e
d i v e n t a n o tali nel m o m e n t o in cui v e n g o n o passati come parametri a d u n a funzione API. E del r e s t o n o n ci
s a r e b b e certo necessità di conoscere il n u m e r o identificatore di u n o g g e t t o se n o n fosse possibile associarlo
a d u n a funzione che lo elabori (e che n a t u r a l m e n t e faccia a l t r e t t a n t o con l'o g g e t t o in q u e s t i o n e ...).
Ricapitolando sommariamente q u a n t o d e t t o , la maggior p a r t e degli o g g e t t i s u p p o r t a t i d a W i n d o w s è
accompagnata d a u n n u m e r o di riferimento. La lista di tali o g g e t t i comprende praticamente qualsiasi cosa
appaia sullo schermo: m e n u , pulsanti, finestre, t e x t b o x e così via. Una volta creato u n o degli o g g e t t i
menzionati, viene " attaccato" a tale o g g e t t o u n a particolare proprietà, hWnd che n o n è altro che il n u m e r o di
riferimento a tale o g g e t t o . O meglio a tale finestra. Q u e s t o perchè è d a t e n e r e p r e s e n t e che p e r W i n d o w s i
pulsanti, le forms, le t e x t b o x s o n o considerati speciali tipi di finestre. Ecco perchè possiamo t r a d u r r e h W n d
come handle (of t h e ) W indo w .
Facciamo u n esempio: abbiamo su u n piano (la form) u n p u l s a n t e . Manteniamo le denominazioni degli o g g e t t i
dati p e r default d a Microsoft: Command1 e Form1. Se vogliamo scoprire qual'è l'intero col quale W i n d o w s fa
riferimento a Command1 dal m o m e n t o s t e s s o in cui è s t a t o creato, possiamo utilizzare q u e s t a linea di codice:
MsgBox (Command1.hWnd)
Dando l'avvio all'applicazione a p p a r e u n a finestra di messaggio che rivela il n u m e r o identificatore
dell'o g g e t t o , a d esempio 2 0 2 0 . Richiudendo l'applicazione e riavviandola senza a p p o r t a r e alcuna modifica si
n o t e r à che il riferimento a Command1 è cambiato. Adesso a d esempio è 2 0 3 9 . Q u e s t o avviene in q u a n t o
l'assegnazione del n u m e r o di riferimento all'o g g e t t o n o n avviene nel m o m e n t o in cui l'o g g e t t o viene p o s t o sul
piano, ma nel m o m e n t o in cui l'applicazione viene compilata. Per W i n d o w s infatti u n a serie di o g g e t t i su u n a
form di u n p r o g e t t o in fase di sviluppo n o n significa n i e n t e , e quindi n o n viene considerata.
Lo s t e s s o procedimento p u ò essere applicato a Form1 :
MsgBox (Form1.hWnd)
Anche qui a p r e n d o e richiudendo l'applicazione, il n u m e r o identificatore di Form1 cambia.
Molto simile all'intero di riferimento di u n o g g e t t o è il riferimento a d u n a periferica o a d u n o g g e t t o grafico.
Anche q u e s t o n u m e r o infatti richiama in realtà u n a s t r u t t u r a interna a W i n d o w s che n o n p u ò essere
d i r e t t a m e n t e accessibile d a u n 'applicazione e s t e r n a .
I n ogni caso, come già il n o m e suggerisce, il riferimento a d u n a periferica o a d u n o g g e t t o grafico (o device
context) fa d a intermediario t r a u n 'applicazione (che nello specifico p u ò essere il programma che stiamo
sviluppando in Visual Basic) e d u n a periferica fisica come la t a s t i e r a , il monitor o la s t a m p a n t e , o p p u r e u n
o g g e t t o modificabile dal p u n t o di vista degli attributi grafici. Q u e s t o sistema di gestire le periferiche h a
l'e n o r m e v a n t a g g i o di t r a t t a r e allo s t e s s o m o d o differenti modelli e marche di periferiche. Non sarà
necessario infatti distinguere t r a u n monitor di marca X o di marca Y, in q u a n t o il riferimento al monitor è
identico.
La cosa particolarmente i n t e r e s s a n t e è che in W i n d o w s le s t e s s e finestre s o n o t r a t t a t e allo s t e s s o m o d o
delle periferiche: h a n n o anche loro il n u m e r o di riferimento di periferica (che come il riferimento all'o g g e t t o è
u n intero a 3 2 bit). La possibilità di t r a t t a r e u n a finestra come u n a periferica deriva principalemente dalla
necessità delle API di disegnare su tale finestra e in ogni caso di manipolarne l'e s p e t t o estetico.
I n q u e s t o m o d o p e r s a p e r e qual'è l'intero di riferimento all'o g g e t t o grafico " finestra" si p u ò utilizzare il
s e g u e n t e blocco di codice:
MsgBox (Form1.hDC)
Come mai n o n esiste la proprietà hDC p e r u n o g g e t t o TextBox? Perchè n o n è u n o g g e t t o grafico perciò n o n
p u ò essere t r a t t a t o come tale.
I n o l t r e , poichè i files DLL che custodiscono le API di W i n d o w s s o n o stati creati con l'utilizzo di C+ + , molte
funzioni richiedono di indicare il p u n t a t o r e a q u e s t o o a quell'o g g e t t o , s o t t o f o r m a di p a r a m e t r o .
L'a r g o m e n t o dei p u n t a t o r i è p i u t t o s t o complesso e richiederebbe u n o studio che p e r il m o m e n t o n o n
interessa, visti gli scopi di q u e s t o articolo. Passiamo quindi d i r e t t a m e n t e all'ultimo o g g e t t o dell'analisi: i Flags
Le costanti o flags
Un flag n o n è altro che u n o speciale tipo di c o s t a n t e . Che cosa differisce allora dalle altre costanti?
Principalmente il f a t t o che p o s s o n o essere combinate con altre costanti. Q u e s t o p e r m e t t e di o t t e n e r e
combinazioni multiple utilizzando u n a sola c o s t a n t e , come si farebbe normalmente. Pensiamo infatti che a d
esempio a t t r a v e r s o u n a sola c o s t a n t e flag è possibile passare a d u n a funzione API a d esempio u n a serie di
combinazioni del tipo: on/ off o si/ no come preferite. Q u a n d o si combinano più flags s a r e b b e cosa o p p o r t u n a
utilizzare l'o p e r a t o r e Booleano Or. Q u e s t o infatti previene dal formare u n a combinazione di flags e r r o n e a o
che comunque n o n r a p p r e s e n t a ciò che volevamo (sempre che comunque sia u n a combinazione valida).
Consideriamo a d esempio u n a funzione che accetta u n solo p a r a m e t r o . La funzione fa apparire u n a finestra
di messaggio. Il p a r a m e t r o si riferisce al p u l s a n t e che si vuole far comparire sulla finestra (a d esempio: OK,
OK-Annulla e così via). Un flag combinato che individua il tipo di p u l s a n t e che d e v e apparire p u ò essere a d
esempio:
Const PK_OK = 1
che fa apparire a p p u n t o il p u l s a n t e " OK", o p p u r e :
Const PK_CANCEL = 2
che si riferisce al p u l s a n t e " CANCEL", o ancora:
Const PK_OKCANCEL = 3
che invece farebbe apparire la combinazione di d u e pulsanti: " OK" e " CANCEL". Q u e s t o dimostra perchè u n
flag è u n a combinazione di costanti. Allora nel caso in cui il p r o g r a m m a t o r e volesse richiamare la funzione
assegnandole il p a r a m e t r o PK_OK gli b a s t e r e b b e fare u n a cosa del g e n e r e :
ValoreDiRitorno = Funzione(PK_OK)
Bisogna a q u e s t o p u n t o fare a t t e n z i o n e . Non è possibile infatti richiamare u n a combinazione col s e g n o " + " .
Q u e s t o perchè se a d esempio scriviamo:
ValoreDiRitorno = Funzione(PK_OK + PK_CANCEL)
p e r o t t e n e r e la combinazione dei pulsanti " OK" e " CANCEL", si o t t e r r e b b e u n altro p u l s a n t e (a d esempio "?")
in q u a n t o il + fa la somma di 1 e 2 e n o n di " OK" e " CANCEL". Ecco perchè b a s t e r e b b e allora utilizzare Or
ValoreDiRitorno = Funzione(PK_OK Or PK_CANCEL)
3. LE A P I: D E F I N I Z I O N E ED USO DELLE STRUTTURE
Sguardo generale sul concetto di struttura
Q u e s t o t e r z o capitolo introduce a d u n 'altro i n t e r e s s a n t e a s p e t t o delle API: il concetto di s t r u t t u r a . Di
s t r u t t u r a se n 'è già parlato in precedenza, a d esempio q u a n d o abbiamo visto la composizione della s t r u t t u r a
MENUITEMINFO. Ma n o n n e avevamo mai definito p e r ò in maniera precisa il concetto. Lo faremo a d e s s o . Le
s t r u t t u r e p e r m e t t o n o alle funzioni di ricevere o ritornare u n v a s t o n u m e r o di informazioni senza dover creare
t r o p p a confusione nella lista dei parametri. Per q u e s t a ragione le s t r u t t u r e s o n o organizzate in gruppi che
corrispondono a singoli " pacchetti di informazioni". Non si t r o v e r a n n o quindi s t r u t t u r e l e g a t e a funzioni
p i u t t o s t o semplici. Diverso è p e r ò il caso in cui i parametri dell'API d i v e n t a n o troppi. Proprio p e r q u e s t a
caratteristica a p p e n a vista, le s t r u t t u r e si p o s s o n o definire in via definitiva come oggetti utilizzati per
raggruppare u n ampio numero di variabili tra loro collegate.
Per definire u n a s t r u t t u r a in Visual Basic, si utilizza u n blocco di codice che comincia con Type e termina con
End Type, proprio in q u e s t o m o d o :
Private)] Type **nome**
membro1 As tipo_di_dato1
membro2 As tipo_di_dato2
...
End Type
[(Public |
d o v e l'indicatore Public/ Private come si p u ò immaginare o p e r a allo s t e s s o m o d o delle funzioni. I n generale
p e r ò le s t r u t t u r e s o n o considerate d a Visual Basic come pubbliche (quindi Public) a m e n o che il
p r o g r a m m a t o r e n o n specifichi diversamente. Proseguendo lungo lo studio degli elementi che compongono la
s t r u t t u r a notiamo * * nome* * , che si riferisce al n o m e a s s e g n a t o alla s t r u t t u r a . Un esempio di n o m e è il già
citato MENUITEMINFO. I n secondo luogo abbiamo u n a lista più o m e n o lunga di membri della s t r u t t u r a .
Nell'esempio si s o n o considerati solo membro1 e membro2 ma la lista p u ò continuare anche di parecchio.
Qualsiasi membro r a p p r e s e n t a il n o m e a s s e g n a t o a d u n particolare e specifico membro della s t r u t t u r a d o v e
p e r membro della s t r u t t u r a si indica u n a variabile c o n t e n u t a all'interno della s t r u t t u r a .
Proseguendo troviamo t i p o _ d i _ d a t o ... che indica il tipo di d a t o del particolare membro della s t r u t t u r a ossia
della variabile specifica. Tipi validi di d a t o s o n o Byte, Integer, Long e String. Tipi di dati p e r ò p o s s o n o essere
r a p p r e s e n t a t i anche d a altre s t r u t t u r e (sempre che siano definite nel p r o g e t t o ).
Vediamo u n esempio: in q u e s t a s t r u t t u r a di esempio, che chiamiamo a p p u n t o " STRUTTURADIESEMPIO",
abbiamo d u e interi a 3 2 bit (Long), d u e stringhe di t e s t o e u n 'altra s t r u t t u r a d e n o m i n a t a " RECT" :
Type STRUTTURADIESEMPIO
Variabile_Long As Long
Altra_Variabile_Long As Long
Testo As String
Altro_Testo As String * 24
Altra_Struttura As RECT
End Type
Approfondimenti sul concetto di struttura: tipi definiti dall'utente
Se recuperiamo la definizione di s t r u t t u r a e l'esempio analizzato nel capitolo precedente, possiamo
addentrarci meglio nella comprensione di tali concetti.
Eravamo infatti rimasti alla s t r u t t u r a d e n o m i n a t a STRUTTURADIESEMPIO. Come si p u ò n o t a r e q u e s t a
s t r u t t u r a è composta d a cinue membri che p o s s o n o essere di tipo diverso, come già abbiamo visto in
precedenza.
Nella fattispecie abbiamo d u e variabili di tipo Long (i primi d u e membri della s t r u t t u r a ), d u e variabili stringa
d e n o m i n a t e Testo e Altro_Testo, e d u n a variabile della s t r u t t u r a RECT.
La p r e s e n z a di u n a variabile di u n 'altra s t r u t t u r a implica che nel p r o g e t t o sia definita u n a seconda s t r u t t u r a
(in q u e s t o caso la s t r u t t u r a RECT) che definisca a s u a volta i suoi membri.
E come si v e d e le interazioni t r a d u e s t r u t t u r e differenti s o n o possibili. I n o l t r e le variabili che fanno p a r t e del
tipo di dati specificato (STRUTTURADIESEMPIO), che facciano p a r t e di q u e s t a o di quella s t r u t t u r a , p o s s o n o
essere t r a t t a t i come variabili del t u t t o normali, p e r cui n o n ci si d e v e preoccupare t r o p p o della s t r u t t u r a di
provenienza.
Poco s o t t o si dimostrerà con u n esempio la validità di tale affermazione.
Se volessimo lavorare con u n a variabile di tipo definito dalla s t r u t t u r a è sufficiente interporre u n p u n t o " . " t r a
il n o m e della variabile e d il n o m e del membro.
Ad esempio, il s e g u e n t e codice definisce e dichiara u n a variabile come d a t o di tipo della s t r u t t u r a d e n o m i n a t a
STRUTTURADIESEMPIO (u n p o ' come se dichiarassimo u n a variabile come Long o String...):
Dim Es As STRUTTURADIESEMPIO
Es.Variabile_Long = 50
Es.Altra_Variabile = 40 + Es.Variabile_Long
Es.Testo = "testo"
Altra cosa i m p o r t a n t e è che al m o m e n t o in cui la prima linea di codice viene l e t t a dall'applicazione, se n o n
viene riconosciuta u n a s t r u t t u r a n o t a , viene g e n e r a t o utipo
n di dati definito dall'u t e n t e (ossia u n tipo di d a t o
n o n p r e s e n t e nel linguaggio ma impostabile in b a s e alle preferenze del p r o g r a m m a t o r e ).
Dove n a t u r a l m e n t e u ntipo di dati r a p p r e s e n t a n o la caratteristica di u n a variabile che determina quale
g e n e r e di dati essa p u ò includere.
I tipi di dati interni al linguaggio e quindi immediatamente interpretabili s o n o : Byte, Boolean, Integer, Long,
Currency, Decimal, Single, Double, Date, String, Object e Variant, m e n t r e altri tipi di dati provenienti
e s t e r n a m e n t e s o n o i tipi definiti dall'u t e n t e , e i tipi specifici di o g g e t t o . Q u e s t o va comunque oltre lo scopo
del p r e s e n t e articolo che h a l'unico fine di analizzare (cosa che verrà f a t t a t r a poco) le s t r u t t u r e API. I n ogni
caso è facile comprendere dal p u n t o di vista visivo q u a n d o Visual Basic g e n e r a u n n u o v o tipo di dati.
Facciamo u n esempio pratico:
Private Type SSTRUTT
Nome As String
Cognome As String
Eta As Integer
Tel As Integer
End Type
Abbiamo creato u n n u o v o tipo di dati. Dichiariamo a d e s s o u n a variabile del tipo a p p e n a definito:
Private Sub Form_Load()
Dim Utente As SSTRUTT
Utente.Nome = "Giovanni"
End Sub
nel m o m e n t o in cui si termina di scrivere As ci si accorge che è possibile selezionare dalla lista dei tipi di dati,
anche SSTRUTT ossia il tipo d a noi a p p e n a g e n e r a t o . L'icona visualizzata alla sinistra di SSTRUTT è quella
tipica dei tipi definiti dall'u t e n t e .
Q u a n d o andiamo invece a d a s s e g n a r e la stringa di t e s t o " Giovanni" a d U t e n t e , n o n facciamo altro che
a s s e g n a r e u n valore a d u n e l e m e n t o della s t r u t t u r a . Ossia l'e l e m e n t o viene finalmente definito.
Da a d e s s o in poi possiamo fare u s o di tale e l e m e n t o proprio come utilizzeremmo u n a variabile q u a l u n q u e .
Ad esempio, possiamo definire anche la variabile Cognome e nella routine Command1_Click unire Nome e
Cognome con l'o p e r a t o r e di concatenazione "&", come faremmo nel caso di d u e semplici variabili di t e s t o .
Ecco l'esempio completo:
Private Type SSTRUTT
Nome As String
Cognome As String
Eta As Integer
Tel As Integer
End Type
Dim Utente As SSTRUTT
Private Sub Form_Load()
Utente.Nome = "Giovanni"
Utente.Cognome = "Verdi"
End Sub
Private Sub Command1_Click()
MsgBox Utente.Nome & " " & Utente.Cognome
End Sub
Una piccola precisazione: perchè nel codice m o s t r a t o sopra la dichiarazione di U t e n t e è s t a t a s p o s t a t a nelle
dichiarazioni generali del modulo di codice?
Semplicemente perchè l'a r e a di validità della variabile U t e n t e n o n è più limitata alla routine Form_Load come
nell'esempio precedente ma si e s t e n d e anche alla routine Command1_Click.
E si sa che le variabili che d e v o n o avere u n o scopo valido p e r t u t t o il modulo di codice s o n o dichiarate nella
p a r t e iniziale del codice.
Q u e s t o r a p p r e s e n t a il funzionamento delle s t r u t t u r e in generale. I n ogni caso l'i n t e r e s s a n t e a r g o m e n t o dei
tipi definiti dall'u t e n t e verrà approfondito in maniera ancora più specifica in u n prossimo articolo al di fuori
dell'a r g o m e n t o API.
Riferendoci alle API le cose n o n cambiano di molto. Nel prossimo articolo si vedrà come molte funzioni interne
a W i n d o w s utilizzano membri di particolari s t r u t t u r e come loro parametri.
Puntatori ad una struttura
Come già si è visto le s t r u t t u r e s o n o molto frequenti all'interno delle dichiarazioni delle funzioni. Q u e s t o
perchè con u n solo p u n t a t o r e a d u n a s t r u t t u r a è possibile richiamare u n n u m e r o di informazioni molto
superiore a quello assegnabile a d u n singolo p a r a m e t r o . Se infatti definiamo puntatore ad una s t r u t t u r a
l'indicatore di passaggio d a u n a dichiarazione di u n a funzione a d u n a s t r u t t u r a , a d esempio:
ByVal lplf As LOGFONT
possiamo n o t a r e che il p a r a m e t r o lplf della funzione in q u e s t i o n e p o r t a con se t u t t e le informazioni della
s t r u t t u r a LOGFONT.
Probabilmente u n esempio chiarirà meglio le idee. Si consideri d u e funzioni che compiono le s t e s s e operazioni
e o t t e n g o n o il medesimo risultato, come CreateFont e CreateFontIndirect. Qual'è la differenza sostanziale t r a
le d u e ? La seconda ossia CreateFontIndirect, come rivela il n o m e , h a u n utilizzo indiretto nel senso che passa
prima p e r la s t r u t t u r a LOGFONT m e n t r e la prima racchiude in sè t u t t i i parametri necessari. E v e d e n d o le d u e
dichiarazioni n o n si p u ò dire che la CreateFont sia di più semplice interpretazione della CreateFontIndirect:
Declare
ByVal W
ByVal u
ByVal Q
Function
As Long,
As Long,
As Long,
CreateFont Lib "gdi32" Alias "CreateFontA" (ByVal H As Long, _
ByVal E As Long, ByVal O As Long, ByVal W As Long, ByVal I As Long, _
ByVal S As Long, ByVal C As Long, ByVal OP As Long, ByVal CP As Long, _
ByVal PAF As Long, ByVal F As String) As Long
Notare che nella dichiarazione della CreateFontIndirect b a s t a u n unico p a r a m e t r o :
Declare Function CreateFontIndirect Lib "gdi32" Alias "CreateFontIndirectA" (lpLogFont _
As LOGFONT) As Long
I n realtà il v a n t a g g i o associato all'u s o di u n a s t r u t t u r a n o n è la minore lunghezza del codice. I n f a t t i n o n si
d e v e scordare che se u n a funzione utilizza u n p u n t a t o r e a d u n a s t r u t t u r a d e v e necessariamente essere
dichiarata anche la s t r u t t u r a . Perciò nel caso della CreateFontIndirect la dichiarazione completa di s t r u t t u r a
s a r e b b e la s e g u e n t e :
Declare Function CreateFontIndirect Lib "gdi32" Alias "CreateFontIndirectA" (lpLogFont _
As LOGFONT) As Long
Private Type LOGFONT
lfHeight As Long
lfWidth As Long
lfEscapement As Long
lfOrientation As Long
lfWeight As Long
lfItalic As Byte
lfUnderline As Byte
lfStrikeOut As Byte
lfCharSet As Byte
lfOutPrecision As Byte
lfClipPrecision As Byte
lfQuality As Byte
lfPitchAndFamily As Byte
lfFaceName(1 To LF_FACESIZE) As Byte
End Type
Il v a n t a g g i o s t a invece nella semplicità di utilizzo e nell'ordine imposto all'u s o della funzione.
4. LE A P I: F U N Z I O N I 'CALLBACK'
Comprendere il concetto di Funzione Callback è molto semplice p e r chi h a seguito gli articoli precedenti sulle
API.
Una Funzione Callback infatti processano delle informazioni nello s t e s s o i s t a n t e in cui la funzione API viene
richiamata, in m o d o quindi d a evitare di a t t e n d e r e il termine dell'elaborazione e d a u n altro lato di inserire la
chiamata API all'interno di u n ciclo.
Per fare u n esempio pratico si p u ò p e n s a r e al processo di enumerazione di t u t t e le finestre a p e r t e a t t r a v e r s o
la funzione EnumWindows. Una volta chiamata l'API EnumWindows essa ritornerà il riferimento alla prima
finestra t r o v a t a , cosa che in sè n o n h a molto significato.
Ecco perchè la funzione passa immediatamente tale riferimento alla funzione callback che la elabora in t e m p o
reale, ancor prima di ricevere il riferimento alla seconda finestra.
Elaborazione che n a t u r a l m e n t e consiste in u n a serie di operazioni a discrezione dello sviluppatore, proprio
come in u n a funzione normale.
E fa p a r t e delle possibilità della funzione callback l'interruzione del processo ossia la segnalazione di s t o p
alla funzione API.
L'utilizzo delle funzioni callback si rivela molto semplice con l'utilizzo dell'istruzione AddressOf che contiene
l'indirizzo della funzione callback.
Cosa molto i m p o r t a n t e d a ricordare è che la funzione callback d e v 'essere pubblica (Public Function) e
c o n t e n u t a in u n modulo e n o n all'interno di u n modulo di form.
Q u e s t o p e r p e r m e t t e r e la piena accessibilità delle funzioni API in qualsiasi p a r t e del codice siano s t a t e
inserite. Le limitazioni all'utilizzo dell'o p e r a t o r e AddressOf s o n o molto chiare nella documentazione di
sviluppo di Visual Studio:
1. "AddressOf p u ò essere utilizzata solo immediatamente prima di u n a r g o m e n t o di u n elenco di argomenti.
Tale a r g o m e n t o p u ò essere il n o m e di u n a routine Sub, Function o Property definita dall'u t e n t e "
1 . " La routine Sub, Function o Property richiamata con AddressOf d e v e trovarsi nello s t e s s o p r o g e t t o delle
dichiarazioni e routine correlate. "
2 . " È possibile utilizzare AddressOf solo con routine Sub, Function o Property definite dall'u t e n t e . Non è
possibile utilizzarla con funzioni e s t e r n e dichiarate con l'istruzione Declare o con funzioni a cui si fa
riferimento d a librerie dei tipi. "
3 . " È possibile passare u n p u n t a t o r e a u n a funzione a u n a r g o m e n t o i m p o s t a t o come As Any o As Long in
u n a definizione dichiarata come Sub, Function o di tipo definito dall'u t e n t e . "
La sintassi dell'o p e r a t o r e AddressOf è la s e g u e n t e :
AddressOf NomeFunzione
d o v e n a t u r a l m e n t e NomeFunzione indica il n o m e della funzione callback che si vuole chiamare ogni volta che
la funzione API ritorna u n risultato utile.
I n definitiva quindi utilizzare u n p u n t a t o r e a d u n a funzione callback significa passare il valore r i t o r n a t o dalla
funzione API alla funzione callback:
EnumWindows AddressOf Funzione_Callback, 0
Ad esempio possiamo creare u n p r o g e t t o nel quale, p e r ogni finestra c o r r e n t e m e n t e a p e r t a viene
visualizzato in u n a finestra di messaggio il t e s t o c o n t e n u t o nella barra del titolo.
A tale scopo dovremo i n n a n z i t u t t o inserire in u n modulo la funzione callback con le dichiarazioni delle funzioni
necessarie a recuperare la lunghezza del t e s t o della barra del titolo e d il t e s t o s t e s s o :
'// MODULO STANDARD
Public Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal _
hwnd As Long) As Long
Public Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, _
ByVal lpString As String, ByVal cch As Long) As Long
'// la funzione callback
Public Function TestoFinestre(ByVal hwnd As Long, ByVal lParam As Long) As Long
Dim LTesto As Long, TBuffer As String '// lungh. del testo e della memoria che lo contiene
LTesto = GetWindowTextLength(hwnd) + 1 '// richiama l'API per ottenere la lunghezza
TBuffer = Space(LTesto) '// crea uno spazio in memoria pari alla lunghezza del testo
GetWindowText hwnd, TBuffer, LTesto '// richiama l'API per ottenere il testo
MsgBox Left(TBuffer, LTesto - 1) '// mostra il testo della barra del titolo
End Function
E a d e s s o nel modulo di codice di Form1:
'// MODULO DI CODICE
Public Declare Function EnumWindows Lib "user32" (ByVal lpEnumFunc As Long, _
ByVal lParam As Long) As Long
Private Sub Form_Load()
EnumWindows AddressOf TestoFinestre, 0
End Sub
Limiti delle funzioni callback
Nell'ultimo articolo si è p o t u t o capire l'importanza e l'utilità dell'o p e r a t o r e AddressOf p e r richiamare u n a
funzione callback che elabori u n o p e r u n o i risultati ritornati d a u n a funzione API.
I n realtà p e r ò esistono alcune limitazioni. Come si è visto il p u n t a t o r e a d u n a funzione callback (ossia
l'o p e r a t o r e AddressOf) è valido come a r g o m e n t o di u n a funzione API. Può p e r ò capitare di dover a s s e g n a r e
a d u n a variabile del tipo definito dalla s t r u t t u r a l'indirizzo di u n a funzione callback, come nell'esempio
riportato sotto:
Private Type EMRPOLYPOLYGON
pEmr As emr
rclBounds As RECTL
nPolys As Long
cptl As Long
aPolyCounts(1) As Long
aptl(1) As POINTL
End Type
Private Function Funzione_CallBack() As Long
If Int(10 * Rnd + 1) >= 1 Then
nPolys = 10
Else
nPolys = 0
Funzione_CallBack = nPolys
End If
End Function
Private Sub Form_Load()
Dim Poligono As EMRPOLYPOLYGON
'istruzione invalida:
Poligono.nPolys= AddressOf Funzione_Callback
End Sub
Avviando l'applicazione (d o p o aver n a t u r a l m e n t e inserito le dichiarazioni di t u t t e le altre s t r u t t u r e ), comparirà
u n messaggio di errore.
La ragione di q u e s t o limite è che il p u n t a t o r e a d u n a funzione callback d e v 'essere obbligatoriamente
all'interno di u n a funzione. Non necessariamente u n 'API p e r ò .
Il m o d o quindi p e r s u p e r a r e l'ostacolo consiste nell'includere nel codice u n a seconda funzione nella quale si
p o t r à senza problemi indicare l'indirizzo della prima funzione. Ad esempio:
Private Sub Form_Load()
Dim Poligono As EMRPOLYPOLYGON
Poligono.nPolys = Prima_Funzione(AddressOf Funzione_CallBack)
End Sub
I n q u e s t o m o d o l'o p e r a t o r e verrà riconosciuto in q u a n t o incluso come p a r a m e t r o di u n a vera e propria
funzione.
5. LE A P I: BYVAL, BYREF E PASSAGGIO D I STRINGHE D I TESTO
Windows a 3 2 bit
Che cosa significa che W i n d o w s è u n sistema operativo a 3 2 bit? Niente di più che t u t t i i valori passati come
parametri alle s u e funzioni interne (le API p e r intenderci) s o n o interi a 3 2 bit.
Q u e s t a dichiarazione p u ò apparire in effetti s t r a n a , s o p r a t t u t t o d o p o che si è visto in dettaglio l'utilizzo e d il
significato di ogni p a r t e di u n a funzione, perchè dalla dichiarazione di u n a qualsiasi funzione risulta che le
p u ò essere p a s s a t o come p a r a m e t r o sì u n intero, ma anche u n valore t e s t u a l e , u n a s t r u t t u r a e così via.
Se infatti consideriamo come funzione di esempio l'API joyGetPos:
Private Declare Function joyGetPos Lib "winmm.dll" (ByVal uJoyID As Long, pji As JOYINFO) As Long
notiamo che è richiesto come p a r a m e t r o sia u n valore intero che u n a variabile che fa riferimento a d u n a
s t r u t t u r a (la s t r u t t u r a JOYINFO).
Andando oltre q u e s t o esempio esistono alcune funzioni che richiedono variabili stringa, array, b y t e e così via.
Che cosa significa allora che anche in questi casi s o n o passati in realtà degli interi a 3 2 bit?
Q u e s t o è il significato in poche parole del termine ByRef d o v e Ref abbrevia la parola Reference e n o n indica
altro che u n intero a 3 2 bit. I n realtà quindi passare u n qualsiasi valore a d u n a funzione di sistema n o n
significa altro che passare il riferimento a tale valore.
Così passare la s t r u t t u r a JOYINFO alla funzione joyGetPos n o n significa p a s s a r n e t u t t i i membri bensì
p a s s a r n e u n riferimento in forma di intero a 3 2 bit.
Come si p u ò comprendere, q u e s t o intero r a p p r e s e n t a u n p u n t a t o r e al d a t o d a a s s e g n a r e alla funzione. Che
differenza intercorre t r a u n p a r a m e t r o p a s s a t o ByVal e d u n o p a s s a t o ByRef?
Come già s p i e g a t o nel dettaglio negli articoli del corso di Visual Basic, m e n t r e le variabili p a s s a t e ByRef
p o s s o n o essere modificate dalla funzione che quindi n e h a pieno accesso, p e r le variabili p a s s a t e ByVal
q u e s t o discorso n o n vale. E' u n m e t o d o di passaggio del Valo r e effettivo anziché dell'indirizzo che consente
alla funzione di accedere a u n a copia della variabile.
Le API utilizzano così il passaggio di parametri p e r valore solamente q u a n d o n o n necessitano di modificare la
variabile in q u e s t i o n e .
Le stringhe di testo
E p e r le stringhe di t e s t o ? La discussione in q u e s t o caso si allunga ulteriormente poichè e s s e n d o le funzioni
di W i n d o w s scritte in C+ + , le regole d a seguire p e r utilizzarle s e g u o n o il principio generale di m a n t e n e r e le
direttive di tale linguaggio, anche in differenti ambienti di programmazione.
Non t r o v e r e m o quindi nel C+ + u n tipo di d a t o che corrisponde a String di Visual Basic ma u n a serie di valori
che va d a -1 2 8 a 1 2 7 r a p p r e s e n t a t i dal tipo di dati char che compongono il t e s t o carattere p e r carattere.
Perciò il tipo di dati definito String n o n è altro che u n o speciale valore Long t r a t t a t o in m o d o differente (ma
s o l t a n t o a p p a r e n t e m e n t e ) p e r facilitarne l'impiego d a p a r t e degli u t e n t i del linguaggio.
L'immagine qui s o t t o r a p p r e s e n t a in maniera schematica la differenza t r a ciò che accade in realtà e ciò che
a p p a r e q u a n d o si passa u n a stringa di t e s t o a d u n a funzione:
Per chiarire ulteriormente il concetto si p u ò considerare u n esempio numerico. Se si p r e n d e in considerazione
infatti u n a semplice s t r u t t u r a del tipo:
Private Type STRUTTURA
Variabile_Stringa As String
End Type
e si considera u n a variabile del tipo STRUTTURA che contiene il t e s t o " Q u e s t o è solo u n esempio" :
Private Sub Form_Load()
Dim Var As STRUTTURA
Var.Variabile_Stringa = "Questo è solo un esempio"
End Sub
ci si p o t r e b b e a s p e t t a r e che, visualizzando in u n a finestra di messaggio le dimensioni della s t r u t t u r a , v e n g a
r i p o r t a t a la lunghezza del s u o c o n t e n u t o ossia la lunghezza del t e s t o " Q u e s t o è solo u n esempio".
Aggiungendo la funzione MsgBox alla routine Form_Load:
MsgBox Len(Var)
si scopre che in realtà il valore visualizzato è 4 . Q u a t t r o infatti r a p p r e s e n t a la dimensione in b y t e di u n intero
numerico a 3 2 bit.
6. R I F E R I M E N T I A I CONCETTI ESAMINATI
I n q u e s t o capitolo v e n g o n o p r e s e n t a t i i collegamenti ai concetti più importanti analizzati nel corso della
guida.
Corso di Visual Basic
S t r u t t u r a MENUITEMINFO
S t r u t t u r a JOYINFO
Funzione MsgBox
Proprietà
Istruzioni e routine
Tipi di dati
A) Le guide della collana "i .pdf di VISUAL BASIC I T A L I A"
Tutte le guide elencate s o n o scaricabili g r a t u t i t a m e n t e al sito Visual Basic Italia
1 . Guida completa alle API: dai concetti b a s e a quelli avanzati
B) N o t e legali
Non è consentita la riproduzione anche parziale dei contenuti di q u e s t a guida senza autorizzazione
dell'a u t o r e . L'a u t o r e e d i responsabili del sito n o n p o s s o n o essere considerati responsabili di eventuali danni
causati a p e r s o n e o cose derivanti d a u n u s o e r r a t o delle informazioni presenti nella guida. Per contatti o
chiarimenti utilizzare l'indirizzo di p o s t a elettronica indicato nel sito.