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.
Documenti analoghi
Funzioni API di Windows - entra nel portale di langy
Con Visual Basic la programmazione di applicazioni Windows è enormemente semplificata, in
quanto la maggior parte di questi messaggi viene automaticamente trasformata in proprietà, metodi
ed eventi...