Skip to main content

Full text of "Io programmo 66"

See other formats


EURO 



RIVISTA Effi 



I CORSI DA ZERO PER IMPARARE: 
VISUAL BASIC, C++, C#, VB.NET, JAVA E JSP 



RIVISTA+SUPPLEMENTO "PROGRAMMARE IL WEB"+2CD € 7,70 



Periodicità mensile • FEBBRAIO 2003 • ANNO Vili, N.2 (66) 

Poste Italiane • Spedizione in a.p. - 45% • art. 2 comma 20/b legge 662/96 - AUT. N. DCDC/033/01/CS/CAL 



ROGRAMMO 

Grafica Digitale 

e Visual Basic 



Sviluppiamo una completa 
applicazione di fotoritocco 

XML & FLASH 

Impariamo a integrare le tecnologie 
che hanno rivoluzionato il Web 



WinZIP fai da te! 

Le tecniche di compressione 
utilizzate dalle librerie Open Sourc 



SISTEMA 



Impronte digitali: realizziamo un'applicazione VB 
per il riconoscimento e la catalogazione 
Tecniche per ottimizzare le applicazioni Delphi 



ELETTRONICA 



• Lego Mindstorms: un laboratorio di robotica 
sulla tua scrivania 

• Moduli Rabbit: elettrodomestici, luci, allarmi, 
telecamere, ora li controlli dal Web! 

• Realizziamo un software per il controllo 
dei motori passo passo 

ISSN 1128-594X 
30066 




Una 



COLOBI nsp.nrr.8 










ADVANCED 



Reti locali, cablate, wireless: analizziamone 
il comportamento con Network Simulator 




9 '771128 594009 



è una pubblicazione SIR jg^ 



HACKER 

Scovare le password 
di alcuni router ADSL 



MASTER 



INCORSO CROBOTS: I RISULTATI DEL CONCORSO 2002 



Contents 







EOGRAMMO 

Grafica Digitale 
e Visual Basic 




Anno VII - n. 2 (66) Febbraio 2003 ► 

► ► ► Povere le mie orecchie!? 

Sovente le mie orecchie hanno dovuto ascoltare frasi campate in 
aria, elucubrazioni mentali e disquisizioni su nuovi fantomatici 
dispositivi che cambieranno il modo di vivere: TV virtuali che si 
materializzano al solo pensiero, ascensori spaziali in grado di 
catapultarci sulla luna, auto volanti e chi più ne ha, più ne metta. 
Questo nuovo anno porta con se nuovi "pettegolezzi": orologi da 
polso e magneti da attaccare al frigorifero, sistemi in grado di 
integrare le comuni operazioni quotidiane, e l'individuo stesso, 
all'interno della grande Rete. 
Fantascienza o realtà? Sara forse questa, 
una delle tante altre novelle che le mie 
povere orecchie dovranno ancora una 
volta sopportare? I dubbi sono tanti ma, 
forse questa volta, ci sarà da scommet- 
tere qualcosa, soprattutto se a prospet- 
tare il progetto è lui, l'innominabile: Bill 
Gates: "Da qui a breve ogni dispositivo, 
piccolo o grande che esso sia, sarà dotato del 
nuovo .NET Compact Framework, tutto e 
tutti saranno in grado di interfacciarsi alla 
Rete'. Frasi che non restano nella fervida immaginazione del 
buon zio Bill ma che trovano raffronto al Consumer Electronics 
Show, dove, per la prima volta, sono stati presentati i primi 
dispositivi che utilizzeranno la nuova tecnologia. Fossil, Citizen 
e Suunto, produttori d'orologi da polso, prevedono di mettere in 
commercio modelli predisposti ad accogliere SPOT (questo il 
nome del progetto) entro la fine dell'anno. Gli orologi si colle- 
gheranno al PC per compiere una serie d'operazioni: regolazione 
automatica dell'ora, download di software e collegamento wire- 
less a dati streaming trasmessi mediante segnali radio FM, per 
ricevere informazioni di qualunque genere. Per non parlare delle 
calamite per il frigorifero, veri gioiellini che ricevono informazio- 
ni wireless sul traffico locale o sulle specialità dei ristoranti della 
zona. Scommettiamo che a breve sarà possibile, semplicemente 
parlando al proprio orologio, scongelare la cena e azionare il 
forno a micronde? Scommetto le mie orecchie! 

Gianfranco Forlino (gforlino@edmaster.it) 



News 


6 


Soluzioni 


10 


► Frasi anagrammate 

Teoria & Tecnica 


14 



XML e Flash: l'utile ed il dilettevole si incontrano 
Password a "portata di mano" 
Librerie di compressione Open Source 
Fotolab: filtri fotografici in Visual Basic 
Animazione in Java 3D (3 a parte) 

Biblioteca 



14 
21 
26 
31 
37 

41 





Tips&Tricks 


42 




C Robot 


45 


► 


Il Torneo di Crobots 2k2 

Sistema 


47 


► 


Ottimizzare programmi Delphi 

Lego 


52 


► 


LEGO Mindstorms Robotics Invention System 2.0 

Elettronica 


55 


► 
► 


Un Software di controllo per motori Passo-Passo 
Un server WEB nel taschino della giacca 

Exploit 


55 
60 

64 


► 


Non c'è password che tenga! 

I corsi di ioProgrammo 


66 



JSP • Procedure memorizzate con JDBC 66 

VB .Net • Le finestre di dialogo 70 

C# • Passaggio di argomenti, tre casi particolari 74 

C++ • Risoluzione di ambiguità ed ereditarietà multipla 78 

Java • Java Media Framework: strumenti di acquisizione audio e video 82 

VB • Come realizzare un FTP Client 87 



JoR 




OJUto 



Multimedia 


91 


► 3DSM • Modellazione tramite Surface 

Advanced Edition 


97 


► Simulare una rete con Network Simulator 

► Testare il codice con JUnit 

Software sul CD-Rom 


97 

101 

106 


FAQ 


109 


In Box 


113 


Il Sito del mese 


114 



OGRAMMO 



Anno VII - N.ro 2 (66) - Febbraio 2003 - Periodicità: Mensile 
Reg. Trib. di CS al n.ro 593 - Cod. ISSN 1128-594X 
E-mail: ioprogrammo@edmaster.it 
http://www.edmaster.it/ioprogrammo 

Dir. Editoriale Massimo Sesti 
Dir. Responsabile Romina Sesti 
Product Manager Antonio Meduri 

Editor Gianfranco Forlino 

Coordinatore Redazionale Raffaele del Monaco 

Redazione Thomas Zaffino, Antonio Pasqua 

Collaboratori S. Ascheri, M. Autiero, R. Bandiera, 

L. Buono, P. Canini, E. Cobisi, F. Grimaldi, M. Del Gobbo, 

E. Florio, A. Marroccelli, S. Meschini, G. Palumbo, A. Panella, 

A. Pelleriti, C Pelliccia, P. Perrotta, S. Serra, L. Spuntoni, 

G. Uboldi, F. Vaccaro. 

Per l'inserto hanno collaborato M. Battista, A. Cangiano, 

P. Capitani, C Giustozzi, F. Mestrone, G. Uboldi 

Segreteria di Redazione Veronica Longo 

REALIZZAZIONE GRAFICA CROMATIKA Sri 
Cda Lecco, zona ind. - 87030 Rende (CS) 
Tel. 0984 8319 - Fax 0984 8319225 
Coord. grafico: Paolo Cristiano 
Coord. tecnico: Giancarlo Sicilia 
Impaginazione elettronica: Aurelio Monaco 

PUBBLICITÀ Edizioni Master S.r.l. 

Responsabile Vendite Ernesto Redaelli 

Agenti Vendita Elisabetta Februo, Serenella Scarpa, 

Cornelio Morari 

Segreteria Ufficio Vendite Daisy Zonato 

Via Cesare Correnti, 1 - 20123 Milano 

Tel. 02 8321612 - Fax 02 8321764 



e-mail: advertising@edmaster.it 

EDITORE Edizioni Master S.r.l. 

Sede di Milano: Via Cesare Correnti, 1 - 20123 Milano 

Tel. 02 8321482 - Fax 02 8321699 

Sede di Cosenza: Cda Lecco, zona ind. - 87030 Rende (CS) 

Amministratore Unico: Massimo Sesti 

Responsabile Amministraz. e Finanza: Benedetto Celsa 

Produzione e Logistica: Michele Carere 

Diffusione: Alessandra Cervello 

Marketing: Giuseppina Bruno, Leonardo Petrone, Antonio Meduri 

ABBONAMENTO E ARRETRATI 

Costo abbonamento annuale (11 numeri): Italia € 84,70 Promo- 
zione Sconto 30% € 59,00 

Costo abbonamento annuale (11 numeri): estero € 169,40 
Costo arretrati (a copia): il doppio del prezzo di copertina + 
€ 5,16 spese (spedizione con corriere). Verificare la disponibilità 
delle copie arretrate allo 028321482. La richiesta contenente i 
Vs. dati anagrafici e il nome della rivista, dovrà essere inviata 
via fax allo 028321699, oppure via posta a EDIZIONI MASTER 
via Cesare Correnti, 1 - 20123 Milano, dopo avere effettuato il 
pagamento, secondo le modalità di seguito elencate: 

- cc/p n. 16821878 o vaglia postale (inviando copia della rice- 
vuta del versamento insieme alla richiesta); 

- assegno bancario non trasferibile (da inviarsi in busta chiusa 
insieme alla richiesta); 

- carta di credito, circuito visa, cartasi; mastercard/ eurocard, 
(inviando la Vs. autorizzazione, il numero della carta, la data 
di scadenza e la Vs. sottoscrizione insieme alla richiesta). 

SI PREGA DI UTILIZZARE IL MODULO RICHIESTA ABBONAMENTO POSTO 

nelle pagine interne della rivista. L'abbonamento verrà attiva- 
to sul primo numero utile, successivo alla data della richiesta. 

Sostituzioni: Inviare il CD-Rom difettoso in busta chiusa a: 
Edizioni Master Servizio Clienti - Via Cesari Correnti, 1 
20123 Milano 



Assistenza tecnica: ioprogrammo@edmaster.it 

^ Servizio Abbonati: 

®tel.02 8321482 

@ e-mail: servizioabbonati@edmaster.it 



Stampa: Elcograf Industria Grafica (LC) 
Stampa CD-Rom: Disctronics Italia (MI) 
Distribuzione per l'Italia: Parrini & C S.p.A. - Roma 

Finito di stampare nel mese di Gennaio 2003 

Nessuna parte della rivista può essere in alcun modo 
riprodotta senza autorizzazione scritta della Edizioni Master. 
Manoscritti e foto originali, anche se non pubblicati, non si 
restituiscono. Edizioni Master non si assume alcuna re- 
sponsabilità per eventuali errori od omissioni di qualunque 
tipo. Nomi e marchi protetti sono citati senza indicare i 
relativi brevetti. Edizioni Master non sarà in alcun caso 
responsabile per i danni diretti e/o indiretti derivanti dall'u- 
tilizzo dei programmi contenuti nel CD-Rom e/o per even- 
tuali anomalie degli stessi. Nessuna responsabilità è, inol- 
tre, assunta dalla Edizioni Master per danni o altro derivanti 
da virus informatici non riconosciuti dagli antivirus ufficiali 
all'atto della masterizzazione del supporto. 



sili 



A.N.E.S. 



L'Universo Tecnologico 



MASTER % «™™ 

Edizioni Master edita: 

Idea Web, GolOnLine Internet Magazine, Win Magazine, Quale Compu- 
ter, DVD Magazine, Office Magazine, ioProgrammo, Linux Magazine, 
Softline Software World, MPC, Discovery DVD, Computer Games Gold, 
inDVD, I Fantastici CD-Rom, PC VideoGuide, Il CD-Rom di Idea Web, 
I Corsi di Win Magazine, Le Collection. 



w 



News 



Bill Gates presenta 

OneNote, la nuova 

applicazione 

per prendere appunti 

in modo più produttivo 

OneNote unisce l'efficienza 
tipica dei contenuti digitali 
alla possibilità di prendere 
appunti in modo flessibile 

In occasione del COMDEX 2002, Bill 
Gates, Chairman and Chief Software 
Architect di Microsoft Corp., ha annun- 
ciato la prossima disponibilità di Micro- 
soft One Note, un'applicazione che per- 
mette agli utenti di prendere appunti, or- 
ganizzarli e utilizzarli in modo più pro- 
duttivo. OneNote, sul mercato a metà 
del 2003, consentirà di prendere appunti 
su un desktop o su un computer portati- 
le, mentre gli utenti di Tablet PC potran- 
no acquisire anche note scritte a mano, 
immagini e diagrammi. "OneNote com- 
bina la flessibilità di un taccuino cartaceo 
con l'efficienza tipica del contenuto digi- 
tale, mantenendo lo stile con cui ciascu- 
no di noi fissa sulla carta i propri pensie- 
ri e organizza gli appunti", ha dichiarato 
Jeff Raikes, Group Vice President of Pro- 
ductivity and Business Services di Micro- 
soft. "Con la creazione di nuove applica- 
zioni come OneNote, Microsoft è impe- 
gnata nel mantenere la suite Office sem- 
pre aggiornata e al passo con i tempi, e 
nel migliorare la produttività degli infor- 
ma tion worker." Da un recente studio 
condotto da Microsoft Research, risulta 
che il 91 % degli informa tion worker - 
tutti coloro che nello svolgimento della 
propria attività professionale gestiscono 
T informazione attraverso il PC e i dispo- 
sitivi digitali - intervistati prende rego- 
larmente appunti, il 26% li trasferisce in 
messaggi di posta elettronica, mentre il 
23% ha ammesso di non riuscire sempre 
a ritrovare le informazioni desiderate. 
Inoltre, il 36% ha dichiarato di essere 
pronto ad adottare un nuovo sistema di 
appunti. 



VeriSign annuncia un 
toolkit per la sicurezza 
nei WebServices 



Una implementazione Open 
Source di un interessante 
tool che consentirà agli 
sviluppatori di gestire 
problematiche come firma 
digitale e cifratura 

VeriSign ha introdotto una implemen- 
tazione completamente gratuita e 
Open Source di un toolkit rivolto agli svi- 
luppatori che semplifica Y integrazione 
della firma digitale e della cifratura 
air interno di Web Services. VeriSign 
afferma che l'implementazione sarà 
distribuita attraverso delle specifiche 
librerie open source che daranno agli svi- 
luppatori la possibilità di costruire Web 
Service "sicuri" che utilizzino lo standard 
WS-Security. Il Trust Service Integration 
Kit è un tool Java-based che permette di 
gestire XML Signature, XML Encryption 
ed altre funzioni relative alla sicurezza. Il 
TSIK è composto da tre componenti fon- 
damentali: il Messaging Framework, il 
Trust Layer ed alcune risorse specifiche 
per XML. 

• Il Messaging Framework può essere uti- 
lizzato per specificare firma e chiave 
di cifratura per garantire autentica- 
zione, integrità dei dati e riservatezza 
delle comunicazioni. 

• Il Trust Laywe fornisce delle API per la 
sicurezza dei messaggi XML attraver- 
so una infrastruttura a chiave pubbli- 
ca (PKI), e include le implementazio- 
ne delle specifiche W3C per la firma 
digitale e la cifratura XML. 

• Le risorse per XML permettono di 
manipolare direttamente file XML, 
navigare nella struttura dei documen- 
ti, validare gli schema oltre a sempli- 
ficare T interfacciamento con i parser. 

www.verisign.com 



IBM pronta a 
pubblicare il codice 
della nuova tecnologia 
di Storaging 

Con lo scopo di attirare nuovi 
sviluppatori, IBM sta 
approntando una versione 
Open Source di Storage Tank 

I ricercatori di IBM sono al lavoro per 
proporre una versione Open Source di 
una delle più attese release del 2003: 
Storage Tank. Una tecnologia sviluppata 
per meglio gestire i sistemi di storaging 
esistenti e facilitare la cooperazione fra 
piattaforma diverse. Il modello di upgra- 
de proposto da IBM si può definire dun- 
que rivoluzionario: Storage Tank consen- 
te di integrare vecchi e nuovi sistemi, il 
tutto a vantaggio dei costi e della prati- 
cità. Storage Tank è una sorta di file 
system virtuale che si basa sul concetto 
di metadata, attraverso cui gestisce posi- 
zione, dimensione e permessi associati ai 
file immagazzinati. La caratteristica più 
interessante che Storage Tank offre consi- 
ste nella possibilità di far interagire siste- 
mi assolutamente eterogenei: gli stessi 
file saranno accessibili da sistemi opera- 
tivi differenti e potranno essere salvati su 
Windows, AIX e Linux in modo del tutto 
trasparente agli utenti. L' eterogeneità 
non si ferma ai server e ai sistemi opera- 
tivi, ma arriva al supporto per dischi e 
nastri (fondamentale per preservare i 
sistemi già esistenti) di qualsiasi marca e 
modello. Storage Tank sarà dunque 
capace di scendere a livello dei singoli 
blocchi che compongono un file, identifi- 
carne il formato e tradurlo in modo da 
renderlo compatibile al dispositivo che 

10 aveva richiesto. 

www.ibm.com/it/ 

Il PocketPC 
ci fa le multe 

11 Palmare sta cambiando 
in meglio il nostro mondo 

L/ applicazione PocketPM permette agli 
f agenti di Polizia Municipale di sosti- 
tuire il vecchio blocchetto delle multe con 
un innovativo palmare, migliorando l'effi- 
cienza del loro lavoro e fornendo un 
migliore servizio al cittadino. 



6 ►►► F 



b b 



http: //www. itportal.it 



w 



Il prodotto software, realizzato da una gio- 
vane e innovativa società di Cosenza, la 
NoTangle, informatizza l'intero processo di 
attività degli agenti di Polizia Municipale, 
dal rilevamento informatico delle infrazio- 
ne al Codice della Stradare alla gestione 
informatizzata del Back Office con un note- 
vole risparmio di tempo e danaro. 
U applicazione client, sviluppata per 
PocketPC utilizzando l'eMbedded Visual 
C++ e SQLCE 2.0, consente tramite una 
interfaccia amichevole di registrare i dati 
dell' infrazione e di scattare una foto attra- 
verso una camera digitale integrata con il 
dispositivo. I dati raccolti sono successiva- 
mente sincronizzati con il server centrale 
utilizzando una connessione sicura GPRS 
ed elaborati in modo efficace e veloce. 
L'applicazione lato server è stata intera- 
mente sviluppata sfruttando le nuove 
opportunità offerte dalla piattaforma .NET 
di Microsoft. 

FileMaker presenta 
la gamma educational 

Al MacWorld EXPO di San 
Francisco, presentata la 
gamma di soluzioni database 
K12 per le scuole 

Grazie alle numerose e potenti carat- 
teristiche, ai template per Y insegna- 
mento pronti per Fuso e alle centinaia di 
soluzioni per la vasta comunità di esperti 
sviluppatori, FileMaker Pro 6 rende 
ancora più economica ed efficiente la 
gestione e la condivisione delle informa- 
zioni, offrendo soluzioni concrete a 
migliaia di scuole nei principali distretti 
del Nord America. 











Ili 

"1 

i 

ì 

% 
\ 




Jump-start your productivity 
with the leading database 
software for workgroups. 

Get Started Free Solutions | Products | About Us 


FileMaker 





Il mese scorso FileMaker ha lanciato un 
nuovo sito web, K-12 Education, che 
offre soluzioni software gratuite per Y in- 
segnamento, ultime notizie che riguarda- 
no le proposte di FileMaker per il mondo 
delle scuole, aggiornamenti sulle confe- 
renze e sugli eventi dove gli insegnanti 
possono assistere a dimostrazione sull'u- 
so di FileMaker e offerte speciali dei pro- 



dotti FileMaker destinate agli insegnanti 
e amministratori nel segmento K-12. 

www.filemaker.com/education 

Macromedia Director 
diventa MX 

Disponibile la versione MX 
di Macromedia Director, 
il più noto software 
di authoring multimediale 

La nuova versione di Macromedia 
Director è stata arricchita di funziona- 
lità per gli utenti che realizzano prodotti 
interattivi su CD-ROM destinati alla pub- 
blicazione su Internet. Director MX si inte- 
gra perfettamente con tutti gli altri prodotti 
della gamma MX. Il software permette la 
creazione di contenuti che possano essere 
distribuiti dovunque, sia online che offline. 
Supporta tutti formati audio, video, 3D e 
grafici più diffusi e permette agli sviluppa- 
tori di utilizzare stream video senza limiti 
di durata, garantendo il supporto 
QuickTime, RealVideo e AVI. Gli sviluppa- 
tori possono lanciare Flash direttamente da 
Director MX e quindi di effettuare rapidi 
cambiamenti dei contenuti o controllare 
Flash attraverso l'utilizzo di Lingo. Inoltre, 
il software si integra con le tecnologie ser- 
ver di Flash, e in particolare con Flash 
Remoting MX, permettendo di ottenere una 
connessione ad elevate prestazioni tra 
ColdFusion MX e il Player Shockwave e 
con Flash Communication Server MX per la 
gestione di giochi multi utente, streaming 
video Flash e collaborazioni in tempo reale. 

www.macromedia.com/it/software/director/ 

WebSphere 5 
supporta Soap 

Uscita la quinta release 
dell'application server 
di IBM, con funzioni 
di autodiagnosi e 
autoriparazione e un miglior 
supporto ai web service 

Rilasciato WebSphere Application Server 
5.0, con funzioni per "lautonomic com- 
puting", un supporto potenziato per i web 
service. Secondo IBM, WebSphere 5.0 costi- 
tuirà la piattaforma di base per il software 
"On Demand" di IBM e sarà integrato con 
il database Db2, le applicazioni Tivoli per la 
gestione della rete e il software Lotus per la 



collaborazione, puntando a definire nuovi 
standard in termini di prestazioni, scalabi- 
lità, affidabilità, facilità di manutenzione ed 
interfaccia d'uso. Inoltre gli strumenti di 
sviluppo, strettamente integrati nelT am- 
biente, permettono agli sviluppatori di es- 
sere più veloci ed efficaci nella creazione di 
applicazioni J2ee". Dal punto di vista com- 
merciale, è stata aggiunta una nuova linea 
di prodotti, la cosiddetta Express che per- 
mette a IBM di estendere la propria offerta 
agli Isv e alle aziende che hanno bisogno di 
un ambiente J2ee, ma anche di un paradig- 
ma di sviluppo per le applicazioni semplifi- 
cato. I nuovi tool, infatti, rendono più sem- 
plice lavorare sui web service, "automatiz- 
zando" il processo di sviluppo, fino a limi- 
tare al minimo la scrittura di codice. In più, 
i wizard di WebSphere Studio danno l'op- 
portunità di ispezionare il codice prima di 
eseguirlo. WebSphere 5 è anche una buona 
piattaforma di integrazione perché ha il 
pieno supporto per J2ee Connection Archi- 
tecture 1.0. IBM ha aggiunto il supporto per 
Web Service Invocation Framework, una 
tecnologia che permette di richiamare e svi- 
luppare servizi Web su varie reti e protocol- 
li di trasporto, e Axis 3.0, un nuovo sistema 
per i web service ad alta velocità in grado 
di gestire richieste Soap, il più importante 
protocollo di trasporto per questi servizi. 
WebSphere 5.0 include anche Ibm Web Ser- 
vices Gateway per amministrare e rendere 
sicuri i Web service; un repository privato 
Uddi (Universal Description, Discovery and 
Integration)', una tecnologia per il workflow 
dei Web service basata su Bpel4Ws 
(Business Process Execution Language) for 
Web Services. 

www.ibm.com/it/ 

Batosta di Sun 
a Microsoft 

Per ordine di un giudice, la 
Java Virtual Machine di Sun 
dovrà essere inclusa nel 
sistema operativo di 
Windows e nel browser 
Internet Explorer 

La corte di giustizia del Maryland ha 
dato ragione alla Sun in una causa 
intentata contro la Microsoft per violazioni 
della legge antitrust e del copyright. 
L'oggetto della causa era l'implementazione 
di una versione proprietaria del linguaggio 
Java. Ora Microsoft dovrà distribuire Java 



http: //www. itportal.it 



2 



3 ►►► 7 



w 



IBM 

WebSphere 

Payment Manager 




"genuino". Il contenzioso tra le due aziende 
risale sin dal Marzo 1996, quando Microsoft 
strinse un accordo con Sun per distribuire 
prodotti basati sulla tecnologia Java, allora 
molto in voga. La natura trasversale della 
piattaforma Java, che non dipende dal 
sistema operativo, venne giudicata da 
Microsoft come un serio rischio alla 
posizione di predominio di Windows. 
Microsoft tentò quindi di togliere a Sun il 
controllo di Java, trasformando Java in un 
modo per scrivere applicazioni per 
Windows. Ma Sun replicò con una clausola 
che obbligava i prodotti Java distribuiti da 
terzi a superare un "core test" di Sun. 
Microsoft apportò quindi delle modifiche 
alla Virtual Machine, creandosi una propria 
versione (MSJVM). La piattaforma Java 
originale continuò ad essere distribuita 
soprattutto grazie a Netscape Navigator. 
Sun iniziò un'azione legale che portò ad un 
primo successo il 24 Marzo 1998, corte 
distrettuale della California del Nord. Nella 
sentenza, si proibiva a Microsoft di 
utilizzare la dizione "compatibile Java" nella 
distribuzione di MSJVM. La corte d'appello 
annullò però la sentenza, pur senza negare 
l'incompatibilità di MSJVM con Java. Sun si 
rifiutò di fornire il sorgente aggiornato a 
Microsoft. MSJVM, distribuito da Microsoft, 
divenne presto obsoleto rispetto agli 
sviluppi di Java. MSJVM è più lento, più 
soggetto a "crash" e con meno funzioni 
rispetto alle versioni più recenti di Java. Il 
23 Gennaio 2001 Microsoft e Sun trovarono 
un accordo che permise di mettere fine alla 
controversia legale in California, ma 
Microsoft decise di lavorare ad 
un'alternativa a Java, quello che oggi noi 
conosciamo come .NET framework. Anche 
in questo caso si tratta di una piattaforma 
"trasversale" e che utilizza un linguaggio 
diverso da Java. Il 13 Febbraio 2002 
Microsoft cominciò la distribuzione 
commerciale del primo prodotto contenente 
il framework .NET, ossia Visual Studio 
.NET Nello stesso tempo Microsoft smise di 
fornire MSJVM, che infatti non è incluso in 



WindowsXP, anche se è poi stato reinserito 
nel Service Pack 1, con annuncio che 
comunque nel prossimo futuro sarà 
abbandonato. Sun reagì affermando che 
Microsoft stava sfruttando i vantaggi 
derivanti dalla precedente attività illegale 
(rispetto alla legge antitrust) con la quale 
aveva frammentato la piattaforma Java e 
distrutto i canali di distribuzione di cui Sun 
si era avvalsa. Sun intraprese quindi 
un'altra azione legale, richiedendo che 
Microsoft distribuisse l'ultima versione, 
fornitale a costo zero, del binario (il 
sorgente non essendo più fornito a 
Microsoft già da un po' di tempo) di Java 
(Java Runtime Environement: JRE) con tutti 
i pacchetti Windows e con Internet 
Explorer; che JRE venisse installato ed 
abilitato automaticamente; che Microsoft 
rendesse disponibile JRE tramite il sito 
Windows Update; e che Microsoft 
annunciasse la prossima disponibilità di 
nuove versioni di Windows e di Internet 
Explorer con almeno 120 giorni di anticipo, 
e non modificasse in alcun modo il codice 
binario di JRE. La corte di giustizia del 
Maryland ha dato ragione a Sun e quindi, se 
la decisione non sarà annullata in appello 
(Microsoft ha già annunciato che presenterà 
ricorso) gli utenti Windows dovrebbero 
presto avere a disposizione JRE tramite il 
sito di aggiornamento di Windows. Non 
solo: i prossimi CD di Windows, nonché le 
distribuzioni di Internet Explorer, 
conterranno JRE. 

http://it.sun.com 

Intel presenta i nuovi 
compilatori 

Disponibile la versione 7.0 
dei compilatori Intel C+ + 
e Intel Fortran per Windows 
e Linux 

I nuovi compilatori Intel permettono 
di sviluppare applicazioni che 
possano avvalersi della tecnologia 
Hyper-Threading di Intel, grazie alla 
quale si possono eseguire più attività 
contemporaneamente. I compilatori 
sono stati ottimizzati per i processori 
Intel Itanium 2, Intel Pentium 4 e Intel 
Xeon, e consentono di realizzare 
applicazioni compilate in modo più 
efficace per velocizzare le operazioni. 
Tra le varie applicazioni che potranno 
beneficiare dell'ottimizzazione, i 




programmi commerciali orientati alle 
transazioni, le applicazioni finanziarie 
ad elaborazione intensiva e quelle 
tecniche e scientifiche, i programmi 
multimediali digitali, i videogame e gli 
effetti speciali. I nuovi compilatori 
supportano funzioni di Compaq Visual 
Fortran, tra cui la compatibilità a 
livello di riga di comando, e prevedono 
l'integrazione con Microsoft Visual 
Studio. La versione di Linux prevede la 
compatibilità a livello di GNU con C++ 
con l'adozione dell'interfaccia binaria 
delle applicazioni C++. I nuovi 
compilatori Intel versione 7.0 
comprendono inoltre un'opzione di 
parallelizzazione automatica, tramite 
la quale, nelle applicazioni, viene 
automaticamente ricercata la 
possibilità di creare più thread 
esecutivi e miglioramenti per il 
supporto OpenMP, standard di settore 
che consente l'uso di direttive di alto 
livello per semplificare la creazione e la 
gestione di software multithreaded. 
I compilatori Intel C++ versione 7.0 per 
Windows e Linux sono già disponibili 
al prezzo di listino consigliato di 399 
dollari USA ciascuno. I compilatori 
Intel Fortran versione 7.0 per Windows 
e Linux sono altresì disponibili al 
prezzo di listino consigliato di 499 e 
699 dollari rispettivamente. I 
compilatori possono essere acquistati 
tramite download presso Intel e i 
rivenditori di tutto il mondo, e saranno 
presto disponibili anche su CD-ROM. 

www.intel.com/software/products/ 



8 ►►► F e b b 



http: //www. itportal.it 



w 



Allarme BSA: giovani 
pirati in aumento 



La pirateria informatica tra i 
ragazzi europei allarma la 
Business Software Alliance 

La Business Software Alliance ha espres- 
so forte preoccupazione per il numero 
crescente di casi di pirateria software su In- 
ternet in Europa che vedono coinvolti i mi- 
nori. Tre casi sottoposti recentemente dalle 
polizie locali all'attenzione dell' European 
Internet Investigation Team della BSA, il 
gruppo di investigatori dedicato alla ricerca 
di siti internet illegali, hanno visto infatti la 
partecipazione di minori ad attività com- 
merciali illegali. In tutte e tre le occasioni le 
autorità hanno intrapreso opportune azioni, 
mentre altri casi simili sono attualmente al 
vaglio degli inquirenti. Nel Regno Unito 
uno studente sedicenne è stato incriminato 
per aver venduto software pirata su siti 
d'aste online, mentre in Svizzera un minore 
è stato arrestato per aver pubblicizzato e 
venduto software pirata su un sito Web spe- 
cializzato in piccoli annunci. Sempre in 
questo paese, uno studente minorenne è 
stato incriminato perché vendeva CD conte- 
nenti software "pirata". In tutti i casi la ma- 
gistratura ha imposto severe pene pecunia- 
rie alle quali, in una circostanza, si sono ag- 
giunte anche restrizioni sull'uso futuro di 
Internet. Studi recenti dimostrano che alcu- 
ni genitori giudicano innocuo questo tipo di 
attività e tendono a chiudere un occhio con 
il risultato che i minori vengono incriminati 
e i genitori sono costretti a pagare multe ele- 
vate. Organizzazioni come la BSA compio- 
no ogni sforzo per spiegare ai giovani i ri- 
schi insiti in queste attività, ma senza l'atti- 
va collaborazione dei genitori si tratta spes- 
so di sforzi vani. 

Il Tablet PC diventa 
un bloc-notes evoluto 

Alias Wavefront annuncia 
uno strumento software 
intuitivo per trasformare il 
Tablet PC in un bloc notes 
digitale 

Alias SketchBook Pro permetterà agli 
utenti di cambiare i pennelli elettro- 
nicamente, di fare e rifare velocemente i 
propri lavori, di manipolare immagini 



» g 


i.^M,jÌ 




?l| Make your mark. 

I £'.-■ la ..--t Ci- *~<v 


:rrr 


«ijd.-.KPT.U.tPC 




£- 






T,H. l P t ,H.I. B ».in.„,, S , II ,,d 


EjjExpertZone 


^ ^Z^^^—--'™"^-^*- 








rT.. 




H~" :: 






~ 



















sovrapposte e di integrare gli schizzi 
digitali dall'interno del mondo Windows 
XP. Pensato appositamente per i Tablet 
PC, Alias SketchBook Pro offre la 
possibilità di fare bozzetti, annotare 
informazioni e immagini, presentare il 
proprio lavoro ogni volta che si realizza 
una nuova idea creativa: Alias 
SketchBook Studiato per una vasta 
gamma di utenti aziendali e grafici 
professionali, Alias Sketchbook Pro si 
basa sulla tecnologia grafica sviluppata 
da Alias I Wavefront per i software Maya 
e Studio Tools. Supportato da 
un'interfaccia utente basata sui gesti che 
offre agli utenti la possibilità di cambiare 
strumenti e colori, utilizzare la funzione 
di zoom, salvare e modificare gli schizzi, 
Alias Sketchbook Pro introduce un 
insieme di strumenti di sketching 
semplice ma completo. 
È possibile creare una raccolta di schizzi 
che possono essere visualizzati, 
organizzati e distribuiti facilmente, o 
effettuare presentazioni formali e 
improvvisate di sketch e immagini e 
registrare qualsiasi feedback 
istantaneamente. Infine, Marking Menu è 
un'interfaccia utente ergonomica che 
riconosce i movimenti naturali della 
mano per selezionare i comandi. Alias 
Sketchbook Pro sarà disponibile nei 
primi mesi del 2003. 

www.aliaswavefront.com/sketchbook 
www.microsoft.com/tabletpc 

Hi Tech: più imprese 
che esperti! 

Sono ancora numerose le 
figure con competenza 
adeguata che mancano nel 
settore Ict italiano... 

Il rapporto 2002 Occupazione e 
formazione nell'Ict nasce con l'auspicio 
di analizzare dinamiche, caratteristiche e 



opportunità del mondo occupazionale 
dell'information & communication 
technology italiano. La capacità di 
sviluppo delle piccole e medie imprese e 
il dinamismo del settore richiedono uno 
sforzo di riqualificazione sia delle 
aziende stesse sia del personale 
coinvolto, come ha spiegato Giulio Koch, 
presidente di Assinform. È necessario 
avviare un processo di rinnovamento che 
coinvolga tutti i protagonisti per 
adeguare la formazione di base. 
Secondo le elaborazioni di Unioncamere i 
lavoratori delle imprese Ict quest'anno 
sono 598.000 (di cui ben il 52,8% è 
impiegato nelle aziende di software e 
servizi), dato che porta il settore al 
settimo posto nella classifica 
dell'industria privata per numero di 
addetti. Le imprese che hanno sistemi 
informativi arretrati investono 
maggiormente in corsi che hanno come 
meta l'alfabetizzazione, le altre investono 
di più in formazione tecnica e 
professionale, ha commentato Capitani. 
Dal rapporto emerge un dinamismo forte 
sulla crescita della formazione, ma c'è un 
livello di inadeguatezza decrescente, 
perché si registra un processo di rapida 
obsolescenza delle competenze. Inoltre la 
compenetrazione tra le tecnologie e i 
processi ne velocizza ancora di più 
l'obsolescenza. 

Secondo il rapporto, la carenza di risorse 
specializzate genera diversi problemi: 
primo fra tutti l'impossibilità di 
realizzare un progetto. Ma ci sono anche 
la perdita di competitività verso i 
concorrenti, quella d'immagine verso i 
clienti per il ritardo del progetto, o la 
possibilità di prendere decisioni 
sbagliate. 

Nella formazione non c'è sistematicità, 
afferma Franco Patini, presidente 
An@sin. Si passa da esempi di eccellenza 
ad arretratezza. Manca una diffusione 
omogenea e qualitativamente ideale. 
Inoltre, il Paese non investe 
nell'istruzione, perché manca la capacità 
di lavorare insieme. Senza dimenticare 
che gli investimenti hanno valori 
marginali e che siamo in presenza di una 
scarsa coscienza del valore strategico 
della formazione. 

Non bisogna cercare il ritorno di valore 
della conoscenza, bensì il valore della 
competenza. 

www.assinform.it 
www.unioncamere.it 



http: //www. itportal.it 



2 



3 ►►► 9 



Frasi 

anagrammate 



Riveste particolare interesse sia nel campo 

enigmistico che in quello della programmazione, 

la produzione automatica di anagrammi 

multiparola, ovvero che in generale trasformano 

frasi in frasi. 



role, come nel caso standard, ma più in generale 
insiemi di parole. Vedremo che le tecniche algorit- 
miche per la produzione di questi interessanti tipi 
di anagrammi si basano su quelle sviluppate per 
il caso base, studiate nel numero scorso e di cui 
daremo un breve ma significativo cenno nel pros- 
simo paragrafo. 



// 



i 



"1 mago di fibra": metafora postmoderna 
di esperto di reti ad alta velocità, "Ma- 

-glio di fibra": una variante più aggressi- 
va della figura precedente, "Figlia morbida": deli- 
cata immagine familiare, "Fa orli di gambi": atti- 
vità artigiana che ricorda ambienti bucolici e an- 
cora "Il dio fra gambi" soggetto a limite tra il flo- 
reale e il blasfemo; ecco un insieme di figure a me 
intrinsecamente legate, diciamo pure mie strette 
parenti, frasi che con me, "Fabio Grimaldi", sono 
in forte relazione. Si tratta, infatti, di anagrammi 
multiparola del mio nome e cognome o se preferi- 
te frasi anagrammate. Gli amanti dell' enigmistica 
sanno benissimo che stiamo parlando di un intri- 
gante gioco che si fa con parole. Qualche altro 
esempio? Presto serviti. Un anagramma di Geor- 
ge Bush è "He bugs Gore", che se valutato prima 
delle elezioni presidenziali assume un perverso 
carattere premonitore. Con la presenza della dou- 
blé (w), si innesca l'interessante anagramma "He 
grew bogus", che svela la presunta personalità del 
president, sarà davvero cresciuto falso? chissà. 
Stiamo scherzando ovviamente, tutti giochi di pa- 
role, come l'anagramma di "Madonna Louise 
Ciccone" la pop star di origine italiana che dopo 
una rimescolata di lettere si trasforma in "Occa- 
sionai nude income". Mentre, curioso è l'ana- 
gramma di un conosciuto sistema operativo di 
mamma Microsoft, infatti, "Windows Me" diven- 
ta nuova saggezza, ossia "new wisdom". In que- 
sto appuntamento tenteremo un salto di qualità, 
oltre a produrre un semplice anagramma, dove 
per semplice intendo un anagramma che è una 
nuova permutazione delle lettere di una singola 
parola che a sua volta ha un senso compito, tente- 
remo di sviluppare un algoritmo per la genera- 
zione di frasi anagrammate. Come sarà risultato 
chiaro dai precedenti esempi, un anagramma 
multiparola o una frase anagrammata è un parti- 
colare anagramma per il quale la stringa di origi- 
ne e quella di destinazione non sono singole pa- 



LA VERSIONE ZIPPATA 
DELLA PUNTATA 
PRECEDENTE 

Per comprendere le tecniche che svilupperemo, 
per chi non ha letto il precedente numero, è ne- 
cessario conoscere alcune fondamentali nozioni. 
In tal modo il presente articolo sarà completa- 
mente indipendente dal precedente anche se di 
questo ultimo si consiglia quanto meno una rapi- 
da lettura. La ricerca di anagrammi assume una 
complessità non esponenziale con una semplice 
quanto efficace idea. La stringa da anagrammare 
anziché essere confrontata in tutte le sue permu- 
tazioni con tutte le parole presenti in un diziona- 
rio, che sarebbe una operazione di elevatissima 
complessità per la natura esponenziale del calco- 
lo combinatorio, viene confrontata con una firma 
associata alla parola. La firma di una parola non è 
altro che la permutazione di lettere della stessa in 
modo ordinato, ad esempio la firma della parola 
anagramma è aaaagmmnr. Una volta individuata 
per ogni parola la sua firma, basta accorpare (col- 
lassare) le firme uguali mantenendo la lista per 
ognuna di esse delle parole che le hanno genera- 
te. Infine, bisogna ordinare la struttura per firma. 
Abbiamo ottenuto quello che è stato definito di- 
zionario delle firme. Qualora si vuole ricercare un 
anagramma basta prendere la parola da anagram- 
mare (sorgente) calcolarne la firma ed effettuare 
una ricerca binaria sul dizionario delle firme, 
quindi esaminare se esiste la liste delle parole as- 
sociate a quella firma. Insomma, fatto salva la 
produzione di un dizionario delle firme che è una 
operazione da effettuare una tantum e che co- 
munque ha una complessità computazionale poli- 
nomiale, la ricerca avrà complessità ancora mino- 
re che come si sa, per la ricerca binaria è di tipo lo- 
garitmico. Nell'articolo precedente si potranno 
trovare utili approfondimenti nonché la struttura 
dell'algoritmo risolutore che sicuramente chiarirà 
eventuali dubbi. 



10 ►►► F e b b 



3 



http://www.itportal.it 



PRODURRE ANAGRAMMI 
MULTIPAROLA 

Anagrammare una frase producendo un'altra fra- 
se non è altro che una naturale estensione del me- 
todo appena descritto. Sarà necessario ovviamen- 
te prestare alcune attenzioni. Anche questa volta 
invito chi volesse approfondire l'argomento a vi- 
sitare il sito allestito da uno dei pionieri dell'ana- 
grammatica in Italia, il conosciuto Corrado Giu- 
stozzi, che da poco, e di questo tutti ne siamo fie- 
ri, è entrato a far parte della grande famiglia di io- 
Programmo. Il sito a cui vi rimando che contiene 
un interessante motore di ricerca di anagrammi è 
http:/ /www .nightgaunt.org/anagrams. Ma esaminia- 
mo il metodo, cerchiamo di capire come si possa- 
no produrre anagrammi multiparola sulla base 
dei saperi acquisiti. Il primo passo da compiere è 
quello di considerare Finterà frase come un'unica 
parola, questa operazione di concatenazione delle 
singole componenti della frase si ottiene banal- 
mente eliminando dalla stringa di partenza gli 
spazi, ottenendo in tal modo una sequenza di let- 
tere. Di questa stringa bisogna calcolare la firma 
che indicheremo con sorgente. Si tratta adesso di 
ricercare anagrammi all'interno della firma sor- 
gente. Per farlo si valuta la generica firma consul- 
tata nel dizionario omonimo, che chiameremo og- 
getto, e la si compara con la firma sorgente. Una 
generica firma rispetto alla sorgente può trovarsi 
in tre casi diversi. 

Il primo, è che le due firme siano coincidenti, vor- 
rà dire che siamo stati fortunati e che quindi ab- 
biamo quanto meno trovato un anagramma, pos- 
siamo quindi procedere per la ricerca di altri ana- 
grammi. Il secondo caso si ha quando la firma og- 
getto, ossia quella consultata nel dizionario delle 
firme, sia contenuta nella sorgente. Ciò porta a 
sperare che nella restante parte di stringa sorgen- 
te vi siano altre parole (firme) e che quindi si pos- 
sa comporre la frase anagramma ta. Quindi in tal 
caso si procede sottraendo alla firma sorgente 
quella contenuta e riapplicando lo stesso procedi- 
mento di ricerca anagrammi alla stringa così otte- 
nuta, è evidente che la stringa oggetto debba es- 
sere accantonata momentaneamente da qualche 
parte. Riapplicare lo stesso procedimento signifi- 
ca richiamare la stessa routine che stiamo descri- 
vendo passando questa volta non la firma sorgen- 
te ma la firma ottenuta dalla sottrazione tra la sor- 
gente e la oggetto. Il terzo caso si ha quando la fir- 
ma sorgente non è contenuta in quella oggetto, 
ovviamente in tale situazione si scarta la soluzio- 
ne e si passa alla valutazione delle successive fir- 
me oggetto consultate nell'apposito dizionario. 
Merita uno specifico approfondimento il secondo 
punto la cui definizione svela la natura ricorsiva 
del procedimento. Si tratta, infatti, di applicare la 
stessa procedura man mano a stringhe di lun- 
ghezza minore fin quando non si verifica la con- 



dizione di uscita che può coincidere con il primo 
caso se viene trovato un anagramma multiparola 
o con il presentarsi più volte del terzo caso (esplo- 
razione di tutte le possibili soluzioni) se siamo 
sfortunati e quindi non esiste alcuna frase ana- 
grammata. La struttura ricorsiva attua un ricerca 
esaustiva di soluzioni che gli affezionati della se- 
zione soluzioni di ioProgrammo conosceranno si- 
curamente, giacché mi capita di proporla periodi- 
camente. 

Mi sto riferendo ovviamente al backtracking. Si 
noti che la ricerca in profondità non sempre va a 
buon fine, può capitare che per diverse volte si 
trovi una firma oggetto nella sorgente o comun- 
que nella firma derivata dalla sorgente per suc- 
cessive sottrazioni di stringhe oggetto e che si per- 
venga comunque ad un vicolo cieco. Può accade- 
re cioè che applicando più volte il secondo caso 
non si trovi una stringa che sia uguale o contenu- 
ta nella sorgente, quindi bisogna fare un passo in- 
dietro (back) eliminare cioè l'ultima stringa ogget- 
to e ricercare nuove soluzioni. Se anche questo ca- 
so non presenta soluzioni sarà necessaria un'altra 
retromarcia, secondo la ben conosciuta tecnica del 
backtracking. Solo per inciso ricordiamo che si 
presta ad essere gestita attraverso Fuso di uno 
stack con il quale si tiene traccia di tutte le chia- 
mate a procedura con la push ed il rilascio delle 
stesse con la pop. Ad ogni modo i moderni com- 
pilatori implicitamente gestiscono la ricorsione 
con Fuso di uno stack di sistema. Ma queste sono 
tutte nozioni che ben possedete, per cui andiamo 
avanti analizzando ancora più a fondo il metodo 
per svelarne tutti i segreti e per poter poi svilup- 
pare una struttura di algoritmo risolutore. Per fa- 
re il punto della situazione, deve essere chiaro 
che nel momento in cui l'algoritmo confronta la 
firma oggetto con la firma sorgente (per sorgente si 
intende anche quella che si ottiene man mano dal- 
la sottrazione della prima firma sorgente con le 
successive oggetto prodotte) si possono verificare 
tre dei casi appena descritti. 
Con il primo si esce e si ottiene una soluzione, 
semplicemente raccogliendo tutte le stringhe og- 
getto prodotte, si procede quindi automaticamen- 
te per la generazione di altre soluzioni riapplican- 
do l'algoritmo a partire dalla firma immediata- 
mente successive a quelle valutate. Con il secondo 
si procede in profondità con la ricerca e si genera- 
no le soluzioni parziali come stringhe oggetto. In- 
fine, con il terzo si torna indietro, si effettua un 
back, e si passa alla procedura chiamante. La ri- 
cerca termina quando tutte le soluzioni possibili 
sono state esplorate, ovvero quando sono termi- 
nate le firme oggetto da valutare rispetto alle 
stringa sorgente iniziale. 

Ovviamente, la ricerca può risultare infruttuosa 
quindi in alcuni casi può non produrre alcun ana- 
gramma multiparola. 



Curiosità 



\/%\ Vi sono alcune 
\^\ curiosità di carat- 
tere storico geografico 
legate all'affascinante 
mondo degli anagram- 
mi. Tra le più antiche si 
annovera un aneddoto, 
che sembra avere soli- 
di riscontri storici, se- 
condo il quale il re di 
Francia Luigi XIII ave- 
va nominato e stipen- 
diato una persona con 
il solo compito di pro- 
durre anagrammi. Da 
un punto di vista geo- 
grafico è interessante 
notare che il Giappone 
è runico paese al mon- 
do che ha importanti 
città che sono tra loro 
anagrammi Tokyo e 
Kyoto. 



http://www.itportal.it 



3 ►►► 11 



Ó 



Varianti 

di anagrammi 

I patiti dell'enig- 
mistica hanno con- 
cepito nuove ed inte- 
ressanti varianti degli 
anagrammi. Tra le più 
curiose vi è il pana- 
gramma che non è altro 
che un anagramma co- 
stituito da tutte le lette- 
re dell'alfabeto (26 nel 
caso più generale di al- 
fabeto anglosassone). 
Si definisce anigramma, 
ossia anagramma ani- 
mato da anigram, un 
modo animato di mo- 
strare la formazione 
dell'anagramma. Per in- 
tenderci gli anigrammi 
possono essere effica- 
cemente prodotti con 
strumenti come macro- 
media flash. Per con- 
cludere la mini rasse- 
gna è interessante la fi- 
gura dell'anugramma 
(traduzione di anu- 
gram) che è un partico- 
lare anagramma multi- 
parola che non cambia 
il significato. Vi ripro- 
pongo l'esempio in in- 
glese che ho trovato in 
giro per internet, sono 
sicuro che ve ne sono di 
sorprendenti anche in 
italiano: 

Eleven plus two = 

Twelve plus one 

Insomma la somma fa 
sempre thirteen, tredi- 
ci, 13. Da notare che, 
per una generica frase, 
gli anugrammi sono dei 
sotto insiemi degli ana- 
grammi, ma non vale il 
contrario. 



ALCUNE IMPORTANTI 
CONSIDERAZIONI 

L'output dell' algoritmo che ci apprestiamo a svi- 
luppare secondo il procedimento appena descrit- 
to è una sequenza, a volte lunga, di "frasi". Ho 
usato le virgolette per specificare che non si tratta 
propriamente di frasi ma si ha a che fare con se- 
quenze di parole tutte rigorosamente appartenen- 
ti al dizionario della lingua italiana. Chi però, 
pensava che il risultato finale fosse un insieme di 
frasi tutte di senso compiuto rimarrà un po' delu- 
so. Uoutput prodotto va trattato manualmente in 
due modi. Premetto che è raro il caso in cui una 
delle frasi prodotte abbia una semantica corretta. 
Quindi il primo tentativo consiste nel valutare la 
sequenza di parole per capire se è possibile di- 
sporle in modo differente tale da dare un signifi- 
cato alla frase. Se il tentativo non porta i frutti spe- 
rati bisogna passare all'eliminazione della se- 
quenza. 



Con questa doppio accorgimento al termine della 
valutazione manuale otterremo il risultato spera- 
to. Di seguito è riportato uno scorcio del output 
prodotto dal motore di ricerca sviluppato da Cor- 
rado Giustozzi a fronte del mio nome e cognome 
fornito come input. 



Permutazioni 

PERMUTAZIONI SEMPLICI 

Il numero di permutazioni di n elementi è pari 

al fattoriale di n: 

Pn = n! 

=n*(n-l)*(n-2)*..*l 
P0=1 

PERMUTAZIONI CON ELEMENTI RIPETUTI 
Se le permutazioni presentano gli stessi 
elementi nella stessa configurazione, cioè se a 
è il numero di volte che si ripete un dato 
elemento, b le ripetizioni di un secondo 
elemento, e di un terzo e così via. Allora le 
permutazioni in cui sono presenti degli 
elementi ripetuti sono uguali a: 

P(a,b,c,..)n= 

Come esempio consideriamo un'urna con- 
tenente palline di colore: giallo, rosso e blu. 
Le Pn saranno: 

grb, gbr, bgr, brg, rbg, rgb 

che come suggerisce la formula sono sei. Si 
parla di permutazioni distinte con elementi 
ripetuti quando uno o più elementi possono 
riproporsi più volte. Se alcuni elementi si 
ripetono a,b,c .. volte allora indicheremo tali 
permutazioni come: 

P(a,b,c,..)n 

Ovviamente a parità di n le permutazioni con 
elementi ripetuti sono in numero minore. Dove 
n è il numero totale di elementi, computando 
cioè anche le ripetizioni. Se cioè si vuole fare 
l'anagramma della parola "pippo", n vale 5 e 
non 3. 

Utili riferimenti sull'argomento si possono 
trovare nell'articolo della sezione Soluzioni 
ioProgrammo n. 18 - autore Fabio Grimaldi. 





154: 


dal fiori gambi 




155: 


darò fili gambi 




156: 


di fa gambi orli (fa orli di 


gambi) 


157: 


di farà globi mi 




158: 


di fari gambi lo 




159: 


di fari gambo il 




160: 


di faro gambi il 




161: 


di faro gambi li 




162: 


di fibra il mago (il mago 


di fibra) 


163: 


di fibra li mago 




164: 


di fibra maglio (maglio di 


fibra) 


165: 


di fora gambi il 







Le scritte tra parentesi sono state riportate da me 
manualmente per dare senso alla frase. È possibi- 
le sperare che in futuro l'output finale di un qual- 
siasi motore sia una frase di senso compiuto, ma 
il problema come gli esperti di linguistica auto- 
matica ben sanno è alquanto spinoso. Non a caso 
si riscontrano, ad esempio difficoltà nella tradu- 
zione automatica di testi da diverse lingue. Ma la 
trattazione si fa complessa, magari sarà oggetto di 
una futura discussione tra queste pagine. 

L'ALGORITMO DI RICERCA 

Facendo riferimento alla struttura dati ed alle rou- 
tine presentate la scorsa volta, un'implementazio- 
ne del procedimento già accuratamente descritto 
potrebbe essere la seguente. Non si tenga conto 
della presentazione ne tanto meno dell' efficienza. 
Lo scopo di questo paragrafo è descrivere il meto- 
do di chiamata ricorsiva che innesca il back- 
tracking. Cominciamo con quello che può essere 
definito mairi program: 

Il mairi program 

inizio 

scaricadizfirme(sorgfirme, firme) 

leggi(frase) 

sorgente <- calcolafirma(concatena(frase)) 

anagrammamulti(sorgente, destinazione) 

scrivi(destinazione) 

fine 

Si caricano le firme, si legge la frase da anagram- 
mare, la si concatena e si calcola la firma, poi si ri- 
chiama la procedura di produzione di anagrammi 
multipli anagrammamulti. 
Uoutput sarà riportato sul vettore destinazione 



12 ►►► F e b b 



3 



http://www.itportal.it 



(ogni riga-cella una frase anagrammata) 

// Proc anagramma multi 

inizio 

i<-0 

ripeti 

sorg<-sorgente 

i <-i+l 

j<-' 

va luta (firma^], sorg) 

finche i = max 

scrivi(destinazione) 

fine 

Supponendo che tutte le firme siano presenti in 
un vettore si scorre questo ultimo al fine di com- 
parare le singole firme con la stringa sorgente 
chiamata sorg. La procedura valuta è il fulcro del 
programma. Si controlla che l'indice delle firme 
non sia in overflow (max è il numero di firme), poi 
verifichiamo se ci troviamo nel caso 1 prima de- 
scritto, se così fosse avremmo trovato una solu- 
zione e potremmo tornare nella procedura ana- 
grammamulti alla ricerca di altre. Se la condizione 
precedente è falsa si controlla che la firma j-esima 
sia contenuta nella stringa parziale sorg. In tal ca- 
so si sottrae la stringa firma da sorg, si aggiunge al 
risultato parziale oggetto e si valuta ricorsivamen- 
te la stringa rimanente. Se invece la condizione 
non è vera prima di abbandonare la procedura 
chiamante per effettuare il backtracking si incre- 
menta la j per poter valutare la prossima firma, 
automaticamente l'oggetto si libera dall'ultima 
soluzione (poiché si fa riferimento all'oggetto pre- 
cedente). 

// Proc valuta 

inizio 

se j< = max allora 

azzera(oggetto) 

se sorg=firme[j] allora 

oggetto<-aggiungi(oggetto,sorg) 

soluzione(destinazione, oggetto) 

altrimenti 

se contenuto(firme[j], sorg) allora 

sorg < -sottraici rme[j], sorg) 

oggetto<-aggiungi(oggetto, sorg) 

valuta(firma[j],sorg) 

altrimenti 

fine 

Le procedure aggiungi e sottrai fanno rispettiva- 
mente una concatenazione e una estrazione di 
stringhe. Mentre soluzione aggiunge al vettore de- 
stinazione la stringa oggetto. I blocchi di codice 
vanno valutati per come sono intentati. L'algorit- 
mo è migliorabile e personalizzabile come si può 
riscontrare nelle applicazioni presenti anche su 



internet che sviluppano motori di ricerca di ana- 
grammi multiparola. Ad esempio, si possono ap- 
plicare alcuni vincoli come il numero di parole 
della frase, la presenza o l'assenza forzata di spe- 
cifiche parole e altro. Può essere uno stimolante 
esercizio pensare a come si possa modificare l'al- 
goritmo per attuare tali estensioni. 

CONCLUSIONI 

Le applicazioni degli anagrammi non sono sol- 
tanto ludiche, vengono ad esempio usate in com- 
plessa materia di crittografia ed in altre applica- 
zioni avanzate. Ad ogni modo spero che l'argo- 
mento sia stato gradito. Personalmente lo apprez- 
zo molto perché è uno di quei casi, come altri che 
ho presentato tra queste pagine e che ricerco per 
studiarli ed eventualmente tradurli in articoli, in 
cui sono egualmente interessanti e sorprendenti 
sia il problema in se che la sua soluzione algorit- 
mica. È arrivato il momento di congedarmi, la 
versione postmoderna di esperto di reti ad alta 
velocità è pronta per voi a ricercare nuove ed 
emozionanti soluzioni. Alla prossima!! 

Il mago di fibra 
Fabio Grimaldi 



Backtracking 



Gli algoritmi di backtracking sono anche cono- 
sciuti come tecniche di ricerca esaustiva della 
soluzione di problemi. Consistono in algoritmi 
che esplorano tutte le possibili soluzioni proce- 
dendo, per così dire, per tentativi. Nel caso più 
generale l'obiettivo finale viene diviso in sotto- 
obiettivi, ognuno di essi viene risolto in modo 
assestante, per cui può essere a sua volta par- 
tizionato in ulteriori problemi con corrispon- 
denti sotto-obiettivi. Analizzando l'approccio al- 
la soluzione si denota una logica ricorsiva. La ri- 
cerca della soluzione come esplorazione di sot- 
to-obiettivi può essere interpretata come la vi- 
sita di un albero di obiettivi dove i nodi sono ap- 
punto sotto-obiettivi ognuno dei quali può ave- 
re dei sotto-alberi come discendenti, ovvero al- 
tri sotto-obiettivi. Qualora la ricerca lungo un 
sotto albero risulti infruttuosa bisogna tornare 
indietro (back) ed esplorare altri rami. Questo 
parallelo "botanico", ci indica i pregi e i difetti 
del metodo, per cui se da un lato esplorando, 
nella peggiore delle ipotesi tutto l'albero, si per- 
viene alla soluzione, è anche vero che l'albero 
può crescere secondo andamenti esponenziali 
rendendo di fatto la risoluzione alquanto costo- 
sa, in termini di complessità temporale; in alcu- 
ni casi il costo è così elevato da rendere la tec- 
nica sostanzialmente impraticabile. Per ovviare 
questo ultimo aspetto negativo si rendono ne- 
cessari metodi di potatura dell'albero che esclu- 
dano a priori, secondo logiche proprie del parti- 
colare problema, alcune soluzioni. 
Utili riferimenti sull'argomento si possono tro- 
vare negli articoli delle sezioni Soluzioni ioPro- 
grammo nei numeri 12, 19, 26 e 27 - autore Fa- 
bio Grimaldi 



http://www.itportal.it 



3 ►►► 13 




XML e 
Flash 



File sul CD^ 

\soft\codice\FlashXML.zip 



XML e Flash 

L'UTILE ED IL DILETTEVOLE 
SI INCONTRANO 



Esploriamo in questo articolo 

l'avvincente possibilità di 

interazione tra Macromedia 

Flash ed il protocollo XML, 

creando un'applicazione di 

esempio che usufruisca di tale 

tecnologia per implementare un 

menu dinamico, costruito 

interamente a partire da un file 

XML. Vedremo nel dettaglio il 

supporto che Flash offre per 

scambiare dati in questo 

formato, analizzando le funzioni 

più utilizzate dell'oggetto XML 

che Macromedia ha messo per 

noi a disposizione nel suo 

gioellino. 



Oggigiorno, quasi tutto ciò che viene prodotto 
dall'industria del software riguarda in qual- 
che maniera i dati e la loro elaborazione. Dal 
negozio virtuale al gestionale aziendale, oramai non vi 
è applicazione che non faccia uso di una base dati, sia 
questa un database relazionale o un semplice file di te- 
sto con la propria semantica. Esistono molti modi dif- 
ferenti per accedere, manipolare ed elaborare i dati e 
nuove tecnologie nascono ogni giorno per aggiungere 
funzionalità a quelle già esistenti: tra tutte, XML è 
quella che nel tempo ha riscosso maggior successo, sia 
per la sua semplicità che per la sua integrazione per- 
fetta anche tra sistemi eterogenei. Un fattore impor- 
tante per lo sviluppatore che si accinge ad utilizzare 
nel proprio software il protocollo XML, è la consape- 
volezza di trovare API o wrapper di supporto per la 
maggioranza dei linguaggi di programmazione e nel- 
la quasi totalità dei sistemi operativi; la sua struttura 
basata su markup, infatti, permette una facile imple- 
mentazione di software che la interpreti, perlomeno 
per quanto riguarda le funzionalità più basilari. L'in- 
sieme di oggetti software (Document Object Model o 
DOM in breve) che permettono l'interazione con dati 
XML varia nella sua completezza di sistema in sistema 
e di produttore in produttore, e a seconda natural- 



mente delle necessità del software che ne farà uso. La 
maggior parte delle applicazioni che utilizzano XML, 
sfrutta il DOM messo a disposizione dal sistema ope- 
rativo; Microsoft, ad esempio, sviluppa uno dei DOM 
XML più completi ed evoluti, tramite cui lavorare con 
flussi XML diventa un gioco da ragazzi. Basta dare 
un'occhiata su MSDN nella sezione dedicata a 
MSXML (questo è il nome in codice del prodotto) per 
farsi un'idea di quanto questo componente software 
sia potente. Gli sviluppatori di Macromedia Flash 
Player, vista la natura multi piattaforma che avrebbe 
avuto tale software, hanno preferito non affidarsi ai 
vari DOM dei sistemi operativi per i quali andavano 
sviluppando ma hanno optato per costruirsi un DOM 
proprietario, in comune tra tutte le implementazioni 
di player. Il supporto XML di Flash, reso disponibile 
solo a partire dalla versione 5.0, non offre molte fun- 
zionalità e, a prima vista, il suo funzionamento appa- 
re davvero criptico, anche (e oserei direi soprattutto) 
per chi già utilizza altri DOM XML; i vantaggi offerti, 
però, dallo studio di questo modello ad oggetti e dalla 
conseguente possibilità di elaborare dati XML tramite 
Flash sono molti e aprono le porte a progetti software 
completamente dinamici e di altissimo impatto visivo. 
Scopo di questo articolo, come già annunciato, è la rea- 
lizzazione di un'applicazione Flash che costruisca di- 
namicamente un semplice menu a partire da un file 
XML che ne descrive interamente le funzionalità e la 
struttura: il risultato sarà completamente dinamico e 
indipendente dai dati. La qualità estetica dell'applica- 
zione esula dall'obiettivo preposto, pertanto si lascia 
alla fantasia del lettore l'ampliamento di quest'ultimo 
punto. 

IN PRINCIPIO FU XML 

Prima attrice della nostra applicazione è senz'altro la 
base dati XML, impiegata come sorgente strutturale 
del menu che andremo a costruire. Seguendo la buona 
pratica, stabiliamo a priori lo schema seguito dalla 
struttura descrittiva del nostro menu; innanzitutto de- 
cidiamo di quali dati abbiamo bisogno per visualizza- 
re gli elementi - ovvero le voci - di cui quest'ultimo è 
composto. Fortunatamente il nostro problema è molto 
semplice e possiamo tranquillamente convenire che 
per creare una voce di menu ci occorrono due dati fon- 
damentali, un testo descrittivo della voce e un uri ver- 
so cui puntare. Stabiliamo, inoltre, che entrambi i va- 



14+» F e b b 



http://www.itportal.it 



TECNICA 



lori saranno di tipo stringa. Definita così la struttura 
della singola voce, affermiamo ancora che a livello glo- 
bale ciascuna voce può contenere a sua volta un nu- 
mero n di sottovoci con caratteristiche uguali alla pri- 
ma. Quest'ultima asserzione ci permette la costruzio- 
ne dinamica di menu a più livelli. 
Vediamo una realizzazione applicativa di quanto ap- 
pena descritto: 



<menu> 



<elementi> 



<voce testo="Edizioni Master" url = 
"http://www.edmaster.it" /> 



<elementi> 



<voce testo="Prodotti" url = 
"http ://www.edmaster.it/?job= prodotti" /> 



<elementi> 



<voce testo="ioProgrammo" url = 

"http://www.edmaster.it/?job=prodotti&id=4" /> 
<voce testo="Internet Magazine" url = 

"http://www.edmaster.it/?job=prodotti&id=3" /> 



</elementi> 



<voce testo ="ITPortal" url="http://www.itportal.it/" /> 



</elementi> 



<voce testo="Macromedia" url = 
"http://www.macromedia.com" /> 



<elementi> 



<voce testo="FlashMX" url = 

"http://www.macromedia.com/software/flash/" /> 



</elementi> 



<voce testo="World Wide Web Consortium" url = 
"http://www.w3c.org" /> 



</elementi> 



</menu> 

Si osservi la struttura gerarchica descritta dal docu- 
mento appena esposto: un tag radice, menu, raggrup- 
pa T intero insieme di dati. Con ordine, caratteristica 
fondamentale per la buona riuscita di qualsiasi siste- 
ma software, vengono raggruppate tutte le voci di me- 
nu del primo livello sotto il tag elementi, appartenente 
al tag radice. Al di sotto di elementi, vengono esposti i 
tag voce, che incapsulando gli attributi testo e uri dan- 
no vita alle voci di menu di primo livello. Gli elemen- 
ti voce, come è possibile osservare chiaramente nell'e- 
sempio proposto, possono contenere essi stessi il tag 
elementi, che a loro volta possono contenere tag di tipo 
voce, così da permettere, come si annunciava, la possi- 
bilità di creare menu a livelli multipli. 
Nel nostro fine applicativo, continuiamo lo sviluppo 
del menu e diamo nome al file appena creato Me- 
nu, xml) una volta salvato il file, lo rendiamo disponibi- 
le per la lettura da parte di Flash, salvandolo nella stes- 
sa cartella dove risiederà l'swf che andremo a costrui- 
re nel resto dell'articolo. Si tenga presente che Flash, se 
utilizzato all'interno di una pagina html sotto forma di 
plugin, consente di default l'apertura di file XML che 
sono residenti solo all'interno dello stesso sottodomi- 
nio dell' swf caricato: nella maggioranza dei casi ciò si- 



gnifica che il plugin di Flash non consente di caricare 
dati da un sito web che non sia quello da cui viene lan- 
ciato l'swf. A tale limitazione, studiata in effetti per 
non essere tale ma per offrire un livello di sicurezza 
maggiore agli utenti del plugin, va incontro anche la 
funzione LoadVariablesO, così come il nuovo oggetto 
LoadVars di FlashMx, che altro non è che un wrapper 
di quest'ultima. 






li Master" url="http://ivww. edmaster.it" /> 

testo="Prodotti" url="http://wwiM.edmaster.it/?job = prodotti" /> 

e testo="ioProgrammo" url="http://wvjvj.edmaster.it/?job = prodotti8!Ìd = 4" /> 

e testo="Internet Magazine" url="http://wwvj.edmaster.it/?job = prodotti8:id = 3" /> 



<voce testo="ITPortal" url="http://wiMi 
</elementi> 
<voce testo="Macromedia" url="http://vj 



.itportal.it/" /> 

iw.macromedia.c 

.macromedia.coi 



<voce testo="FlashMX" url="http://i 
</elernenti> 
<voce testo="World Wide Web Consortium" url="http://i 



i/software/flash/" /> 
(.vj3c.org" /> 



Fig. 1: Il menu XML appena creato, aperto tramite 
Internet Explorer. 



Non soffrono di questo limite, invece, gli swf non in- 
globati in pagine html ma aperti in maniera diretta tra- 
mite il player apposito (solitamente utilizzato dai soli 
sviluppatori Flash). 

L'INTERFACCIA 

Come già anticipato, la porzione del nostro applicati- 
vo che opererà con l'utente utilizzerà unicamente l'in- 
terfaccia Flash 5 (e l'html necessario per istanziare il 
plugin swf). Le operazioni che affidiamo a questo mo- 
dulo sono a livello logico abbastanza semplici; sostan- 
zialmente utilizzeremo actionScript per caricare la 
struttura XML appena creata e per visualizzare a video 
il nostro menu, utilizzando quest'ultima come direttri- 
ce. Per chiarezza, dividiamo il codice che andremo a 
sviluppare in tre step: acquisizione dei dati, elabora- 
zione dei dati e visualizzazione a video. Creiamo quin- 
di il movie con cui lavoreremo nel resto dell'applica- 
zione di esempio. Non sono importanti qui le impo- 
stazioni grafiche, lascio al lettore il piacere di procede- 
re verso questa direzione come meglio crede. Il codice 
actionScript che andremo a creare nel resto dell'appli- 
cazione risiederà pertanto per semplicità nel primo e 
unico frame del nuovo movie. Con la convinzione che 
effettuare una buona progettazione ora servirà a facili- 
tarci le cose in un secondo momento, procediamo a 
scendere nel dettaglio dell'implementazione degli step 
di cui si accennava poche righe fa. Non nascondo che 
la difficoltà si abbatte drasticamente se la base dati è 
ben predisposta: fortunatamente quest'ultima è stata 
creata da zero ed ho preferito dare ad essa una strut- 
tura chiara e facile. Di conseguenza i primi due step - 
acquisizione dei dati e elaborazione dei dati - non ci 
creeranno troppi grattacapi. L'acquisizione dei dati av- 
viene in maniera pressoché automatica; eccone il codi- 
ce: 

1 var xmlMenu = new XML(); 




XML e 
Flash 



XML e Flash 

L'utile ed il dilettevole 
si incontrano 



Dom 

yift L'insieme di og- 
—^ getti software (Do- 
cument Object Model o 
DOM in breve) che per- 
mettono l'interazione 
con dati XML varia nella 
sua completezza di si- 
stema in sistema e di 
produttore in produtto- 
re, e a seconda natural- 
mente delle necessità 
del software che ne farà 
uso. 



http://www.itportal.it 



3 ►►► 15 




3 xmlMenu.ignoreWhite = true; 



XML e 
Flash 



XML e Flash 

L'utile ed II dilettevole 
si Incontrano 



XML e Flash 

y^ft II supporto XML di 
■^s Flash, reso dispo- 
nibile solo a partire dal- 
la versione 5.0, non of- 
fre molte funzionalità 
e, a prima vista, il suo 
funzionamento appare 
davvero criptico, anche 
(e oserei direi soprat- 
tutto) per chi già utiliz- 
za altri DOM XML; i van- 
taggi offerti, però, dallo 
studio di questo model- 
lo ad oggetti e dalla 
conseguente possibilità 
di elaborare dati XML 
tramite Flash sono mol- 
ti e aprono le porte a 
progetti software com- 
pletamente dinamici e 
di altissimo impatto vi- 
sivo. 



4 xmlMenu.onLoad = MenuLoaded; 



5 xmlMenu.load('Menu.xml'); 

In questa prima porzione di codice avviene la creazio- 
ne dell'oggetto XML e del caricamento dei dati pre- 
senti nel menu XML, creato poco fa. Andando nel det- 
taglio viene effettuata la dichiarazione e la creazione 
dell'oggetto xmlMenu (1), viene impostata la proprietà 
ignoreWhite a true (2), associato all'evento onLoad la 
funzione MenuLoaded che tra poco analizzeremo (3) e 
infine caricato il file menu.xml (4). Fino a qui non pos- 
siamo ancora determinare se tale file è stato caricato o 
meno nell'oggetto xmlMenu. Per poterlo fare è neces- 
sario entrare nel dettaglio della funzione che viene lan- 
ciata non appena il caricamento del file XML è termi- 
nato. 

10 function MenuLoaded(bSuccess) 

ili 

12 ifQbSuccess) { 

13 trace('Menu non caricato.'); 

14 return; 

15_J 

16 

17 trace('Menu caricato.'); 

18 

19 var ndRoot = xmlMenu.firstChild; 

20 var ndElementi = ndRoot.firstChild; 

21 

22 DisplaySubMenu(ndElementi, 0); 

23} 



Come anticipato, MenuLoaded viene richiamata quan- 
do il caricamento del file XML termina. È possibile sa- 
pere se tale caricamento è andato a buon fine analiz- 
zando il parametro bSuccess, booleano, valorizzato a 
false in caso di problemi, a true altrimenti. Come è pos- 
sibile osservare, il codice d'esempio effettua un trace 
dichiarando lo stato dell'operazione (13 e 17) e in caso 
questa non sia stata andata a buon fine esce dalla fun- 
zione (14) annullando di fatto l'intera operazione. Nel- 
l'ipotesi in cui menuXML contenga la struttura presen- 
te nel file menu.xml, vengono dichiarate due variabili. 
La prima, ndRoot (19), è in realtà il primo elemento 
presente all'interno della struttura XML, ciò che nella 
totalità dei DOM XML presenti nel mercato viene chia- 
mato nodo radice) per Flash tale nodo è dunque il pri- 
mo nodo figlio del documento XML caricato. Vista la 
struttura del documento XML, è conveniente creare 
una funzione generica (Display SubMenu), incaricata di 
elaborare in maniera ricorsiva i dati presenti nel tag 
elementi. Tale funzione visualizzerà i tag voce presenti 
nella struttura che verrà passata in parametro e richia- 
merà sé stessa qualora vi fossero altre strutture ele- 
menti figlie di quella originale. L'idea della ricorsione 
è molto utile in casi come questi dove le operazioni da 
effettuare per un blocco di dati sono identiche per n 



blocchi di uguale struttura. Data la necessità di elabo- 
razione del tag elementi, richiediamo al nodo radice la 
referenza alla struttura di primo livello di questo tipo 
e associamo alla variabile ndElementi tale referenza. 
Valorizzata ndElementi, richiamiamo la funzione Di- 
splay SubMenu di cui ora verrà fatta analisi approfondi- 
ta. 

30 var verticalDeep = 0; 

31 

32 function DisplaySubMenu(xmlData, deep) 

Hi 

34 var ndVoce = xmlData.firstChild; 



35 while(ndVoce) 



26_L 



37 switch(ndVoce.nodeName) 



38 { 



39 



case voce : 



40 DisplayMenuItem(ndVoce, deep); 



41 verticalDeep+ + ; 



42 break; 



43 case 'elementi' 



44 DisplaySubMenu(ndVoce, deep + 1); 



45 break; 



46 } 



47 



48 ndVoce = ndVoce.nextSibling; 



49 } 



50} 

Display SubMenu è la funzione cuore della fase dell'ela- 
borazione dei dati. Come è possibile osservare nella 
sua dichiarazione (32), sono previsti due parametri di 
chiamata. Il primo, xmlData, sarà un nodo XML di tipo 
elementi. Il secondo parametro, deep, altro non sarà che 
la profondità orizzontale del submenu, in altre parole 
il livello del menu che la funzione andrà a creare. Non 
a caso nella chiamata effettuata in MenuLoaded (22), 
deep è impostato a zero. Alla stessa maniera viene 
mantenuta una variabile globale, verticalDeep (30), ini- 
zializzata a zero che altro non è che la profondità ver- 
ticale del menu: servirà nella fase di visualizzazione 
per disegnare le voci di menu una sotto l'altra. La fun- 
zione crea dapprima la variabile ndVoce e la fa punta- 
re al primo nodo figlio del nodo elementi ricevuto co- 
me parametro (34). Viene poi iniziato un ciclo che du- 
rerà fintanto che ndVoce sarà un nodo valido (35). Suc- 
cessivamente, se ndVoce è un tag di tipo voce (39) que- 
sto viene passato alla funzione DisplayMenuItem (40) 
che si occuperà di visualizzare la voce a video (la ve- 
dremo in seguito); se invece tale nodo è di tipo elemen- 
ti (43), viene applicato il concetto di ricorsione già an- 
ticipato per cui viene chiamata nuovamente Display- 
SubMenu (44), valorizzando questa volta il parametro 
deep ad un valore incrementato di uno rispetto al deep 
originale. 

Infine ndVoce viene valorizzata con il suo nodo succes- 
sivo dello stesso livello (48): qualora questo nodo non 
esistesse (al termine della struttura XML), ndVoce verrà 



!&►►► F e b b 



http://www.itportal.it 



TECNICA 



impostata automaticamente a nuli, di fatto interrom- 
pendo il ciclo. Va altresì aggiunto che verticalDeep vie- 
ne incrementata ad ogni visualizzazione di voce di 
menu (41), proprio al fine di tenere traccia della 
profondità verticale nelle fase di presentazione dei da- 
ti. Al fine di ottimizzare lo sfruttamento delle risorse e 
migliorare la qualità del nostro lavoro, risulta ora con- 
veniente prevedere la costruzione di un movieclip da 
utilizzare come modello di visualizzazione delle voci 
di menu. Tale movieclip verrà inserito nella library del 
movie su cui stiamo lavorando e ci permetterà di riu- 
tilizzarlo per costruire le n voci di menu di cui neces- 
sitiamo; la funzione di visualizzazione si occuperà 
dunque di duplicare questo movieclip e di impostar- 
ne le proprietà necessarie affinchè ogni voce contenga 
i dati corretti. Creiamo dunque preventivamente il 
movieclip mvVoce, dotiamolo di un testo dinamico al 
quale associeremo la variabile Testo. Fatto questo im- 
portiamolo nella library, ricordando di spuntare nelle 
proprietà di linkage la checkbox Export for Action- 
Script: tale impostazione ci permetterà di lavorare col 
movieclip presente nella libreria anche tramite il codi- 
ce che andremo a creare. Finiti i preparativi, vediamo 
dunque nel dettaglio la funzione di visualizzazione 
delle voci di menu. 

60 function DisplayMenuItem(xmlData, deep) 

§LL 

62 attachMovie('mvVoce', 'dmvVoce' + verticalDeep, 
verticalDeep); 

63 var mvCurrent = eval('dmvVoce' + verticalDeep); 

64 

65 mvCurrent.onRelease = functionQ { 

66 getURL(xmlData.attributes.url); 



67_i 



68 



69 mvCurrent. Testo = xmlData.attributes. testo; 



70 mvCurrent._x = 20 * deep; 



71 mvCurrent. _y = (mvCurrent. _height + 2) * 

verticalDeep; 

72} 

Come si è già potuto osservare, DisplayMenuItem vie- 
ne richiamata con il parametro xmlData che punta ad 
un nodo voce della nostra struttura XML ed il para- 
metro deep che indica il livello corrente del menu (ma 
anche il suo scostamento orizzontale, nel nostro caso). 
Inizialmente la funzione crea un nuovo movieclip (62), 
duplicando mvVoce, presente nella library. A questo 
duplicato viene assegnato un nome, creato dinamica- 
mente, formato dalla stringa dmvVoce (la d sta per di- 
namico) e dalla profondità verticale che cambia ad 
ogni chiamata. Eseguita la duplicazione, viene asse- 
gnata alla variabile mvCurrent la referenza a tale nuo- 
vo movieclip (63), allo scopo di impostarne le proprietà 
nelle righe successive. Tramite la referenza appena 
creata, impostiamo la risposta air evento onRelease del 
movieclip (65): trattandosi di una voce di menu, non 
facciamo altro che eseguire un getURL verso il colle- 



gamento specificato dall'attributo uri del nodo XML 
voce preso in esame (66). Impostiamo inoltre la varia- 
bile Testo, associata al testo dinamico creato in prece- 
denza air interno del movieclip mvVoce: il nuovo valo- 
re sarà quello dell'attributo testo del nodo voce corrente 
(69). Non ci resta che impostare le coordinate entro cui 
il nuovo movieclip sarà disegnato; impostiamo dun- 
que l'attributo _x ad un valore di scostamento a piace- 
re (neir esempio si è scelto 20) che ovviamente andrà 
moltiplicato per la profondità orizzontale del menu 
(70). 



Edizioni Master 
Prodotti 

• io Programmo 

* Internet Nagazine 
ITPortal 

Macromedia 

FlashMX 
World Wide Web Consortium 



Fig. 2: L'interfaccia Flash, dopo un piccolo ritocco 
grafico. 

Infine impostiamo l'attributo __y pari all'altezza del 
movieclip più un valore di scostamento a piacere (nel- 
l'esempio 2), moltiplicando il tutto questa volta per la 
profondità verticale. Il motore di visualizzazione del 
nostro menu XML è ora pronto e funzionante; sarà 
sufficiente solo qualche accorgimento grafico per in- 
globarlo nelle vostre soluzione dinamiche basate su 
tecnologia Flash. 



CONCLUSIONI 

Le possibilità offerte dall'elaborazione dei dati tramite 
il motore XML fornito da Flash sono notevoli; nono- 
stante il supporto incompleto che questo prodotto of- 
fre per la manipolazione dei dati secondo tale model- 
lo, è comunque facile creare applicazioni completa- 
mente dinamiche che utilizzano l'interfaccia Flash. 
L'interesse di Macromedia verso questa tecnologia 
sembra comunque essere in continuo aumento: se fino 
alla versione 5 il motore XML era codificato interna- 
mente tramite actionScript (con l'enorme penale della 
velocità di esecuzione), con la versione MX di Flash la 
casa produttrice ha scelto di optare per una compila- 
zione in C++, inglobando il supporto XML nello stes- 
so motore del player. 

Nella visione globale del web, sia le componenti ser- 
ver che quelle client tendono sempre più verso la tec- 
nologia XML, facendone di fatto uno standard verso 
cui guardare con fiducia. Non ci rimane che sfruttare 
al meglio ciò che il mercato ci propone, seguendo que- 
sta tendenza che, come abbiamo visto nel corso del- 
l'articolo, offre ampi spunti di riflessione per mettere 
all'opera la fantasia. 

Efran Cobisi 




XML e 
Flash 



XML e Flash 

L'utile ed il dilettevole 
si incontrano 



XSLT 

r-& Il linguaggio XSLT 
^-J {eXtensible Style- 
sheet Language Transfor- 
mations), nasce dall'esi- 
genza di definire uno stru- 
mento generale che con- 
senta di trasformare e ma- 
nipolare un documento 
XML. Così come per l'XML, 
anche l'XSLT prende vita 
dal consorzio W3C, organo 
che si occupa della sua 
standardizzazione. La ver- 
sione corrente di XSLT è la 
1.0 (raccomandazione 
W3C del 16 Novembre 
1999), al momento della 
stesura di questo testo è 
stata proposta la versione 
1.1, attualmente reperibile 
come working draft 
http: //www. w3. org/TR/xsltl 1/ 



http://www.itportal.it 



2 3 ►►► 17 



:: i;AAAMÌ_ 




XML e 

Flash 



XML e Flash 

L'utile ed il dilettevole 
si incontrano 



XPath 

y-S II linguaggio XPath 
--J viene utilizzato per 
formulare espressioni in 
grado di valutare ogni 
nodo di un documento 
xml e di svolgere deter- 
minate operazioni su di 
essi, restituendo a parti- 
colari valori di tipo strin- 
ga, numerici o booleani. 
Il metodo con il quale 
XPath esplora le diverse 
strutture di nodi, all'in- 
terno del documento 
XML, è denominato per- 
corso di posizione. Un 
percorso di posizione di- 
spone di una sintassi 
specifica che consente di 
includere operatori ed 
espressioni utilizzati nel- 
l'individuazione di parti 
di un documento in base 
al tipo di struttura che 
rappresentano. 



L'OGGETTO XML DI ACTIONSCRIPT 
PRONTUARIO DELLE FUNZIONI PIÙ USATE 



new XML([sorgente]) 

È il costruttore dell'oggetto XML, vale a dire il metodo da ri- 
chiamare per creare un oggetto di questo tipo. Accetta op- 
zionalmente come unico parametro una stringa di testo XML 
con cui istanziare il nuovo oggetto. 

Es: Creazione di un nuovo oggetto XML vuoto 



var xOggetto = new XML(); 

Es: Creazione di un nuovo oggetto XML con alcuni dati 

var xOggetto = new XML('<provincia>PD</provincia> 

<provincia>Mk/provincia> 



PROPRIETÀ 

attributes 

È un array associativo che contiene gli attributi xml di 
un particolare nodo. 



Es: Accesso ad un attributo xml 

var xOggetto = new XML('<provincia sigla="PD" 

descrizione="Padova" /xprovincia sigla="MI" 

descrizione="Milano" />'); 

trace(xOggetto.firstChild.attributes.sigla); 

// Visualizza in output la stringa PD 



childNodes 

È un array che contiene i nodi figli di un particolare no- 
do xml. 

Es: Accesso al secondo nodo figlio di una struttura 
XML 

var xOggetto = new XML('<provincia sigla="PD" 

descrizione="Padova" /xprovincia sigla="MI" descrizio- 

ne="Milano" />'); 

var xFiglio = xOggetto. childNodes[1]; 



firstChild 

Proprietà di un qualsiasi oggetto XML che punta al pri- 
mo nodo figlio di quest'ultimo. È conseguentemente 
una scorciatoia per oggetto. childNodes[0]. Nel caso in 
cui l'oggetto XML non abbia nodi figlio, tale proprietà 
ritorna nuli. 



lastChild 

Proprietà di un qualsiasi oggetto XML che punta all'ul- 
timo nodo figlio di quest'ultimo. Anche qui, nel caso in 
cui l'oggetto XML non abbia nodi figlio, tale proprietà 
ritorna nuli. 



ignoreWhite 



Proprietà booleana che indica, se impostata a true, di 
non prendere in considerazione gli spazi e i ritorni di 
carrello presenti tra un tag ed un altro. È molto utile in 
tutti quei casi dove la struttura xml che si va a leggere 
contiene questi tipi di caratteri e ciò è molto comune, 
specie se il vostro file XML è chiaro ed ordinato. 
Di default è impostata a false, quindi Flash interpreta in 
maniera scorretta tali tipi di file. È consigliabile impo- 
starla di regola sempre a true prima di procedere alla 
lettura di qualsiasi struttura XML. 



Ioaded 

Proprietà booleana che indica il corretto caricamento 
della struttura XML in cui viene chiamata. Se ritorna 
true, il documento è stato caricato con successo. 

Es: Controllo sullo stato di caricamento dell'oggetto 
XML preventivamente creato 

trace(xOggetto.loaded); 

// Se xOggetto è stato caricato correttamente visualizza 

true in output. 



nextSibling 



Ritorna l'oggetto XML successivo nello stesso livello 
corrente, appartenente allo stesso nodo genitore. Que- 
sta proprietà è utile quando si intende effettuare la 
scansione di un intero set di nodi XML appartenenti ad 
uno stesso nodo genitore. 

Es: Stampa in output tutti gli oggetti figlio di un parti- 
colare nodo XML 

var xOggetto = new XML('<provincia sigla="PD" /> 

<provincia sigla="MI" /xprovincia sigla="RM" />'); 

var xFiglio = xOggetto.firstChild; 

while(xFiglio) // Questo ciclo si ferma se xFiglio è nuli 

{ 

trace(xFiglio. attributes. sigla); // Visualizzo di ogni 
elemento l'attributo sigla 



xFiglio = xFiglio.nextSibling; 



L 



//Visualizza PD MI RM 



previousSibling 

Ritorna l'oggetto XML precedente nello stesso livello 
corrente, appartenente allo stesso nodo genitore. Que- 
sta proprietà è utile quando si intende effettuare la 
scansione di un intero set di nodi XML appartenenti ad 
uno stesso nodo genitore. La funzionalità è inversa ri- 
spetto a quella offerta da nextSibling. 

Es: Stampa in output tutti gli oggetti figlio di un parti- 
colare nodo XML (scansione all'indietro) 

var xOggetto = new XML('<provincia sigla="PD" /> 

<provincia sigla="MI" /xprovincia sigla="RM" />'); 

var xFiglio = xOggetto.lastChild; 



while(xFiglio) // Questo ciclo si ferma se xFiglio è nuli 



L 



trace(xFiglio. attributes. sigla); // Visualizzo di ogni 
elemento l'attributo sigla 



xFiglio = xFiglio.previousSibling; 



1_ 



Il Visualizza RM MI PD 



18 ►►► F e b b 



http://www.itportal.it 



TECNICA 



PROPRIETÀ 

nodeName 

Proprietà che ritorna il nome del tag del nodo XML corrente. 

Es: Stampa in output del nome del tag del primo nodo pre- 
sente in una struttura XML 

var xOggetto = new XML('<provincia sigla="PD" /xprovincia 

sigla="MI" /xprovincia sigla="RM" />'); 

var xFiglio = xOggetto.firstChild; 

trace(xFiglio.nodeName); 

// Visualizza provincia 



nodeType 

Proprietà che ritorna il valore 1 se il nodo XML corrente è un 
elemento, il valore 3 se il nodo è un nodo contenente solo te- 
sto. Si noti che Flash tratta i nodi testuali come unici nodi fi- 
glio del nodo che li contiene. 

Es: Stampa in output del tipo di nodo per due nodi XML 

var xOggetto = new XML('<provincia sigla="PD"> 

<commento>Si trova in Veneto</commento></provincia'); 
trace(xOggetto.firstChild.nodeType); // provincia 



uguale a 3). Ritorna il testo presente all'interno del nodo. 

Es: Stampa in output del valore di un nodo testuale 

var xOggetto = new XML('<provincia sigla="PD"> 

<commento>Si trova in Veneto</commento></provincia'); 
trace(xOggetto.firstChild.firstChild.firstChild.nodeValue); 

// Nodo testuale all'interno di commento 

// Visualizza Si trova in Veneto 



parentNode 

Ritorna il nodo genitore di un particolare nodo XML. Se tale 
nodo XML non appartiene ad alcun nodo genitore, la pro- 
prietà ritorna nuli. 



status 

Proprietà che indica se un documento XML è stato caricato 
nell'oggetto XML con successo. Ritorna un valore interpreta- 
bile come segue: 



trace(xOggetto.firstChild.firstChild.firstChild. nodeType); 

// Nodo testuale all'interno di commento 

// Visualizza 1 3 

nodeValue 

Proprietà utile solo per i nodi di tipo testuale (nodeType è 






Nessun errore 


-2 


Una sezione CDATA non è stata chiusa correttamente 


-3 


La dichiarazione XML non è corretta 


-4 


La dichiarazione DOCTYPE non è corretta 


-5 


Un commento non è stato chiuso correttamente 


-6 


Un elemento XML non è corretto 


-7 


Memoria esaurita 


-8 


Un valore di attributo non è stato chiuso correttamente 


-9 


Un tag iniziale non è stato chiuso con un tag finale 


-10 


Un tag finale non è stato aperto da un tag iniziale 






METODI 

load(url) 

Carica il documento XML specificato nel parametro uri. Tale 
documento deve risiedere nello stesso sottodominio del mo- 
vie Flash chiamante. A caricamento completato si occupa di 
impostare il valore di loaded pari a true e scatena l'evento 
onLoadQ. 

Es: Caricamento di un file XML 

var xOggetto = new XMLQ; 

xOggetto. Load('http://localhost/f ile. xml'); 



parseXML(testoXML) 

Carica la struttura XML specificata nel parametro testoXML. 
Tale struttura andrà a sovrascrivere quella precedente (se 
esistente). La sua funzione è analoga a quella offerta dal co- 
struttore della classe. 



Es: Caricamento di una struttura XML 



var xOggetto = new XMLQ; 



xOggetto. parseXML('<provincia sigla="PD"xcommento> 

Si trova in Veneto</commentox/provincia') 



hasChildlModes() 



Ritorna un valore booleano che indica se il nodo corrente ha 
nodi figlio o meno. 



getBytesLoadedQ 



Ritorna il numero di byte caricati per il documento corrente. 
Utile se utilizzata in coppia con getBytesTotalQ per fornire 
percentuali di caricamento dei documenti XML. 



getBytesTotal() 



Ritorna la dimensione in byte del documento corrente. 




XML e 

Flash 



XML e Flash 

L'utile ed il dilettevole 
si incontrano 



I percorsi 
di posizione 

r& I percorsi di posizio- 
ne/ ne rappresentano il 
più importante strumen- 
to per generare espres- 
sioni XPath. Un percorso 
di posizione consente di 
avere accesso ai nodi, sia 
nello specifico del conte- 
sto, sia indipendente- 
mente dal contesto; pos- 
siamo formalizzare un 
percorso di pozione con 
un'espressione che iden- 
tifica un insieme di nodi 
dell'albero, ognuno di 
questi noto come node- 
set. 



EVENTI 

on Load(bSuccess) 

Evento scatenato dalla funzione LoadQ quando il documento 
XML da caricare viene caricato. Il parametro che le viene pas- 
sato (bSuccess) è di tipo booleano e indica se il documento 
è stato caricato con successo (true) o no (false). 

Es: Caricamento di una documento XML dal web 



var xOggetto = new XMLQ; 



xOggetto.onLoad = function(bSuccess) 



L 



if(bSuccess) 



{ trace('Documento caricato con successo.'); } 



else 



[ trace('Documento non caricato!') 



L 



xOggetto. Load('http://localhost/file.xml'); 



http://www.itportal.it 



3 ►►► 19 



PASSWORD 



A "PORTATA DI MANO 



// 



Prendendo spunto da quanto discusso 

la scorsa volta sulla sicurezza di 

Windows e sui meccanismi di 

autenticazione, parliamo questa volta 

delle procedure di autenticazione 

biometriche, basate sul 

riconoscimento delle impronte digitali. 



Nel numero precedente di ioProgrammo, si è 
ampiamente parlato della sicurezza di 
Windows 2000 /XP e si è analizzato, da vi- 
cino, il meccanismo di autenticazione implementato 
da Microsoft per il suo sistema operativo, illustran- 
do come fosse possibile modificare il modulo di lo- 
gin (chiamato GINA), per crearne uno personalizza- 
to. La personalizzazione del sistema di accesso di 
Windows è oggi spinta al limite dalle aziende infor- 
matiche che si occupano di Information Security, 
che spesso accoppiano le tecnologie da noi trattate 
nel precedente articolo con i dispositivi biometrici 
per realizzare meccanismi di autenticazione che 
possono fare a meno delle password! 

I SISTEMI BIOMETRICA 

U autenticazione e il riconoscimento dell'identità nel 
mondo informatico, oggi, sono argomenti che susci- 
tano notevole interesse, grazie soprattutto air espan- 
sione dei dispositivi biometrici (il cui costo è ormai 
alla portata di tutti) e a fronte delle continue richie- 
ste nei settori commerciale/militare. Proprio per 
questo motivo ioProgrammo si è sentita in obbligo 
di approfondire queste tematiche, cercando, con 
questo articolo, di trattare alcuni aspetti delle tecno- 
logie biometriche. Stando alla definizione classica, 
un generico sistema di autenticazione può essere 
classificato in una di queste tre categorie, contraddi- 
stinte dalle diverse tecniche utilizzate: 

• autenticazione mediante dati /informazioni che 
una persona conosce (password /PIN); 

• autenticazione mediante oggetti /dispositivi che 
una persona possiede (chiavi fisiche come le 
smartcard); 

• autenticazione mediante caratteristiche fisiche 
uniche dell'interessato (impronte digitali, voce, 
retina); 



La scienza della biometria, nata sul finire degli anni 
1950, si occupa proprio di quest'ultima categoria, 
cioè quella che tratta Y autenticazione e il riconosci- 
mento effettuato mediante la rilevazione delle carat- 
teristiche fisiche individuali di ciascuna persona, 
realizzato - ovviamente - con l'ausilio dei computer. 
In questo articolo ci occuperemo di un ramo parti- 
colare della biometria, quello che studia le impronte 
digitali, discutendo dapprima il ruolo dei sistemi 
biometrici nel mondo informatico e mostrando, infi- 
ne, un esempio di applicazione biometrica capace di 
schedare (e successivamente identificare) le perso- 
ne, mediante un apposito scanner di impronte digi- 
tali, gentilmente concesso in uso, per i nostri esperi- 
menti, dalla Eutron (www.eutron.it), società leader 
nel settore dell' Information Security. I requisiti ne- 
cessari per una corretta lettura degli argomenti trat- 
tati sono ridotti al minimo: le nozioni essenziali ri- 
guardo le tecniche biometriche saranno esposte nel- 
la parte introduttiva dell'articolo, mentre per la 
comprensione del codice è richiesta la sola cono- 
scenza di Visual Basic e dell'uso delle API; natural- 
mente la compilazione e l'uso dei sorgenti di esem- 
pio necessitano di un sensore di impronte digitali 
come quello prodotto dalla Eutron e dell'apposito 
SDK. 



PERCHE UNA PASSWORD 
NON BASTA? 

Perché non basta usare semplicemente una pas- 
sword? E' una domanda che molti si pongono, in 
maniera del tutto legittima, e alla quale si può ri- 
spondere con qualche piccola statistica prelevata dai 
documenti del consorzio per le tecnologie biometri- 
che (www.biometrics.org). Le password "costano" 
troppo, non garantiscono un'adeguata sicurezza e 
sono poco pratiche. 

Qualche dato indicativo testimonia che ciò che stia- 
mo dicendo è vero: 

• la maggior parte di telefonate (30-50%) ai centri 
di assistenza sono dovute a problemi degli uten- 
ti con le password; 

• i blocchi dei sistemi dovuti a password dimenti- 
cate causano notevoli perdite in produttività e a 
volte anche perdite di dati; 

• mediamente un hacker è in grado indovinare il 
30% delle password di una rete aziendale me- 
diante appositi tool; 




Biometria 



File sul CD 

\soft\codice\FPDemoVB.zip 



GINA 

y* GINA è l'abbreviazio- 
-^ ne di Graphical Iden- 
tification and Authentica- 
tion e rappresenta il mo- 
dulo di Windows 2000/XP 
responsabile dell'autenti- 
cazione e dell'accesso de- 
gli utenti. Tale modulo è 
localizzato nella libreria di 
sistema MSGINA.DLL ed è 
rimpiazzabile con altri 
moduli che ad esempio 
fanno uso di tecnologie 
biometriche, smartcard, 
chiavi hardware. Per ulte- 
riori approfondimenti su 
GINA fare riferimento al 
numero 65 di ioProgram- 
mo. 



http://www.itportal.it 



2 3 ►►► 21 




Biometria 



Password 

a "portata 
di mano" 



Ó 



Tecnologie 
Biometriche 

Le tecnologie bio- 
metriche fino ad og- 
gi implementate e utiliz- 
zate nel mondo informa- 
tico sono basate su : 

• Riconoscimento 
impronte digitali; 

• Riconoscimento 
facciale; 

• Riconoscimento della 
voce; 

• Riconoscimento della 
geometria della mano; 

• Scansione della retina 
e dell'iride; 

• Riconoscimento della 
firma. 

Si differenziano tra loro 
per caratteristiche come 
l'affidabilità, il costo e la 
praticità di uso. Per 
quanto riguarda il rico- 
noscimento facciale, si è 
ampiamente parlato di 
questo argomento nel 
numero 56 di ioProgram- 
mo. 



• la lunghezza minima di una password "sicura" 
cresce col tempo e con l'aumentare della velocità 
di elaborazione dei calcolatori; 

• l'utilizzo nella vita quotidiana di molti dispositi- 
vi elettronici obbliga gli utenti a ricordare troppe 
password e codici numerici; 

• la maggior parte delle password viene spesso 
trascritta dagli utenti su file in chiaro, su fogli di 
carta e su Post-it, causando una consistente ri- 
duzione della sicurezza; 

Al contrario, le tecnologie di riconoscimento biome- 
trico presentano molti più vantaggi rispetto alle tra- 
dizionali password: l'identificazione è univoca, non 
può essere condivisa da più utenti (cosa che invece 
avviene con le password, che spesso sono infatti 
scambiate tra colleghi e amici!) e non si è costretti a 
ricordare alcuna cosa, né a portar dietro dispositivi 
fisici di accesso che potrebbero essere rubati. L'uni- 
co svantaggio di queste tecnologie era rappresenta- 
to dal costo eccessivo: dico "era" perché oggi il prez- 
zo dei sensori biometrici è diventato talmente conte- 
nuto, da essere oramai accessibile a molte fasce di 
utenti. 



IL PROCESSO BIOMETRICO 

Un sistema biometrico per calcolatori prevede in ge- 
nere tre fasi distinte di lavorazione : 



• Enrollment 

• Verification 

• Identification 

La prima fase è anche detta di "training" ed è ne- 
cessaria per memorizzare l'identità di una persona e 
per raccogliere i dati biometrici che consentiranno 
ad un computer in futuro di identificarla corretta- 
mente. È la fase più delicata del processo, perché è 
qui che si crea il modello (template) rappresentativo 
di una persona: un cattivo modello può indurre in 
errore la macchina, causando false identificazioni 





Ridge 

Eiuling Core 






\ \\ 








Delta Pores R[ó £ c 

Bifurcation 





Fig. 1: STRUTTURA DI UN IMPRONTA 
L'elemento fondamentale di ogni impronta è la 
"ridge line", ossia la cresta, che forma intrecci, 
biforcazioni, spirali e divergenze. Un disegno 
formato da più creste è detto "ridge pattern". 



(un utente potrebbe spacciarsi per un altro) o il ri- 
getto dell'identità reale (l'utente legittimo non viene 
autorizzato perché non riconosciuto). La fase di ve- 
rifica è invece detta "1-to-l matching" ', ossia corri- 
spondenza 1-a-l. E' la fase in cui un utente dall'e- 
sterno fornisce le sue credenziali biometriche (im- 
pronte, voce, retina, ecc.) per consentire al calcolato- 
re di confrontarle col template memorizzato in pre- 
cedenza, in modo da avere un riscontro: in sostanza 
il computer si pone la domanda "sei veramente la per- 
sona che dici di essere?" '. Il processo di identificazione 
è simile a quello di verifica, ma lavora su un set di 
credenziali più esteso: in questo caso si parla di "1- 
to-N matching" , cioè la macchina non conosce l'iden- 
tità di un utente e prova a scoprirla analizzando tut- 
ti i template memorizzati in un database, cercando 
quello più somigliante fra tutti, se esiste. 

LE IMPRONTE DIGITALI 

La scienza delle impronte digitali è antica e moder- 
na allo stesso tempo, nel senso che la sua introdu- 
zione risale a molti secoli prima (la scoperta delle 
impronte è attribuita a Marcello Malpigli, nel 1700 
circa) ma l'uso effettivo dei primi sistemi di ricono- 
scimento a impronte è datato solo intorno al 1950- 
1970, ad opera dell'FBI. Le caratteristiche che rendo- 
no forte l'uso delle impronte digitali sono l'immuta- 
bilità (la configurazione delle impronte è sempre 
identica nel tempo e a tutte le età) e l'unicità (la pro- 
babilità di trovare due impronte uguali è minore di 
10-20 anche per gemelli omozigote), senza contare 
altri fattori come la praticità e l'universalità del si- 
stema. La classificazione delle impronte, in appa- 
renza caotica, segue invece uno schema ben preciso, 
che fa uso di termini tecnici utili per individuare e 
catalogare le forme e i disegni rilevati su un'im- 
pronta: l'elemento fondamentale di un'impronta è 
la cresta (ridge line), che può formare intrecci, bifor- 
cazioni, spirali e divergenze; un disegno formato da 
più creste è detto ridge pattern. Il concetto fonda- 
mentale su cui si basa l'identificazione tramite im- 
pronte digitali sono le minutiae (o minuzie), cioè 
quei punti significativi dove le creste terminano o si 
biforcano. Generalmente basta un insieme di 30-40 
minuzie per avere un'identificazione corretta e con 
basso margine d'errore, infatti il matching fra due 
impronte viene fatto proprio mediante l'analisi del- 
la posizione e dell'orientamento di un certo set di 
minuzie. Può facilmente accadere che impronte di- 
gitali diverse possano avere in comune fra loro qual- 
che minuzia, ma solo l'impronta originale raggiun- 
gerà un numero massimo di corrispondenze di mi- 
nuzie; questo fatto permette inoltre di stabilire un 
valore di soglia nel riconoscimento, utile per au- 
mentare/abbassare la sicurezza del riconoscimento. 
L'identificazione delle impronte fatta dai computer 
si basa sul calcolo dell'immagine direzionale del- 
l'impronta digitale: l'immagine viene dapprima ac- 



22^^^ f 



b b 



http://www.itportal.it 




Fig. 2: MATCHING E MINUTIAE 
L'identificazione delle impronte digitali si basa 
sulle minutiae (o minuzie), punti significativi dove 
le creste terminano o si biforcano. Il matching fra 
due impronte viene fatto proprio mediante 
l'analisi della posizione e dell'orientamento di un 
certo set di minuzie (30-40 sono sufficienti). 

quisita dagli appositi sensori CCD/CMOS che usa- 
no lenti particolari per rilevare le impronte, quindi 
viene ripulita dal rumore e dalle imperfezioni e infi- 
ne trasformata in una immagine B/N, formata da 
zero e uno. A partire da questa immagine si calcola 
r immagine direzionale dell'impronta, dividendo 
r immagine in tante piccole celle immaginarie (come 
se fosse una matrice) e calcolando la tangente ad 
ogni cresta presente nelle varie celle, ossia Y angolo 
di inclinazione. Questo metodo è molto robusto per- 
ché è invariante rispetto alle rotazioni dell'impronta 
e permette quindi un corretto riconoscimento anche 
quando il dito viene poggiato sul sensore con ango- 
lazioni differenti. Una volta ottenuta Y immagine di- 
rezionale si procede al rilevamento delle minuzie 
usando algoritmi molto complicati, molti dei quali 
sono protetti dal segreto più assoluto. 




' 




IMPRONTA DIGITALE 



IMMAGINE DIREZIONALE 



Fig. 3: IMMAGINE DIREZIONALE 
L'immagine direzionale di una impronta è la 
rappresentazione elettronica dell'impronta stessa. 
Si calcola dividendo l'immagine una sorta di 
matrice a blocchi e calcolando la tangente ad ogni 
cresta (l'angolo di inclinazione) presente nelle 
varie celle. 



MAGICSECURE SDK 

Il sistema biometrico MagicSecure progettato dalla 
Eutron si basa su un sensore di rilevamento im- 
pronte (venduto in versione singola o integrato su 
un mouse ottico) dotato di un kit di autenticazione 
per sistemi Windows 2000 e XP. Il software com- 
prende il driver USB necessario per pilotare il sen- 
sore e un rimpiazzamento del modulo MS GI- 
NA. DLL di Windows (di cui si è a lungo parlato nel- 
l'articolo precedente) che consente agli utenti di au- 



tenticarsi usando la normale password o ricorrendo 
all'impronta digitale. 

L'installazione del kit prevede inoltre una utility di 
migrazione account utile per convertire le informa- 
zioni e gli account esistenti sul nuovo modulo GI- 
NA, con la possibilità di memorizzare fino a 10 dita 
per ciascun utente. Ma il motivo per cui ioProgram- 
mo ha scelto di trattare MagicSecure in questo arti- 
colo è un altro: gli sviluppatori interessati air argo- 
mento possono infatti acquistare (separatamente) Y- 
SDK con le librerie, la documentazione (in lingua in- 
glese) e gli esempi necessari per sviluppare softwa- 
re di autenticazione e riconoscimento mediante im- 
pronte digitali, in diversi linguaggi (C++, Visual Ba- 
sic, Delphi). USDK è basato interamente sulla libre- 
ria HBAPI.DLL che esporta una API utilizzabile per 
pilotare il sensore biometrico e per rilevare, visua- 
lizzare e confrontare le impronte digitali. La API è il 
risultato degli sforzi dell'azienda internazionale 
Hunno Technologies Inc. {www.hunno.com), specializ- 
zata da anni in tecnologie e sensori biometrici. La li- 
breria è divisa in due moduli: High-Level API e Low- 
Level API, cioè i programmatori, a seconda della pro- 
pria competenza e delle proprie necessità, possono 
importare funzioni con difficoltà implementativa di- 
versa, con la particolarità che le funzioni High-Level 
sono completamente automatizzate (wizard) nelle 
procedure di acquisizione e riconoscimento impron- 
te. 

LA NOSTRA APPLICAZIONE 
BIOMETRICA 

L'applicazione di esempio si basa sostanzialmente 
su due operazioni : acquisizione e riconoscimento, 
implementate come routine di due diversi pulsanti 
di un form Visual Basic. In aggiunta sul form trovia- 
mo alcuni controlli OptionButton usati per consenti- 
re all'utente di selezionare il livello di soglia del ri- 
conoscimento, che è memorizzato nella variabile 
globale mjiSecuLevel (vedi definizioni di FRR e 
FER). All'avvio il programma cercherà di aprire e 




I Change 



r ,■-.•■'•■•! i ri 



": : alse Rejci tioi 
Rate (FRR)" and 
"False Acceptance 
Rate (FAR)" in case 
of selecting the 
authentication type 
with fingerprint. 



L: 



[tori Type 
Fingerprint 
O Password 

Fingerprint and Password 
Fingerprini or Password 



) [ Annulla j ] Applica 



Fig. 4: PASSWORD O IMPRONTA? 

Il kit MagicSecure venduto da Eutron consente 

agli utenti di autenticarsi e accedere a Windows in 

4 diverse modalità, usando la tradizionale 

password in combinazione con le impronte 

digitali. 




Biometria 



Password 

a "portata 
di mano" 



Prestazioni 

y-S La misura delle pre- 
^-J stazioni di un siste- 
ma biometrico si basa 
sui seguenti indici: 

• FRR (False Rejection 
Rate): misura la fre- 
quenza con cui il sistema 
rifiuta gli utenti legitti- 



• FAR (False Acceptance 
Rate): misura la fre- 
quenza con cui il sistema 
consente l'accesso ad 
utenti non autorizzati; 

• ERR (Equal Error Ra- 
te): errore del sistema 
nel punto in cui vale che 
FRR = FAR; 

In genere FRR(k) e 
FAR(k) sono due funzio- 
ni del parametro "k", 
detto valore di soglia del 
sistema. Il variare di k 
porta in genere all'au- 
mento di un indice e al 
conseguente decremen- 
to dell'altro. 



http://www.itportal.it 



3 ►►► 23 




FingerPrint Recognifion Test 



Biometria 



Password 

a "portata 
di mano" 



Sul Web e^ 

Consorzio BioAPI, fonda- 
to nel 1998, si propone 
l'obiettivo di distribuire 
uno standard per la pro- 
gettazione di applicazio- 
ni biometriche "OS indi- 
pendent." 
http://www.bioapi.org 

Biometrie Systems Lab 
dell'Università di Bolo- 
gna; ottimo repository di 
informazioni e pubblica- 
zioni sulle tecnologie 
biometriche. 
http://bias.csr.unibo.it 
/research/biolab/bio tree.html 



Comandi 


RICONOSCI 




| ACQUISISCI | 




UTENTI : | 3 


CHIUDI 



-SecurityLevel 
C Highest 


C High 


(• Medium 


C Low 


C Lo west 



Created by Elia Florio (ioProgrammo - 2003) 



Fig. 5: DAMMI LA MANO E TI DIRO' CHI SEI 
L'applicazione dimostrativa creata con l'SDK 
consente di acquisire le impronte di più utenti per 
poi salvarle su file, creando un archivio 
personalizzato. In seguito, usando il pulsante 
Riconosci, sarà possibile rilevare l'identità di una 
persona schedata in archivio. 



leggere il file "C:\USERS.DAT" (indispensabile!), 
usato come contatore per memorizzare il numero di 
utenti correntemente schedati dal sistema di ricono- 
scimento. Il progetto VB richiede inoltre, per un cor- 
retto funzionamento, la presenza dell' SDK e deve 
contenere un modulo aggiuntivo con le dichiarazio- 
ni delle funzioni, dei tipi e delle costanti importate 
da HBAPI.DLL. Nel nostro progetto abbiamo fatto 
uso della Low-Level API per Y acquisizione e della 
High-Level API per il riconoscimento. Uapertura 
della periferica di riconoscimento USB e il test della 
sua presenza avvengono così: 

Dim ret As Long 

ret = HTOpen(0, pDevice) 

If (ret >= 0) Then 

nStatus = 

IbStatus = "Posiziona il dito sul lettore di impronte" 
Else 



MsgBox "Impossibile aprire periferica 

di acquisizione impronte digitali" 

End If 

Il codice è auto-esplicativo: si fa uso della funzione 
HTOpen che restituisce un valore Long maggiore o 
uguale a zero se l'operazione è riuscita; i parametri 
da passare alla funzione sono l'ID della periferica e 
una variabile globale (pDevice) in cui verrà memo- 
rizzato il codice associato alla periferica, da usare in 
tutte le successive operazioni. Ovviamente in fase di 
uscita bisognerà chiudere e rilasciare il controllo del 
lettore di impronte usando HTClose. U acquisizione 
di impronte ad alto livello è immediata, basta solo 
chiamare HTEnroll passando i parametri necessari e 
il gioco è fatto: questa chiamata genera infatti una fi- 
nestra indipendente, dotata di icone e grafica, in cui 
è possibile acquisire l'impronta di un qualsiasi dito 
in modo molto semplice; al programmatore non è ri- 
chiesto nessuno sforzo. U acquisizione a basso livel- 
lo è invece più macchinosa e richiede Fuso di un ti- 
mer col quale temporizzare le diverse fasi dell'ac- 
quisizione (periferica pronta, contatto del dito sul 



sensore, rilascio del dito): 



Dim pulReadStatus As Long 



Dim Result As Long 



Dim BufferQ As Byte 



'Lettura singola impronta digitale usando Low-Level API 



'Parametri da passare: 



' periferica da usare (ricavata da HTOpen) 

' variabile di tipo HT_RAW_DATA che conterrà 

l'immagine (raw) dell'impronta letta 

' variabile di tipo HT_BIO_DATA (dati biometrici 

calcolati dall'impronta) 

' stato della periferica 

'Restituisce : 

' boolean (true se l'operazione riesce) 

Dim pRawData As HT_RAW_DATA 

Dim pEnRollBioData As HT_BIO_DATA 

Result = HTRead(pDevice, pRawData, 

pEnRollBioData, pulReadStatus) 

If Result = HT_OK Then 

'Disegna su un frame immagine VB l'impronta 

catturata in pRawData 

Result = HTDrawRawImage(Frame.hWnd, 8, 12, 
160, 160, pRawData) 




Acquisizione Impronta cornp etata 



Fig. 6: LETTURA DELL'IMPRONTA 
Come un moderno mago, il sensore biometrico 
legge la nostra mano, visualizzando le impronte 
sul form....sarà anche in grado di prevedere il 
nostro futuro? 



U impronta digitale, una volta acquisita viene resti- 
tuita dalla funzione HTRead in due formati diversi: 
come HT_RAW_DATA (corrisponde all'immagine 
vera e propria acquisita dal sensore) e come 
HT_BIO_DATA (è la traduzione dell 7 impronta in 
forma biometrica, analizzabile dal computer). La 
memorizzazione su file richiede Y intervento di una 
piccola conversione (eseguita con la API di sistema 
CopyMemory), necessaria per consentire a Visual Ba- 
sic di trattare adeguatamente i dati biometrici: 

'Converte i dati biometrici acquisiti dal lettore 

'in un array di bytes (necessario per l'uso sotto VB) 

ReDim Buffer(pEnRollBioData.ulLength - 1) 

CopyMemory Buffer(O), ByVal pEnRollBioData. pvData, 

pEnRollBioData .ulLength 

'Richiede il nome da associare all'impronta acquisita 
'e lo scrive su file 



nome = InputBox("Nome?", "Assegnazione impronta") 



24 ►►► F e b b 



http://www.itportal.it 



Open "C:\FINGER" 


+ FP_ 


_RecTest.ID + ".TXT" 

For Output As #1 


Print #1, nome 


Close #1 


'Scrive su file i dati biometria dell'impronta acquisita 


Open "C:\FINGER' 
For Binary > 


+ FP_RecTest.ID + ".DAT" 
<\s #1 Len = pEnRollBioData.ulLength 


Put #1, , Buffer 


Close #1 



U impronta di ciascun utente viene infine scritta su 
un file di nome "C:\FFNGERxx.DAT" dove "xx" 
rappresenta il valore numerico del contatore salvato 
in "C:\USERS.DAT" , che viene incrementato ad 
ogni acquisizione. Ad ogni file che memorizza 
un'impronta è associato un file analogo del tipo 
"C:\FINGERxx.TXT" che memorizza invece il nome 
associato alla persona (è un'alternativa scelta per 
evitare Fuso di un database). 



FingerPrint Recognition 



•CormancJi- 



ACQUISISCi 



RICi 



UTENTI 



F 




vel- 
est 



ìs\ 



Createci by Elia Fli 



Fig. 7: CONOSCERE... E RICONOSCERE 
Il riconoscimento di un'impronta è immediato (si 
tratta di pochi secondi) e la percentuale di errore 
è molto bassa. L'applicazione consente tuttavia 
all'utente di scegliere un adeguato livello di 
sicurezza, per evitare riconoscimenti errati o 
troppo serveri. 



In fase di riconoscimento bisognerà invece leggere 
una nuova impronta dal sensore (usando HTCaptu- 
ré) e confrontarla poi con tutte quelle memorizzate 
nei diversi file "C:\FINGERxx.DAT" '. 

Dim pBioData As HT_BIO_DATA 

Result = HTCapture(FP_RecTest.hWnd, pBioData, 10, 

0, 0, 0) 

If Result = HT_OK Then 

For I = 1 To n 

Open "C:\FINGER" + CStr(I) + ".DAT" For 

Binary As #1 Len = 256 

Get #1, , Buffer 

Close #1 

Dim fileBioDatal As HT_BIO_DATA 

fileBioDatal.pvData = VarPtr(Buffer(Q)) 

fileBioDatal.ulLength = 256 

'Confronta due impronte digitali usando 

High-Level API 

'Parametri da passare: 

' improntai (tipo HT_BIO_DATA), 

' impronta2 (tipo HT_BIO_DATA), 

' livello di sicurezza da usare per il confronto 



' variabile long che indica l'esito del confronto 

'Restituisce : 

' boolean (true se l'operazione riesce) 

Result = HTMatch(fileBioDatal, pBioData, 
m_nSecul_evel, IRtnMatch_Frt) 

La funzione HTMatch è il cuore dell' SDK, perché 
implementa il confronto fra due impronte passate 
come argomento (fileBioDatal e pBioData), usando 
un certo valore di soglia (m_nSecuLevel) e resti- 
tuendo come esito del confronto lRtnMatch_Frt, 
che vale HT_SUCCEEDED se le due impronte 
combaciano. 



FingerPrint Recognition Test 



-Comandi 




Riconoscimento completato. Identità : Elia 



TU 



Hdiurn 



Created by Elia Florio (ioProgratnmo - 2003) 



Fig. 8: PIÙ' PRECISO DI SHERLOCK HOLMES 
Da un'impronta riconosciuta diventa facile risalire 
all'identità di una persona usando un database o 
un archivio che associa i nomi e i dati anagrafici 
alle impronte digitali acquisite. 

Per il codice completo del programma si rimanda al 
progetto VB incluso nel CD-ROM della rivista. 

Elia Florio 



EUTRON 

La Eutron è una società da anni leader nel 
settore dell'IT Security, produttrice di di- 
verse soluzioni per la protezione del soft- 
ware, del copyright e per l'autenticazione 
dell'identità mediante token, chiavi hard- 
ware e ora anche attraverso le impronte di- 
gitali. Tutte le informazioni sul kit MagicSe- 
cure distribuito dalla Eutron sono reperibili 
all'indirizzo http://www.eutron.it/infosecurity 
/magic.asp 




il costo dei diversi kit biometrici venduti da 
Eutron varia tra i 130 e i 180 euro (IVA 
esclusa) mentre l'SDK necessario per lo 
sviluppo delle applicazioni viene venduto 
separatamente. 




Biometria 



Password 

a "portata 
di mano" 



MagicSecure 
SDK 

/A Il sistema biome- 
^--J trico MagicSecure 
progettato dalla Eutron 
si basa su un sensore di 
rilevamento impronte 
(venduto in versione 
singola o integrato su un 
mouse ottico) dotato di 
un kit di autenticazione 
per sistemi Windows 
2000 e XP. Il software 
comprende il driver USB 
necessario per pilotare il 
sensore e un rimpiazza- 
rne nto del modulo MSGI- 
NA.DLL di Windows. 



http://www.itportal.it 



3 ►►► 25 



TEORIA 



TECNICA 




Sistema 



File sul CD ^s> 

\soft\codice\compressione\ 



Ó 



Lossy 

Indica un tipo di 
compressione che a 
fronte di una perdita par- 
ziale di informazioni (es. 
formato JPEG) permette 
di ottenere livelli di com- 
pressione più elevati di 
quelli ottenibili con algo- 
ritmi di tipo lossless. 



Librerie 

DI COMPRESSIONE OPEN SOURCE 



In questo articolo vedremo 

come introdurre nelle nostre 

applicazioni, in modo semplice e 

rapido, la possibilità di gestire 

dati in forma compressa, sia su 

disco che direttamente in 

memoria. L'utilizzo di alcune 

delle tecniche illustrate, oltre a 

ridurre la quantità di spazio 

necessario a memorizzare i 

nostri dati, fornisce una prima 

forma di cifratura di 

informazioni che non devono 

essere facilmente rilevabili 

analizzando i file che fanno 

parte delle nostre applicazioni. 



Chi ha sviluppato progetti di una certa en- 
tità si sarà probabilmente imbattuto nel 
problema di dover riorganizzare i propri 
database, immagini o dati in genere, che per ra- 
gioni di dimensioni sforano il tetto massimo che ci 
si è prefissati o che le specifiche impongono. Cosa 
fare, ad esempio, se le textures del nostro ultimo 
gioco 3D sono troppe o troppo dettagliate ma non 
vi vogliamo o non vi possiamo rinunciare? Il pri- 
mo pensiero corre a famosi programmi di archi- 
viazione come WinZIP, WinRAR e simili. Certo 
una soluzione, ma come gestire il tutto diretta- 
mente dal nostro codice? Basta dare un'occhita in 
giro per la rete per rendersi conto che in realtà esi- 
stono ottime soluzioni al problema e per di più to- 
talmente gratuite: librerie di compressione lossless 
più o meno efficienti e con API più o meno sem- 
plici da usare. Le librerie di compressione propo- 
ste di seguito sono state scritte nella maggior par- 
te dei casi in puro ANSI C, e dunque facilmente 
portabili su qualunque sistema operativo che for- 
nisca un compilatore C che rispetti tali specifiche. 
Per loro natura, quindi, tali librerie sono da utiliz- 
zarsi principalmente in C, anche se esistono, in al- 
cuni casi, librerie DLL per Windows e quindi uti- 
lizzabili, in linea di principio, da qualunque lin- 
guaggio/ambiente di programmazione (Delphi, 
Visual Basic, ecc.). Come vedremo tra breve con 
esempi pratici di utilizzo, le librerie presentano 



una interfaccia utente per la compressione /de- 
compressione dei dati secondo due diverse moda- 
lità: 

• Direttamente in memoria 

• Files su disco 

La prima delle due possibilità è certamente quella 
più interessante perché ad esempio ci permette di 
effettuare una fase di precompressione "off-line" 
dei dati delle applicazioni, magari usando livelli 
di compressione molto elevati, e utilizzare i files 
così ottenuti decomprimendoli "on the fly" in me- 
moria prima di darli in pasto alla parte di codice 
che dovrà elaborarli. Tale tecnica, se applicata cor- 
rettamente, porta dei grossi vantaggi per la ridi- 
stribuzione delle proprie applicazioni, al costo di 
un ragionevole impatto sulle prestazioni. La com- 
pressione dei dati presenta inoltre altri vantaggi e 
talvolta inaspettati effetti collaterali: 

• Aumento dello spazio disponibile su floppy, 
ZIP, cdrom, nastri, hard disk e qualunque altro 
supporto di memorizzazione. 

• Una certa probabilità di correzione dei possibi- 
li errori generati dai supporti di memorizza- 
zione. 

• Riduzione dei tempi di trasferimento in appli- 
cazioni di rete e conseguente ottimizzazione 
dell'utilizzo della banda. 

• Un primo semplice livello di protezione dei 
dati stessi: i files e i flussi di dati in memoria 
saranno, in senso lato, cifrati. 

Nel seguito analizzeremo le API fornite da tre li- 
brerie di compressione dati (LibBzip2, LZO e Zlib) 
indicando vantaggi e svantaggi di ciascuna, e for- 
nendo alcuni esempi di utilizzo delle loro primiti- 
ve. I sistemi operativi presi come riferimento, sia 
per la compilazione delle distribuzioni delle stesse 
librerie che per gli esempi proposti, saranno quel- 
li Unix-like. 



LIBBZIP2: EFFICIENTE 
MA NON VELOCISSIMA 

Questa libreria si basa sull'algoritmo di compres- 



26^^ F e b b 



http://www.itportal.it 



sione di Burrows-Wheeler, che mediamente si 
comporta meglio della più famosa famiglia di al- 
goritmi LZ77/LZ78 anche se non eccelle in quan- 
to a velocità di compressione. Questa libreria è di- 
sponibile per una vasta gamma di architetture, tra 
le quali Linux, Windows 95/98/ME/NT 4/ 
2000/XP (in versione statica e DLL), MacOS, Sola- 
ris Sparc e x86, OS/2, OpenBSD e FreeBSD. 
L'interfaccia utente fornita da LibBzip2 si presenta 
suddivisa su tre livelli: funzioni di basso livello, 
funzioni di alto livello e funzioni di utilità. Al li- 
vello più basso troviamo le funzioni per compri- 
mere/decomprimere direttamente in memoria: 

• int BZ2_bzCompresslnit(bz _stream *stream, int 
blockSize, int verbosity, int workFactor) 

• int BZ2_bzCompress(bz _stream *stream, int ac- 
tion) 



ti da comprimere. Per quanto riguarda il parame- 
tro small, se è settato ad un valore diverso da zero 
forza al libreria ad usare un algoritmo di decom- 
pressione alternativo che riduce l'utilizzo della 
memoria. Sebbene il tutto possa sembrare compli- 
cato, in realtà la sequenza di operazioni da com- 
piere per comprimere un blocco di dati è piuttosto 
semplice: 

1) Invocare BZ2_bzCompressInit(&stream, 4, 0, 30) 
specificando i puntatori ai buffer sorgente /de- 
stinazione nella struttura puntata da &stream 

2) Invocare BZ2_bzCompress(&stream, BZ_RUN) 

3) Modificare opportunamente i puntatori ai buf- 
fer sorgente /destinazione e invocare BZ2_bz- 
Compressi&stream, BZ_FINISH) finché ci sono 
dati da comprimere 




Sistema 



Librerie 

di compressione 
Open Source 



• int BZ2_bzCompresEnd(bz_stream *stream) 



4) Invocare BZ2_bzCompresEnd(&stream) 



• int BZ2_bzDecompresslnit(bz _stream *stream, 
int verbosity, int small) 

• int BZ2_bzD ecompr ess(bz_stream *stream) 

• int BZ2_bzDecompressEnd(77z_s£razra *stream) 

Definizione del tipo bz_stream in bzlib.h 

typedef struct { 

char *next_in; 

unsigned int avail_in; 

unsigned int total_in_lo32; 

unsigned int total_in_hi32; 

char *next_out; 

unsigned int avail_out; 

unsigned int total_oiitJo32; 

unsigned int total_out_hi32; 

void *state; 

void *(*bzalloc)(void *, int, int); 

void (*bzfree)(void *,void *); 

void *opaque; 

_j 

bz_stream; 

Un tipo bz_stream, come è possibile vedere, indica 
una struttura in cui sono mantenute informazioni 
sui buffer sorgente e destinazione utilizzati duran- 
te la compressione/decompressione, blockSize- [1, 
... ,9] è la dimensione del blocco dati usato per la 
compressione (9=massima compressione ed eleva- 
to uso della memoria), verbosity -[0,... ,4] indica il 
livello di verbosità da usare (0=nessun messag- 
gio), mentre workFactor=[0,..,250] indica la soglia 
oltre la quale si passa dall' algoritmo standard a 
quello di tipo fallback in presenza di blocchi di da- 
ti ripetitivi, computazionalmente piuttosto pesan- 



Se il blocco dati da comprimere non è molto gran- 
de si può invocare una sola volta la BZ2_bzCom- 
press() specificando direttamente il valore BZ_FI- 
NISH per il parametro action. Allo stesso modo, 
per decomprimere un blocco di dati in memoria 
basta: 

1) Invocare BZ2_bzDecompressInit(&stream / 0, 0) 
specificando i puntatori ai buffer sorgente /de- 
stinazione 

2) Invocare ripetutamente BZ2_bzD ecompressi & 
stream) aggiustando di volta in volta i puntato- 
ri ai buffer sorgente /destinazione 

3) Invocare BZ2_bzDecompressEnd(&stream) per 
concludere l'operazione 

Vediamo un breve esempio di come sia possibile 
comprimere e decomprimere un blocco di dati in 
memoria usando queste primitive (esempio pre- 
sente sul CD: ESEMPIO 1: bzip2_LowLevel.c). 
L'interfaccia di alto livello fornisce una serie di 
primitive che permettono di comprimere e decom- 
primere direttamente i file, che per default sono 
identificati dal suffisso .bz2: 

• BZFILE *BZ2_bzReadOpen(m£ *bzerror, FILE 
*fp, int small, int verbosity) 

• int BZ2_bzRead(m£ *bzerror, BZFILE *bzfp, void 
*buf, int len) 

• void BZ2_bzReadGetUnused(m£ *bzerror, BZ- 
FILE *bzfp, void **unused, int *nllnused) 

• void BZ2_bzReadClose(m£ *bzerror, BZFILE 



Burrows- 
Wheeler 

^a La trasformata di 
^---J Burrows-Wheeler è 
una operazione che per- 
mette di ottenere, a par- 
tire da una stringa S di N 
caratteri, una matrice M 
le cui righe sono tutti gli 
shift ciclici a sinistra del- 
la stringa 5. L'ultima co- 
lonna BW della matrice M 
ordinata costituisce la 
trasformata di Burrows- 
Wheeler. La stringa BW 
così ottenuta contiene gli 
stessi caratteri della 
stringa in input, ma è più 
facile da comprimere. 



http://www.itportal.it 



2 3 ►►► 27 




Sistema 



Librerie 

di compressione 
Open Source 



LZ77/LZ78 

y-S Sono due varianti di 
^-J una serie di algorit- 
mi detti di Lempel-Ziv. 
Concettualmente l'algo- 
ritmo LZ78 è una varian- 
te di LZ77 che consente 
di raggiungere una com- 
pressione di 4:1. Invece 
di caricare i dati in un 
buffer e sostituire i byte 
ripetuti solamente entro 
il blocco attuale, LZ78 
crea un elenco dei byte 
ripetuti e li sostituisce 
sull'intero file. 



*bzfp) 

• BZFILE *BZ2_bzWriteOpen(m£ *bzerror, FILE 
*fp, int MockSize, int verbosity, int workFactor) 

• void BZ2_bzWrite(int *bzerror, BZFILE *bzfp, 
void *buf, int len) 

• void BZ2_bzWriteClose(m£ *bzerror, BZFILE 
*bzfp, int abandon, unsigned int *nbytes_in, unsi- 
gned int *nbytes_out) 

Il prossimo esempio chiarisce come utilizzare tali 
primitive (esempio presente sul CD: ESEMPIO 2: 
bzip2_HiLevel.c). Le funzioni di utilità, infine, per- 
mettono di comprimere e decomprimere i dati in 
memoria attraverso una semplice chiamata alle se- 
guenti funzioni: 

• int BZ2_bzBuffToBuffCompress(c/zar *dest, 
unsigned int *destLen, chat *source, unsigned int 
sourceLen, int MockSize, int verbosity, int work- 
Factor) 

• int BZ2_bzBuffToBuffDecompress(c/zar *dest, 
unsigned int *destLen, char *source, unsigned int 
sourceLen, int small, int verbosity) 

i cui parametri hanno la stessa semantica di quelli 
visti in precedenza per le funzioni di alto livello 
(esempio presente sul CD: ESEMPIO 3: bzip2_Uti- 
lity.c). Per compilare gli esempi precedenti, basta 
seguire la solita procedura: 

• Scaricare il tarball bzip2-1.0.2.tar.gz dal sito 
sources.redhat.com/bzip2 

• Compilare il tutto col comando "make" per ot- 
tenere la libreria \ibbz2.a 

• Compilare gli esempi da riga di comando: ce 
<sor gente. c> -lbz2 

L'unico svantaggio di questa libreria risiede nel- 
l'affermazione fatta dagli autori della stessa, e suf- 
fragata dall'evidenza dei benchmark, ossia nella 
non trascurabile quantità di memoria e cicli di 
CPU richiesti per la compressione e decompres- 
sione dei dati. Per questo motivo LibBzip2 non è la 
scelta ottimale nel caso in cui Y interattività risulta 
essere un fattore chiave dell'applicazione. Ma que- 
sto probabilmente è da imputare alla complessità 
computazionale della trasformata di Burrows- 
Wheeler. 



LZO (LEMPEL-ZIV-OBERHUMER): 
DECOMPRESSIONE REAL-TIME 

Questa libreria di compressione è considerata co- 



me una delle più efficienti in termini di tempo 
necessario a comprimere /decomprimere i dati: 
la velocità permette di operare la decompressio- 
ne, e spesso anche la compressione, in real-time. 
Inoltre è molto efficiente in termini di memoria 
richiesta per le operazioni: sia la compressione 
che la decompressione possono essere di tipo 
overlapped, ossia è possibile comprimere o de- 
comprimere i dati nella stessa area in cui questi 
sono memorizzati, azzerando di fatto la richiesta 
di memoria extra. Il rovescio della medaglia è 
che purtroppo non risulta altrettanto efficiente in 
termini di rapporto di compressione. Per tale 
motivo, la migliore strategia di utilizzo consiste 
nel precomprimere i dati da usare nelle applica- 
zioni, e decomprimerli al volo a seconda delle 
necessità, facendo affidamento sulla capacità di 
decompressione real-time. In tal modo è possibi- 
le usare algoritmi relativamente lenti nella com- 
pressione ma molto efficienti. 
La libreria LZO comprende molti algoritmi, cia- 
scuno con diversi livelli di compressione: LZOX- 
N, con X=tipo di algoritmo (1, 1A, 1B, 1C, 1F, IX, 
1Y, 1Z, 2A), ed N=livello di compressione (1...9, 
99, 999). Naturalmente, quanto più è elevato il 
valore di N tanto più efficiente e lento sarà il 
processo di codifica. Nella maggior parte dei ca- 
si la scelta migliore risulta essere l'algoritmo 
LZOIX-N. 

Anche in questo caso le piattaforme supportate 
sono le più svariate: Dos (16 e 32 bit), Windows 
3.x, Windows 95/98/NT 4/2000/XP, Linux, 
HPUX, Alpha, AIX, MacOS, e così via. Esistono 
inoltre versioni native in Java, Perl e Python. 
L'interfaccia utente in C, linguaggio in cui è scrit- 
ta la libreria, risulta essere molto estesa, per la- 
sciare al programmatore la più ampia libertà sul- 
la scelta dell'algoritmo da utilizzare, ma di sem- 
plice gestione. Rispetto alle altre, tuttavia, non 
fornisce primitive in grado di creare files con un 
preciso formato di compressione standard, ma 
tutto il lavoro è lasciato al programmatore. A ta- 
le scopo sono fornite alcune primitive di utilità 
tra cui quelle per il calcolo del checksum (Adler e 
CRC), lzo_fwrite() ed lzo_fread() (versioni portabi- 
li delle freadQ /fwriteO standard). Le primitive for- 
nite permettono unicamente di operare la com- 
pressione/decompressione di blocchi di dati in 
memoria. Per operare su uno di questi blocchi 
basta invocare la funzione lzo_init() e quindi pas- 
sare alla compressione o decompressione dei da- 
ti in questione utilizzando le funzioni relative al- 
la versione dell'algoritmo scelto (ad esempio 
lzolx_l_compress() e lzolx_l_decompress() nel caso 
si volesse usare LZOlX-1). Vediamo in dettaglio 
queste primitive: 

• int ìzo_init(v oid): inizializzazione della libre- 
ria da invocare prima dell'utilizzo di qualun- 



28^^ F e b b 



http://www.itportal.it 



que altra primitiva. 

int lzolx_l_compress (const Izojbyte *src, 
Izojuint src_len, Izojbyte *dst, Izojuintp 
dst_ leti, lzo_voidp wrkmetn): compressione 
con algoritmo LZOlX-1. Il parametro turk- 
meni rappresenta il puntatore ad un buffer 
utilizzato internamente dalla libreria e la cui 
dimensione varia in base all'algoritmo usato. 
La dimensione di questo buffer è predefinita 
da una serie di costanti che ritroviamo nel- 
Theader file relativo all'algoritmo. Per quan- 
to riguarda V esempio riportato di seguito, nel 
file Izolx.h è definita la costante LZ01X_1_ 
MEM COMPRESS. 



A questo punto è possibile compilare l'esempio 
che usa le funzioni relative all'algoritmo LZOIX- 
1 con un semplice comando: (esempio presente 
sul CD: ESEMPIO 4: lzo_compress.c). 

ce -o lzo.com press lzo.com press. e -llzo 

Oltre alla versione completa, esiste anche una 
versione minimale della libreria LZO, chiamata 
miniLZO, costituita da un sorgente in C e due 
header files, che occupa solo 6KB dopo la compi- 
lazione, mentre l'intera distribuzione occupa ap- 
pena 14 KB. Come dire: nessuna scusa per non 
incorporare queste funzionalità nella proprie ap- 
plicazioni. 




Sistema 



Librerie 

di compressione 
Open Source 



• int lzolx_decompress(cons£ Izojbyte *src, 
Izojuint src_len, Izojbyte *dst, Izojuintp 
dst_ len, Izojvoidp wrkmem): decompressio- 
ne con algoritmo LZOlX-1. In questo caso il 
parametro wrkmem non è utilizzato e va po- 
sto al valore NULL. 

Esiste, come detto, una vasta scelta di primitive: 
in genere per ciascun algoritmo esiste una serie 
di funzioni del tipo lzoALGJSl_compress() ed 
lzoALG_ N_decompressTYPE(), dove: 

• ALG=l, la, Ih, le, If, Ix, ly, Iz, la 

• N=l,2,3,4,5,6,7,8,9,99,999 

• TYPE= _safe, _asm, _asm_safe, _asm_fast, 
_asm_fast_safe. Il suffisso jism indica il fatto 
che il codice è per lo più scritto in assembly 
ottimizzato, _safe indica la versione di de- 
compressore che effettua alcuni test di vali- 
dità del blocco dati compresso da elaborare, 
mentre _fast indica una versione ancora più 
performante in termini di velocità di esecu- 
zione. 

Per quello che concerne il buffer in cui i dati ver- 
ranno decompressi, esistono semplici formule 
per calcolarne la dimensione: 

• Per gli algoritmi LZOl* outjbufferjsize = 
in_buffer_size+(inJbuffer_size/64)+16+3 . 

• Per gli algoritmi LZ02* outjbufferjsize = 

in_buffer_size+ (in_buffer_size/8)+l2 8 +3 . 

La libreria LZO può essere scaricata da www.ober- 
humer.com/opensource/lzo e compilata con la se- 
guente procedura: 

• configure 

• moke 

• moke instali 



ZLIB: UN BUON 
COMPROMESSO TRA 
VELOCITÀ ED EFFICIENZA 

Questa libreria utilizza una variante del ben no- 
to algoritmo LZ77 chiamata deflation (RFC1951), 
che affonda le sue radici nell'altrettanto famoso 
PkZip della PkWare. 

Anche Zlib, come le precedenti, è assolutamente 
gratuita, scritta in ANSI C e vanta un enorme nu- 
mero di sistemi operativi su cui è stata imple- 
mentata: Windows 9x/NT 4/2000 /XP/CE, Li- 
nux, MacOS, Solaris, HPUX, Compaq Tru64, Irix 
6.x e BeOS, solo per citare i più noti. Il rapporto 
di compressione può variare da 2:1 a 5:1, anche 
se, come da specifiche, il formato zlib è capace di 
un limite teorico di 1030:1. 

Definizione del tipo z_streamp in zlib.h. 

typedef struct z_stream_s { 

Bytef *next_in; /* next input byte */ 

ulnt avail_in; /* number of bytes available 

at next_in */ 

uLong total_in; /* total nb of input bytes read so far */ 
Bytef *next_out; /* next output byte 

should be put there */ 

ulnt avail_out;/* remaining free space at 

next_out */ 

uLong total_out; /* total nb of bytes output so far */ 
char *msg; /* last error message, NULL if no error */ 



struct internal_state FAR *state; /* not visible by 
applications */ 

alloc_func zalloc;/* used to allocate the internai 
state */ 

free_func zfree; /* used to free the internai state */ 

voidpf opaque; /* private data object 
passed to zalloc and zfree */ 



int data_type; /* best guess about the data type: 
ascii or binary */ 

uLong adler; /* adler32 value of the uncompressed 
data */ 

uLong reserved; /* reserved for future use */ 



Adler 

^a Si tratta di una tec- 
^J nica di calcolo del 
checksum che impiega 2 
contatori da 16 bit, si ed 
s2. Il primo contiene la 
somma di tutti i byte in 
input, mentre s2 contie- 
ne la somma di tutti i va- 
lori di si. Entrambe le 
somme sono modulo 
65521. Il checksum è da- 
to da s2*65536 + si in 
network byte order. 



CRC 

^a II Cyclic Redundan- 
-J cy Check permette 
di calcolare il checksum 
(un valore a 32 bit che 
riassume il contenuto di 
un blocco di dati) som- 
mando blocchi da 2 byte 
in complemento a 1. 



http://www.itportal.it 



3 ►►► 29 



TE 



} z_stream ; 



Sistema 



Librerie 

di compressione 
Open Source 



Lossless 

^a E' un termine riferi- 
J to ad una famiglia di 
algoritmi di compressio- 
ne che permettono di ri- 
durre la dimensione di 
qualunque tipo di dati 
senza perdita di alcuna 
informazione. 



Sul Web W 

LibBzip2: 

http://sources.redhat.com/ 
bzip2 

LZO : 

http://www.oberhumer.com 
/opensource/lzo 

Zlib : 

http://www.qzip.org/zlib 



typedef z_stream FAR * z_streamp; 

U interfaccia verso il programmatore risulta esse- 
re composta da tre classi, una di base (Basic) che 
permette un tuning fine di ogni parametro del- 
l'algoritmo, una di alto livello (Utility) che pre- 
senta funzioni per la compressione /decompres- 
sione in memoria e di file in formato standard 
gzip (RFC1952), ed infine una classe di funzioni 
avanzate (Advanced) che risulta essere abbastan- 
za complessa e di utilizzo piuttosto raro. 
Tali classi risultano essere ben strutturate e pos- 
sono coprire qualunque necessità possa avere il 
programmatore: ne è una chiara dimostrazione il 
fatto che sia stata adottata per i loro prodotti da 
moltissime compagnie leader nel settore del 
software per PC. Tra queste ricordiamo anzitutto 
Microsoft, Apple, Adobe, Macromedia, Cisco, 
Borland e Netscape. Vediamo in dettaglio i pro- 
totipi delle funzioni di livello Utility: 

• int compress(Byfef *dest, uLongf *destLen, con- 
st Bytef *source, uLong sourceLen) 

• int uncompress(Byfef *dest, uLongf *destLen, 
const Bytef *source, uLong sourceLen) 

• gzFile gzopen(const char *path, const char 
*mode) 

• int gzread( gzFile file, voidp buf, unsigned len) 

• int gzwrite( gzFile file, const voidp buf, unsi- 
gned len) 

• z_off_t gzseek( gzFile file, z_off_t offset, int 
whence) 

• int gzeoi(gzFile file) 

• int gzclose( gzFile file) 

I parametri da passare alle funzioni sono piutto- 
sto intuitivi e l'implementazione del codice che 
effettua la compressione risulta molto semplice, 
come si può rapidamente dedurre dall'esempio 
(esempio presente sul CD: ESEMPIO 5: zlib_Uti- 
lity.c). 

Per quanto riguarda la classe Basic, troviamo le 
seguenti funzioni: 

• int deflatelnit (z_streamp strm, int level) 

• int def late (z_streamp strm, int flush) 

• int deflateEnd (z_streamp strm) 

• int inflatelnit (z_streamp strm) 



• int inflate (z_streamp strm, int flush) 

• int inflateEnd (z_streamp strm) 

Anche in questo caso, i parametri da passare alle 
funzioni sono concettualmente identici al caso 
della libreria LibBzipl. Anzi, come chiaramente si 
può vedere confrontando i listati 1 e 2, le struttu- 
re che descrivono lo stream di dati da compri- 
mere o decomprimere sono pressoché identiche 
se si trascurano alcuni piccoli particolari. Si veda 
l'esempio presente sul CD: ESEMPIO 6: zlib_Ba- 
sic.c). 

La compilazione della distribuzione in formato 
sorgente di Zlib avviene con la solita procedura: 

• configure 

• make 

• make instali 

mentre per compilare gli esempi forniti basta da- 
re i comandi: 

• ce -o zlib_Utility zlib_Utility.c -lz per com- 
pilare l'esempio relativo alle funzioni della 
classe Utility. 

• ce -o zlib_Basic zlib_Basic.c -lz per compi- 
lare l'esempio relativo alle funzioni della 
classe Basic. 



CONCLUSIONI 

Come avrete capito, queste librerie di compres- 
sione open source permettono di dotare le nostre 
applicazioni di porzioni di codice, relativamente 
semplici da implementare, che gestiscono dati 
compressi con una notevole riduzione di spazio 
occupato su disco a fronte di un ragionevole 
overhead in termini di memoria e cicli di CPU. 
Molte applicazioni che usiamo tutti i giorni fan- 
no uso di tali librerie e ciò testimonia, più di ogni 
altra argomentazione, l'indubbia affidabilità e i 
molti vantaggi che se ne possono trarre. 
La caratteristica di essere multipiattaforma, inol- 
tre, permette di avere un impatto praticamente 
nullo su tutte quelle applicazioni di natura 
platform-independent. 

Insomma, una volta capite le modalità di utiliz- 
zo di queste librerie, la possibilità di maneggiare 
grosse quantità di dati al costo di una frazione 
delle loro reali dimensioni diventa pressoché tra- 
sparente per le nostre applicazioni. Sicuramente 
un ottimo motivo per aggiungere la compressio- 
ne la prossima volta che si ha a che fare con 
quantità titaniche di dati. 

Giuseppe Palumbo 



30 ►►► F e b b 



http://www.itportal.it 



TEORIA 



Fotolab 



FILTRI FOTOGRAFICI IN VISUAL BASIC 




In questo articolo, suddiviso in 

due parti, si vogliono presentare 

alcuni algoritmi di ritocco 

fotografico finalizzati a 

migliorare la qualità di immagini 

bitmap acquisite con lo scanner 

o con una macchina fotografica 

digitale e ad estrarne delle 

caratteristiche, come ad 

esempio i contorni delle figure. 



Per memorizzare questo livello di intensità oc- 
corrono 8 bit per ciascuno dei colori primari, e 
quindi in totale 24 bit per pixel. In questo mo- 
do si hanno 2 A 24 = 16.777.216 possibili colori. 
Alcuni esempi di colori sono indicati nella Ta- 
bella 1. 

Secondo il modello RGB, quando le intensità 
dei tre colori primari sono identiche si ottengo- 
no dei livelli di grigio; pertanto si possono ave- 
re 256 livelli di grigio, graduati dal nero 0, 0, 
al bianco 255, 255, 255. 



Visual 
Basic 



^File sul CD 

\soft\codice\filtri.zip 



Un qualche ritocco si rende spesso ne- 
cessario perché l'acquisizione di im- 
magini comporta inevitabilmente l'in- 
troduzione di "rumore elettronico", che si ma- 
nifesta mediante l'alterazione del colore di 
qualche pixel, ed anche di qualche distorsione 
geometrica. Gli algoritmi verranno sviluppati 
in Visual Basic, partendo da un file in formato 
BMP, limitandosi ad usare le librerie e i con- 
trolli standard di tale linguaggio. Pertanto ri- 
sulterà agevole la realizzazione degli stessi in 
altri linguaggi di programmazione. 

IL MODELLO RGB 

Si ricorda brevemente che le immagini bitmap 
a colori sono costituite da una griglia di punti, 
ad esempio 800 x 600 punti, detti pixel, per cia- 
scuno dei quali si memorizza il colore, ottenuto 
come combinazione dei tre colori primari Red, 
Green, Blue (Rosso, Verde, Blu). Per ciascuno di 
questi colori si memorizza il livello di intensità 
che può variare da = assenza di colore a 255 = 
massima intensità di colore, e quindi massima 
luminosità (brightness). 



R 


G 


B 


Colore 


255 








rosso 





255 





verde 


255 


255 





giallo 


255 


255 


240 


avorio 


255 


255 


255 


bianco 


128 


128 


128 


grigio 











nero 



IL FORMATO BMP 

La scelta di questo formato è stata dettata dalla 
sua ampia diffusione unitamente alla sua gran- 
de semplicità. Innanzitutto si deve sapere che 
un file BMP è composto di 4 parti: 

1. intestazione del file, 

2. intestazione dell'immagine, 

3. eventuale tavolozza dei colori, 

4. i dati sui pixel. 

La Tabella 2 rappresenta in dettaglio la struttu- 
ra di un file BMP, dove in neretto sono eviden- 
ziati i campi che vengono utilizzati nel pro- 
gramma FotoLab che svilupperemo. Si fa notare 
che l'immagine viene memorizzata capovolta 
rispetto a come essa viene visualizzata a video: 
ovvero le righe di pixel che costituiscono l'im- 
magine vengono memorizzate in ordine inver- 
so, dall'ultima alla prima. Si veda la Fig. 1. 





immagine 
uisualizzata 



immagine 
memorizzata 



Tab. 1: Livelli di intensità necessaria a ottenere 
alcuni colori fondamentali. 



Fig. 1: Il formato BMP memorizza le immagini 
capovolte. 

TRASFORMAZIONI 
DELL'IMMAGINE 

Tralasciando tutte le trasformazioni di tipo geo- 
metrico (quali ad esempio riflessione, rotazio- 
ne, ingrandimento, riduzione dell'immagine), 
ci si occupa delle trasformazioni che modifica- 



La risoluzione 
dell'immagine 

r& Il numero di pixel 
-J che formano l'imma- 
gine acquisita da una fo- 
tocamera digitale è fisso, 
e dipende dalle caratteri- 
stiche del suo sensore 
CCD (Charge Coupled De- 
vice): ad esempio essa 
potrebbe avere un senso- 
re da circa 2 milioni di 
pixel disposti in una gri- 
glia di 1600 x 1200 pixel. 
Questo vale anche per lo 
schermo del computer, 
che viene solitamente 
impostato per visualizza- 
re immagini a 800x600 
pixel, oppure 1024x768 
pixel. Tuttavia le dimen- 
sioni in pixel non dicono 
nulla sulle dimensioni fi- 
siche in cm dell'immagi- 
ne: è necessario conside- 
rare la densità dei pixel, 
ovvero la risoluzione del- 
l'immagine. 



http://www.itportal.it 



3 ►►► 31 




Visual 

Basic 



Fotolab 

Filtri Fotografici 
in Visual Basic 



La dimensione 
dell'immagine 

/-& La risoluzione di 
--^ una immagine è il 
rapporto tra il numero 
dei pixel che la costitui- 
scono e la dimensione 
fisica della stessa; essa 
si misura in dpi (dot per 
inch = punti per polli- 
ce). Si ricorda l'equiva- 
lenza 1 pollice = 2.54 
cm. Un normale moni- 
tor per computer ha 
una risoluzione relati- 
vamente bassa, di 72 
dpi, mentre una stam- 
pante a getto d'inchio- 
stro può avere una riso- 
luzione di 600 dpi. Uno 
scanner piano per fogli 
A4 può avere una riso- 
luzione effettiva di 
2400 dpi, uno scanner 
per pellicole una risolu- 
zione di 2700 dpi. 
La stessa immagine 
può essere riprodotta 
su carta con risoluzioni 
e quindi dimensioni di- 
verse; ad esempio una 
foto di 1268 x 1012 
pixel se stampata ad 
una risoluzione di 300 
dpi avrà dimensioni di 
4.2 x 3.4 pollici, ovvero 
di 10.7 x 8.6 cm (in- 
fatti 1268 / 300 = 4.2 e 
1012 / 300 = 8.6); se 
invece la si vuole stam- 
pare con dimensioni 
raddoppiate su entram- 
bi i lati, la risoluzione si 
dimezza a 150 dpi. 



no il colore dei pixel, con l'obiettivo di miglio- 
rare la qualità di una immagine affetta da ru- 
more, oppure troppo sfuocata, o scura, e di tra- 
sformazioni che cercano di evidenziare la su- 
perficie oppure i contorni degli oggetti in essa 
rappresentati. In base alle tecniche utilizzate, le 
trasformazioni possono essere suddivise in: 

• trasformazioni puntuali, che agiscono su 
ciascun pixel singolarmente; 

• trasformazioni locali che modificano il colo- 
re di un pixel in funzione dei pixel che gli 



stanno attorno, 

• trasformazioni globali che modificano il co- 
lore di un pixel in funzione di tutti i pixel 
dell'immagine: si tratta ad esempio della 
trasformata di Fourier per l'analisi delle fre- 
quenze spaziali dell'immagine (essa non 
viene considerata in questo articolo). 

TRASFORMAZIONI 
PUNTUALI 

Dato il generico pixel, indichiamo con x(R), 



Nome Campo 


Dimensione 


Descrizione 


Intestazione del File 


totale 14 byte 






Firma 


2 byte = Stringa 


Contiene i caratteri 'BM' 


Dimensione File 


4 byte = Long 


Dimensione del file in byte 


riservato 


4 byte 


non utilizzato (= 0) 


Offset 


4 byte = Long 


Spiazzamento dei dati relativi ai pixel 


Intestazione dell'Immagine 


totale 40 byte 






Dimensione 
dell'intestazione 


4 byte = Long 


Dimensione dell'intestazione in byte = 40 


W 


4 byte = Long 


Larghezza Immagine 


H 


4 byte = Long 


Altezza Immagine 


Numero Piani 


2 byte = Integer 


Numero di piani del disegno (= 1) 


Bit per Pixel 


2 byte = Integer 


Bit per Pixel 

1 = monocromatica. Numero Colori = 1 

4 = 4 bit. Numero Colori = 16 

8 = 8 bit. Numero Colori = 256 

16 = 16 bit. Numero Colori = 65.536 

24 = 24 bit RGB. Numero Colori = 16 milioni 




Compressione 


4 byte = Long 


Tipo di Compressione 

= RGB nessuna compressione 

1 = RLE8 codifica RLE a 8 bit 

2 = RLE4 codifica RLE a 4 bit 




Dimensione 

dell'Immagine 

Compressa 


4 byte = Long 


= se Tipo di Compressione = 




Pixel Per Metro 

AsseX 


4 byte = Long 


Scala orizzontale Pixel /metro 




Pixel Per Metro 
Asse Y 


4 byte = Long 


Scala verticale Pixel /metro 




Numero Colori 4 
Usati 


byte = Long 


Numero di colori effettivamente usati 




Colori Importanti 


4 byte = Long 


Numero di colori importanti 
= se tutti 


Tavolozza dei colori 


totale (4 * Num. Colori Usati) byte 


E presente solo se Bit Per Pixel <= 8 






Blue 


lbyte 


Intensità di Blu 


Green 


lbyte 


Intensità di Verde 


Red 


lbyte 


Intensità di Rosso 


riservato 


lbyte 


Non utilizzato (= 0) 




... ripetuto per tutti i colori usati 




Dati sui Pixel 


totale byte = multiplo4(3 * W) * H 


Il totale di byte per riga = 3 * W deve essere arrotondato 
per eccesso ad un multiplo di 4: se ad esempio W = 5 
pixel e H = 5 pixel, allora 3 * W = 15 e quindi 
multiplo4(3 * W) = 16, pertanto il totale sarà 16 * 5 = 80 
byte. I byte aggiunti per arrotondare sono settati a 






Blue 


lbyte 


Intensità di Blu 


Green 


lbyte 


Intensità di Verde 


Red 


lbyte 


Intensità di Rosso 




... ripetuto per tutti i pixel dell'immagine 



Tab. 2: Dettaglio della struttura di un file BMP. 



32 ►►► F e b b 



http://www.itportal.it 



TECNICA 



x(G), x(B) le intensità, rispettivamente, delle 
sue componenti rossa, verde e blu. Queste in- 
tensità costituiscono le tre componenti di colo- 
re di ciascun pixel. Le trasformazioni puntuali 
consentono di ottenere delle nuove intensità 
y(R), y(G) e y(B) in funzione soltanto delle cor- 
rispondenti componenti x(R), x(G), x(B): 

1) La trasformazione che produce il negativo 
di una immagine consiste nel calcolare il 
complemento a 255 dell'intensità di ciascu- 
no dei tre colori di base di tutti i pixel, se- 
condo la formula 

y = 255 - x 

La Fig. 2 evidenzia graficamente l'anda- 
mento lineare di questa trasformazione. 



y 

255 






\ 




0^ 


255 x 



Fig. 2: Inversione di una immagine. 



2) Una trasformazione che consente di aggiu- 
stare in modo semplice la luminosità e il 
contrasto di una immagine è la trasforma- 
zione lineare delle intensità di colore 

Per aumentare la luminosità si deve aumen- 
tare il livello di intensità dei colori dei pixel, 
mentre per aumentare il contrasto si deve 
aumentare la differenza tra le intensità dei 
colori di pixel adiacenti. 
La formula è la seguente 

y = a * x + b 

dove i parametri a e b sono numeri reali che 
rappresentano, rispettivamente, il fattore di 
contrasto e la variazione di luminosità. Il 



y 

255 

o" 
b- 






j 


a 




/ 255 x 

r 



contrasto aumenta per a > 1 e diminuisce 
per < a < 1, mentre la luminosità aumenta 
per b > e diminuisce per b < 0. I valori di 
y ottenuti da tale calcolo vengono ricondot- 
ti air intervallo .. 255, assegnando il valore 
agli y negativi e il valore 255 agli y mag- 
giori di 255. La Fig. 3 illustra il significato 
grafico dei parametri a e b, i quali rappre- 
sentano, rispettivamente, la pendenza della 
retta e la sua staccata rispetto air origine. 

3) Quando i tre colori di base hanno uguale in- 
tensità, si ha una immagine a 256 livelli di 
grigio. 

Per separare nettamente le zone chiare dell'im- 
magine da quelle scure si può applicare la tra- 
sformazione di sogliatura (thresholding) che 
riconduce l'immagine a due soli livelli di gri- 
gio: nero e bianco. Lo scopo di questa trasfor- 
mazione è quello di segmentare l'immagine, 
ovvero di evidenziare la superficie degli ogget- 
ti raffigurati nella stessa. Essa risulta maggior- 
mente efficace nei casi in cui si ha un oggetto di 
colore omogeneo che campeggia su uno sfondo 
anch'esso di colore omogeneo. A causa del ru- 
more elettronico non ci sarà mai una perfetta 
distinzione tra l'oggetto e lo sfondo e quindi 
questa operazione sarà comunque sempre sog- 
getta ad un qualche errore. La tecnica della tra- 
sformazione di sogliatura è molto semplice: da- 
to un valore di soglia s, compreso tra e 255, si 
fanno diventare neri tutti i pixel il cui livello di 
grigio è inferiore a s e bianchi tutti gli altri: 

È y = per x < s 
ì 
È y = 255 per x >= s 

La Fig. 4 evidenzia graficamente tale comporta- 
mento. 



y 

255 












0^ 


s 255 x 



Fig. 3: Trasformazione lineare 



Fig. 4: Sogliatura. 



La scelta del valore di soglia s si basa sull'ana- 
lisi dell'istogramma delle frequenze dei livelli 
di grigio dell'immagine. 

La Fig. 5 riporta un esempio di tale istogram- 
ma; esso evidenzia il fatto che nell'immagine ci 




Visual 
Basic 



Fotolab 

Filtri Fotografici 
in Visual Basic 



L'istogramma 
dei livelli 
di grigio 

r& L'istogramma di una 
■-J immagine a livelli di 
grigio è un strumento 
utile per caratterizzare 
l'immagine stessa. Esso 
rappresenta, per ognuno 
dei 256 livelli di grigio, il 
numero di pixel dell'im- 
magine che assumono 
tale livello; tali valori 
verranno poi divisi per il 
numero totale di pixel 
dell'immagine in modo 
da ottenere il diagramma 
delle frequenze relative 
dei livelli di grigio. 



http://www.itportal.it 



3 ►►► 33 




Visual 

Basic 



Fotolab 

Filtri Fotografici 
in Visual Basic 



La tecnica 
dei falsi colori 

rA Si tratta di una tec- 
-J nica che consente 
la segmentazione del- 
l'immagine, ovvero di 
evidenziare alcune zo- 
ne della stessa, carat- 
terizzate da una omo- 
geneità cromatica. 
Data una immagine a li- 
velli di grigio, si fissano 
degli intervalli di inten- 
sità di grigio e si asso- 
cia arbitrariamente a 
ciascuno di essi un di- 
verso colore: si tratta 
evidentemente di "falsi 
colori". 

Essi sono finalizzati a 
facilitare la lettura del- 
l'immagine, anche per- 
chè l'occhio umano non 
è in grado di distin- 
guere tutti i 256 livelli 
di grigio, ma soltanto 
un sessantina. 
Per scegliere tali inter- 
valli si farà uso del- 
l'istogramma dei livelli 
di grigio. 

Ad esempio: i pixel con 
intensità comprese tra 
41 e 60 diventeranno 
verdi, quelli con inten- 
sità compresa tra 61 e 
80 diventeranno rossi e 
tutti gli altri manter- 
ranno l'attuale intensi- 
tà di grigio. 



^ 



K 



20 40 60 80 100 120 140 100 180 200 220 24'J 255 



Fig. 5: Istogramma dei livelli di grigio. 

sono due distinte aree: una più scura, di inten- 
sità compresa tra 30 e 70 e l'altra più chiara, di 
intensità compresa tra 110 e 150. Pertanto, in 
questo caso, la scelta del valore di soglia s = 100 
consente di separare nettamente le due zone 
dell'immagine, facendo diventare neri tutti i 
pixel con intensità < 100 e bianchi tutti gli altri. 
Ovviamente qualsiasi valore di soglia venga 
scelto compreso nell'intervallo tra 70 e 110 darà 
il medesimo risultato di s = 100. 
L'esempio fornito illustra una situazione parti- 
colarmente favorevole, ma spesso non c'è una 
così netta distinzione tra le intensità di colore 
delle diverse aree dell'immagine e pertanto la 
scelta del valore di soglia pur se fatta con ocu- 
latezza non consentirà una netta evidenziazio- 
ne delle stesse. 



ESEMPIO 

A titolo esemplificativo si mostrano gli effetti 
delle suddette elaborazioni sull'immagine di 
Fig. 6a. 




Fig. 6a: Tre; Fig. 6b: Negativo; Fig. 6c: Rosso; 
Fig. 6d: Verde. 

Dell'immagine di partenza ne viene fatto il ne- 
gativo (Fig. 6b) e ne vengono estratti i colori 
primari (Fig. 6c, 6d, 6e). Essa viene poi conver- 
tita in scala di grigi (Fig. 6f), il cui istogramma 
dei livelli di grigio è proprio quello rappresen- 
tato in Fig. 5, a questo punto viene applicata la 
preannunciata operazione di sogliatura, ap- 
punto con valore di soglia pari a 100 (Fig. 6g). 




Fig. 6e: Blu; Fig. 6f: Grigio; 

Fig. 6g: Grigio Soglia 100; Fig. 6h: a 



2b = 20. 



Ripartendo dalla Fig. 6a si applica una trasfor- 
mazione lineare per aumentarne il contrasto e 
la luminosità: la Fig. 6h mostra il risultato ap- 



plicando un fattore di contrasto pari a 2 e una 
variazione di luminosità pari a +20. 

CODIFICA IN VB 

La Fig. 7 mostra la finestra di tipo "Multiple Do- 
cumenta del programma FotoLab con all'interno 
due finestre "figlie" contenenti i controlli Pictu- 
reBox per visualizzare le foto coinvolte nelle 
elaborazioni. 





'; e F ì<: 'unti ale ; 


iltro Locale 








^]n\x\ 




^MM=^ 


■-, (' ) 


/ "3 


4j 


...... H : \ , 


'-'-^{~ 


^ - ^ 


"~— D~ 


















•h 








• — - 



Fig. 7: FotoLab 



Il programma applica il filtro prescelto alla foto 
corrente; per rendere corrente una foto si deve 
fare un click all'interno della stessa. FotoLab ge- 
stisce soltanto immagini BMP a 24 bit, ovvero a 
16 milioni di colori, e qualora si trasformi una 
foto a colori in una foto a 256 livelli di grigio, 
per semplicità, essa viene considerata come un 
caso particolare di una foto a colori senza adot- 
tare il più opportuno formato BMP a 8 bit. 
Inoltre, avendo uno scopo didattico, il pro- 
gramma non si preoccupa troppo dell'efficien- 
za degli algoritmi, ne' recupera spazio in me- 
moria centrale quando si chiude la finestra as- 
sociata ad una foto. A livello globale viene di- 
chiarato un array di oggetti "foto", ciascuno dei 
quali avrà il nome della foto, il riferimento al 
Form su cui essa viene visualizzata, le dimen- 
sioni della stessa, l'offset dei pixel e gli array di 
byte contenenti l'intestazione del file e la ma- 
trice di pixel. 

Private Type tipoFoto 

NomeFoto As String 

Form Foto As frmFoto 

w As Long ' ampiezza foto 

w3 As Long ' ampiezza aggiustata 

h As Long ' altezza foto 

inizioPixel As Long ' offset 

headerQ As Byte ' header del file BMP 

g() As Byte ' matrice di pixel 

End Type 

Dim FotoQ As tipoFoto ' array di foto 



Dim nFoto As Integer 



numero di foto caricate 

nell'array 



34+» F e b b 



http://www.itportal.it 



TECNICA 



Dim gCorrente As Integer ' indice della foto corrente 

La seguente subroutine consente di caricare 
una foto BMP letta da disco in una nuova com- 
ponente dell'array di foto. Il parametro Nome- 
Foto contiene il nome del file e il parametro Ori- 
gine vale per indicare che si deve leggere la 
foto da disco. La foto ha dimensione w * h pixel, 
quindi essa occuperà una matrice di Byte con h 
righe e w 3 = w * 3 colonne, dove w3 viene arro- 
tondato al valore multiplo di 4 immediatamen- 
te successivo, a causa delle specifiche del for- 
mato BMP. 

Private Sub CaricaFoto(ByVal NomeFoto As String, 

ByVal Origine as Integer) 

Dim w As Long 

Dim h As Long 

Dim pixelOffset As Long 

With Foto(gCorrente) ' gCorrente è l'indice della foto 

corrente 

Set .FormFoto = New frmFoto ' crea un nuovo Form 
per la foto 



.FormFoto.Caption = NomeFoto 



. FormFoto. Tag = CStr(gCorrente) ' associa il form alla 

foto corrente 



.Form Foto. Show 



.NomeFoto = NomeFoto 



If Origine = Then 



Set . FormFoto. picFoto.Picture = 
LoadPicture(NomeFoto) 



Open NomeFoto For Binary As #1 



Get #1, 11, pixelOffset 



Get#l, 19, w ' Width 



Get #1, 23, h ' Height 



.w3 = multiplo4(w * 3) ' funzione che calcola il 
multiplo di 4 



.h = h 



■ inizioPixel = 1 + pixelOffset 



acquisizione header del file BMP 



ReDim .header(l To pixelOffset) 



acquisizione matrice di pixel 



ReDim .g(l To .w3, 1 To .h) 



notare che la matrice risulta trasposta: colonne, 
righe e che inoltre le righe sono invertite: 



dall'ultima alla prima 



Get #1, .inizioPixel, .g 



Close #1 



Else 



la foto viene letta dall'array, dalla componente di 



indice Origine 



.w = Foto(Origine).w 



.w3 = Foto(Origine).w3 



.h = Foto(Origine).h 



■ inizioPixel = Foto(Origine).inizioPixel 



■ header = Foto(Origine).header 



.g = Foto(Origine).g 



End If 



End With 



End Sub 

Per l'applicazione di filtri puntuali si veda il se- 
guente estratto di subroutine che applica la tra- 
sformazione in negativo della foto corrente. Si 
devono modificare tutte le componenti della 
matrice dei colori dei pixel. 

Private Sub FiltraFoto(ByVal TipoFiltro As String) 

Dim i As Long 



Dim j As Long 



Dim n As Long 



With Foto(gCorrente) 



n = 3 * .w 



For i = 1 To .h Step 1 



1 = 1 



Do While j <= n 



Select Case TipoFiltro 



Case "Negativo" 



' evidentemente si trattano allo stesso modo 
' le tre componenti componente blue 



■ gli, i) = CByte(255 - .q(i, i)) 



1 = 1 + 1 



' componente green 



■ gli, i) = CByte(255 - .q(i, i)) 



j = j + 1 



' componente red 



■ gli, i) = CByte(255 - .q(i, i)) 



1=1 + 1 



Case ... ' per gestire altri filtri 



End Select 



Loop 



Next i 



' salvo la foto in un file temporaneo 



Open "temp.bmp" For Binary As #1 



Put #1, , .header 



Put #1, 



Close #1 



' visualizzo il risultato 



Set .FormFoto. picFoto.Picture = 
LoadPictureCtemp.bmp") 



End With 



End Sub 

CONCLUSIONI 

Nella seconda parte di questo articolo verranno 
affrontate le trasformazioni locali dell'immagi- 
ne, le quali consentiranno di agire sul contrasto 
della stessa, di attenuarne il rumore elettronico 
ed anche di estrarre i contorni degli oggetti in 
essa rappresentati. 

Roberto Bandiera 




Visual 
Basic 



Fotolab 

Filtri Fotografici 
in Visual Basic 



Riferimenti 

r& Per approfondimenti 
-J e una ampia rasse- 
gna di tecniche di elabo- 
razione di immagini si 
visiti il sito del Diparti- 
mento di Intelligenza Ar- 
tificiale dell'Università di 
Edinburgo 

http://www.dai.ed.ac.uk 
/HIPR2/hipr top.htm 

Presso il Dipartimento di 
Computer Science della 
stessa università sono 
reperibili informazioni 
sui formati grafici 
http://www.dcs.ed.ac.Uk/h 
ome/mxr/qfx/2d-hi .ritmi 

Per una introduzione alla 
fotografia digitale si 
consulti il manuale on li- 
ne "Le Tecniche Fotogra- 
fiche In Archeologia" di 
Fausto Gabrielli del Di- 
partimento di Scienze 
Archeologiche - Univer- 
sità di Pisa 
http://www.arch.unipi.it 
/Foto Libro/Foto Libro.html 



http://www.itportal.it 



3 ►►► 35 



TECNICA 



Animazione 



IN JAVA 3D 



(parte terza) 




Dopo aver toccato i temi 

fondamentali per quanto 

riguarda la creazione dei nostri 

universi tridimensionali, 

possiamo ora addentrarci in 

quegli argomenti, più marginali, 

che sono utili per approfondire 

le nostre conoscenza delle 

librerie Java per lo sviluppo 3D. 

E quale tema è più interessante 

trattare se non l'animazione 

delle scene che abbiamo 

imparato a generare? Vediamo 

quindi come procedere, una 

volta create le scene che 

intendiamo animare, per fare in 

modo che esse risultino dotate 

di una qualche dinamicità. 



Innanzitutto occorre fare una importante premes- 
sa, che riguarda il modo in cui possono essere ge- 
nerate le animazioni. Esse infatti possono avere 
due diverse origini: una data dallo scorrere del tem- 
po, (nel qual caso si parla di animazioni), ed una inve- 
ce dall'interazione dell'utente con la scena, (denomi- 
nate appunto interazioni). Anche se la logica con la 
quale questi due differenti metodi funzionano è simi- 
lare, le classi sulle quali si appoggiano sono differen- 
ti, rendendo di fatto diverso il modo in cui è necessa- 
rio procedere per ognuno dei due comportamenti. Ma 
vediamo appunto come le API 3D ci vengono in aiu- 
to nella programmazione di scene dinamiche, illu- 
strando i passi fondamentali da compiere per arriva- 
re alla creazione di un esempio pienamente funzio- 
nante. 

ANIMAZIONE 
E INTERAZIONE 

Abbiamo detto che le due differenti forme di dinami- 
cità possibili, poggiano comunque sulle stesse basi, 
vediamone quindi i punti in comune. Ogni azione di- 
namica in Java3D si realizza utilizzando i Comporta- 
menti (Behaviors). Un Comportamento non è altro che 
una classe che si occupa di apportare delle modifiche 



ad un oggetto o alla scena stessa in risposta a partico- 
lari eventi che si sono scelti di intercettare. Occorre 
quindi, per poter realizzare una scena dinamica, crea- 
re dei Comportamenti che possano essere sfruttati per 
modificare il nostro universo. Come fare per creare un 
comportamento? I passi necessari sono pochi e sem- 
plici, infatti si deve: 

1. Creare una classe che estenda la classe Behavior. 

2. Fornire la classe di un costruttore che riceva l'og- 
getto da modificare. 

3. Specificare una condizione di attivazione del 
Comportamento . 

4. Specificare quali modifiche il comportamento de- 
ve apportare all'oggetto. 

5. Specificare la prossima condizione di attivazione. 



J2SE 1.4 




Fig. 1: Il parallelepipedo, protagonista della 
nostra scena. 

Anche se i passaggi non sono molti, è comunque uti- 
le sapere che vi sono numerose classi predefinite che 
si occupano di rispondere agli eventi più comuni, e 
che ci sollevano dal gravoso compito di dover scrive- 
re un Comportamento per ciascuna differente anima- 
zione o interazione. Vedremo più in là queste classi e 
come è possibile utilizzarle per i propri scopi, ma, per 
ora, dedichiamoci allo studio del funzionamento dei 
Comportamenti analizzando passo passo tutti i punti 
necessari per la realizzarne uno personalizzato. A tal 
scopo analizziamo il listato seguente: 

public class ComportamentoSemplice extends Behavior{ 

private Tra nsform Group oggetto; 

private Transform3D rotazione = new Transform3D(); 

private doublé angolo = 0.0; 

public ComportamentoSemplice(TransformGroup 

oggetto){ 



File Sul CD 

soft\codice\allegati3.zip 



Ó\ 



Navigazione 

Per navigare nel- 
l'universo che ab- 
biamo realizzato, occor- 
re utilizzare i seguenti 
tasti: 

Freccia su = zoom in; 
Freccia giù = zoom out; 
Freccia destra = sposta- 
mento a destra; 
Freccia sinistra = spo- 
stamento a sinistra; 
Pag. su = spostamento 
in alto; 

Pag. giù = spostamen- 
to in basso; 

Se non riuscite a muo- 
vervi nella scena, po- 
trebbe essere neces- 
sario fare click sulla fi- 
nestra dell'applicazione 
in modo da selezionarla 
come attiva. 



http://www.itportal.it 



3 ►►► 37 




this. oggetto = oggetto;} 



J2SE 1.4 



Animazione 

IN JAVA 3 D 



Comportamenti 

r& Oltre a quelli visti 
—J nel listato di esem- 
pio, sono molte le classi 
che si occupano di fornire 
dei Comportamenti pre- 
definiti utili per i casi più 
semplici. Tra queste sicu- 
ramente le più utilizzate 
sono MouseBehavior, che 
serve per gestire oggetti 
tramite mouse, e tutte le 
sottoclassi di Interpola- 
tor, utili per modificare 
forma, colore, dimensio- 
ne e trasparenza di un 
solido. 



public void initialize(){ 



this.wakeupOn( new WakeupOnAWTEvent ( 

KeyEvent.KEY_PRESSED)); } 

public void processStimulus( Enumeration parametri ){ 
angolo += 0.1; 



rotazione. rotY(angolo); 



oggetto.setTransform(rotazione); 



this.wakeupOn( new WakeupOnAWTEvent ( 
KeyEvent.KEY_PRESSED));> 



} 



Come appare chiaro dal listato, implementare Com- 
portamenti personalizzati non è eccessivamente com- 
plicato anche se, nel caso di procedure più complesse, 
il codice può risultare sicuramente più impegnativo. 
Occorre premettere che questo comportamento fa in 
modo che un solido ad esso associato, una volta vi- 
sualizzata la scena, rimanga immobile finché l'utente 
preme un tasto. Quando un tasto viene premuto, esso 
inizia a roteare su se stesso intorno all'asse delle Y 
senza più fermarsi. Analizzando la dichiarazione del- 
la classe, la prima cosa da notare è che essa deriva dal- 
la classe Behavior, come specificato al punto 1 del pre- 
cedente elenco. Seguono poi una serie di proprietà 
private della classe tra cui distinguiamo oggetto che 
rappresenta l'oggetto che il comportamento andrà a 
modificare. Il costruttore della classe, che rappresenta 
il 2° punto della nostra scaletta, non fa altro che im- 
postare il valore di questa variabile. Arriviamo final- 
mente al primo dei metodi ereditati dalla classe Beha- 
vior, soprascritto per dotare la nostra classe di una 
qualche nuova funzionalità: initializeQ. Questo meto- 
do viene richiamato dal sistema in risposta ad un 
evento che corrisponde all'iniziazione del Comporta- 
mento, che si verifica quando una scena viene visua- 
lizzata. Il metodo posto all'interno della funzione, di 
nome wakeupOn(. . .), si utilizza per dichiarare al Com- 
portamento di rimanere in attesa della condizione 
specificata, esaudendo così il punto 3 del nostro elen- 
co. La condizione utilizzata nel nostro esempio altri 
non è che l'evento di pressione di un tasto. La funzio- 
ne successiva, processStimulus( . . .), è anch'essa eredita- 
ta da Behavior, ed è il metodo che viene richiamato 
quando si verifica la condizione di attivazione del 




Comportamento, cioè nel nostro caso la pressione di 
un tasto. In questo metodo è possibile implementare 
il punto 5 della nostra scaletta, visto che è proprio 
questa la funzione che modifica effettivamente le va- 
rie geometrie del solido associato al Comportamento. 
Le istruzioni che formano il corpo della funzione, so- 
no infatti le istruzioni di modifica dell'angolazione 
sull'asse Y del solido. Per finire, come nel punto 6 del- 
l'elenco, è necessario reimpostare una condizione di 
attivazione per fare in modo che il solido richiami 
questa stessa funzione al verificarsi di un nuovo even- 
to. Il metodo wakeupOn(. . .), infatti, termina la sua fun- 
zione dopo la prima volta e se non si imposta nuova- 
mente il Comportamento in attesa di un evento, esso 
terminerà di essere utilizzabile. Bene, il nostro com- 
portamento è pronto per essere utilizzato ma, per far- 
lo, è necessario definire ancora un paio di cose. In- 
nanzitutto affinché il Comportamento funzioni è ne- 
cessario applicargli una sfera di influenza, che corri- 
sponde alla distanza entro la quale il Comportamen- 
to viene attivato. In parole semplici, se siamo molto 
distanti da un oggetto che deve subire delle modifi- 
che, è probabile che dette modifiche non risultino vi- 
sibili all'utente ma, ciononostante, esse saranno state 
eseguite, portando via tempo di calcolo prezioso in 
un sistema di rendering in tempo reale. Per evitare 
questo spreco, è stato pensato un sistema di gestione 
delle animazioni che prende in considerazione soltan- 
to quelle la cui sfera di influenza racchiude la vista at- 
tualmente utilizzata dall'osservatore. Un altro impor- 
tante punto da rispettare affinché le animazioni che 
abbiamo pensato funzionino a dovere, è quello di im- 
postare il Trasformatore incaricato di modificare uno 
o più oggetti. A questo scopo occorre impostare per 
quest'ultimo la possibilità di essere modificato in uno 
o più modi. Ma vi sarà tutto più chiaro quando legge- 
remo il listato della nostra applicazione. 



IL NOSTRO ESEMPIO 

Questa volta, visto che ormai dovreste essere in grado 
di capire molti dei passaggi riportati, eviterò di com- 
mentare il superfluo, facendovi soffermare esclusiva- 
mente sui punti che formano l'argomento odierno. 
Ma prima di tutto analizziamo il codice che forma la 
nostra applicazione: 



import java.awt.*; 



import javax.swing.*; 



import javax.vecmath.*; 



import javax.media.j3d.*; 



import com.sun.j3d.utils. universe.*; 



import com.sun.j3d.utils.geometry.*; 



import com.sun.j3d.utils.behaviors.keyboard.*; 
public class Dinamicità extends JFrame{ 



public Dinamicita(){ 



super("Dinamicita"); 



setSize(800,600); 



Fig. 2: Visti da vicino. 



setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 



38^^ F e b b 



http://www.itportal.it 



TECNICA 



JPanel nuovoPannello = new JPanelQ; 

nuovoPannello.setLayout(new BorderLayoutQ); 

Canvas3D tela = new Canvas3D(null); 

nuovoPannello.add("Center",tela); 

Simplellniverse universo = new SimpleUniverse(tela); 
universo. getViewingPlatform() 

.setNominalViewingTransform(); 

BranchGroup gruppo = new BranchGroupQ; 

// Inseriamo qui il codice per costruire la nostra scena 3D 

/*** ANIMAZIONE ***/ 

// Iniziamo creando un oggetto che si occupi dello 

scorrere del tempo 

Alpha andatura = new Alpha(-1,50Q0); 

// Poi creiamo un'area entro la quale le animazioni 

hanno luogo 

BoundingSphere area = new BoundingSphereQ; 
// Ora costruiamo tre strutture che identifichino i 

colori primari... 

Color3f rosso = new Color3f(l.Qf,0.0f,0.0f); 

Color3f verde = new Color3f(0. 07,1-07,0 -00; 

Color3f blu = new Color3f(0.0f y 0.0f y 1.0f); 

// con i quali costruiamo poi un materiale... 

Material materiale = new Material(blu, rosso, verde, 

rosso, O.Of); //modificabile... 

materiale. setCapability( 

Material.ALLOW_COMPONENT_READ| 

Material.ALLOW_COMPONENT_WRITE); 

// che utilizziamo per costruire un'estetica. .. 

Appearance estetica = new AppearanceQ; 

estetica .setMaterial(materiale); 

// necessaria a creare infine il nostro solido. 

com.sun.j3d.utils.geometry.Box solido = new 

com.sun.j3d.utils.geometry.Box(0.2f,0.4f,0.3f,estetica); 
// Creiamo ora il trasformatore da utilizzare per le 

nostre animazioni... 



/*** ILLUMINAZIONE ***/ 

// Illuminamo adeguatamente la scena per renderla 

visibile 



// Ora impostiamo i comandi per rendere il nostro 

mondo navigabile 

/*** INTERAZIONE ***/ 

public static void main(String[] args){ 

new DinamicitaQ; } 



ANIMAZIONE 

Il listato di esempio riportato si occupa di creare un 
parallelepipedo applicandovi un materiale non pre- 
definito, nonché di animarlo, facendolo roteare su se 
stesso, e modificarne i valori del materiale associato in 
modo che sembri cambiare colore. Inoltre, al punto di 
vista utilizzato per generare la scena, viene applicato 
un Comportamento che rende possibile la navigazio- 
ne della stessa. 
Sarà quindi possibile, utilizzando dei tasti particolari, 



muoversi all'interno della scena grafica e gironzolare 
intorno al nostro parallelepipedo animato. Il codice fi- 
no al commento "Inseriamo qui il codice per costrui- 
re la nostra scena 3D" è stato più volte analizzato e 
serve a generare un'applicazione che contenga il no- 
stro universo. Subito dopo appare il primo dei blocchi 
di codice che ci interessa, quello relativo air animazio- 
ne della scena. 

La prima istruzione che troviamo crea un oggetto 
Alpha, che serve per essere associato a dei Comporta- 
menti che devono verificarsi con lo scorrere del di 
tempo. In realtà l'oggetto Alpha è molto potente e 
configurabile, e permette di stabilire esattamente: 
quando attivare i Comportamenti ad esso associati, 
quante volte farlo nel corso dell'applicazione e dopo che 
lasso di tempo. 

Quest'oggetto è uno dei più importanti per generare 
animazioni dovute al passaggio del tempo. Nella riga 
successiva troviamo un altro oggetto che dovremmo 
aver imparato a conoscere: BoundingSphere. Esso si oc- 
cupa di fornire un'area entro la quale tutti gli oggetti 
ad esso associati (e come potete vedere sono molti) 
compiano le azioni per la quali sono stati program- 
mati. Come infatti già spiegato, le animazioni e le in- 
terazioni, vengono calcolate esclusivamente se la loro 
sfera di influenza (BoundingSphere) risulta contenere 
anche il punto di vista utilizzato dall'utente per ren- 
derizzare la scena. Il costruttore di default utilizzato 
nel nostro esempio compie egregiamente il suo lavo- 
ro, impostando dei limiti più che sufficienti alle nostre 
esigenze. 

Successivamente II listato crea tre strutture dati che 
identificano i tre colori primari, rosso verde e blu, ne- 
cessari a creare un oggetto di tipo Materiale. Sin ora 
non ci siamo mai occupati della realizzazione di soli- 
di che avessero delle caratteristiche estetiche diverse 
da quelle predefinite ma, in questo caso, creeremo 
una figura che ha delle proprietà visive uniche. I pa- 
rametri passati per la creazione del Materiale, infatti, 
rappresentano come esso risponde visivamente quan- 
do interessato dalle sorgenti luminose. Ma a cosa ci 
serve? 

Come preannunciato, le animazioni di una scena gra- 
fica possono andare a modificare numerosi campi di 
un solido, tra cui anche il suo materiale. Ma per farlo, 
quest'ultimo deve essere predisposto ad accettare 
eventuali modifiche. Ed è proprio a questo che serve 
la riga di codice successiva, che fa in modo che il no- 
stro materiale risulti modificabile in lettura e scrittura. 
Una volta generato questo Materiale modificabile es- 
so viene utilizzato, nelle due linee successive, per 
creare un oggetto di tipo Appearance che rappresenta 
l'insieme delle specifiche estetiche di un solido. Oltre 
al materiale, infatti, esso può avere associate diverse 
caratteristiche (textures, trasparenze, etc.etc.) che ven- 
gono immagazzinate in un unico oggetto che funzio- 
na da contenitore per tutte le possibili caratteristiche 
estetiche di uno o più solidi. Nel nostro caso, l'unica 
particolarità dell'oggetto Appearance sarà nel materia- 




J2SE 1.4 



Animazione 

IN JAVA 3D 



WAKE_UP_ 
EVENTS 

r% Molte sono anche le 
^ condizioni che pos- 
sono essere implemen- 
tate nei Comportamenti 
per fare in modo che 
questi ultimi vengano at- 
tivati in un particolare 
momento. Si può appor- 
tare una modifica alla 
scena grafica ad esem- 
pio quando la vista del- 
l'utente entra nell'area 
di influenza del Compor- 
tamento, oppure in se- 
guito a delle collisioni, o 
in base ad un'evento ge- 
nerato dall'utente, etc. 
etc. 



http://www.itportal.it 



3 ►►► 39 




J2SE 1.4 



Animazione 

IN JAVA 3D 



Bill board 

/% Esiste anche una tec- 
^ nica, chiamata ap- 
punto Billboarding, che 
gestisce l'utilizzo di figu- 
re bidimensionali al posto 
di veri e propri solidi, per 
fare in modo di simulare 
un'universo solo a prima 
vista tridimensionale. Ja- 
va 3D supporta anche 
questa tecnica. 



le che abbiamo creato. 

Fatto ciò, non rimane altro da fare, nella successiva li- 
nea di codice, che generare il nostro solido con asso- 
ciato l'oggetto Appearance appena realizzato. Ora che 
abbiamo un oggetto visivo sul quale lavorare, il lista- 
to prosegue andando a creare un oggetto Transform- 
Group che ci servirà per compiere le nostre animazio- 
ni. Come introdotto nel primo articolo di questa serie, 
infatti, un qualsiasi oggetto da aggiungere alla scena 
grafica va aggiunto ad un Gruppo principale, da col- 
legare poi alla locale fornitaci dalla classe SimpleUni- 
verse che identifica il nostro universo. Ma se si pro- 
getta di compiere delle trasformazioni su uno o più 
oggetti grafici, allora è necessario introdurre tra il 
gruppo ed il solido un altro oggetto di tipo Tran- 
sformGroup, utile a realizzare la trasformazione. Per 
fare in modo che questo oggetto sia in grado di ap- 
portare delle modifiche alla scena anche dopo che 
questa sia stata compilata, si dono impostare delle ca- 
pacità al trasformatore così come fatto nella linea di 
codice successiva alla creazione dello stesso. Dopo 
questa istruzione il trasformatore sarà in grado di mo- 
dificare il o i solidi ad esso associati. 
Proseguendo nella lettura del listato, si notano i due 
successivi blocchi di codice compiere azioni molto si- 
mili. Essi altro non sono che dei Comportamenti pre- 
definiti di Java3D che noi utilizziamo per dichiarare 
in modo il nostro solido deve venire modificato. 
La classe Colorlnterpolator si occupa di modificare il 
materiale associato al nostro oggetto grafico, ed infat- 
ti in fase di costruzione dello stesso gli vengono pas- 
sati come parametri il materiale da modificare e l'og- 
getto Alpha che indica con che ritmo e per quante vol- 
te apportare la modifica. 

La classe Rotationlnterpolator, invece serve a genera- 
re un Comportamento di rotazione per qualsiasi og- 
getto le si associ. Come è possibile osservare dal codi- 
ce, l'oggetto passato al costruttore di Rotationlnterpo- 
lator, insieme al già visto oggetto Alpha anche qui ne- 
cessario, è il Trasformatore precedentemente creato 
ed al quale assoceremo successivamente il nostro so- 
lido. 

Se inserissimo più solidi nel nostro trasformatore, es- 
si subirebbero tutti la medesima animazione. Entram- 
bi i blocchi di codice continuano poi, dopo l'utilizzo 
del costruttore per generare due oggetti di tipo Com- 
portamento che compiono animazioni differenti, im- 
postando i limiti di influenza di quel Comportamen- 
to per fare in modo che esso risulti attivo soltanto en- 
tro una certa distanza dall'osservatore. Il passo finale 
poi consiste neir aggiungere i Comportamenti creati 
al Trasformatore che abbiamo creato, in modo che es- 
so possa utilizzarli dinamicamente. 
I due ultimi passaggi prima del blocco di codice dedi- 
cato all'illuminazione, poi, altro non fanno che inseri- 
re tra il Gruppo che rappresenta la nostra scena grafi- 
ca, ed solido che dobbiamo modificare, il Trasforma- 
tore, con tutti i vari Comportamenti associati, incari- 
cato della modifica. 



INTERAZIONE 

Prima di arrivare al blocco di codice relativo all'inte- 
razione, è necessario passare brevemente in rassegna 
le istruzioni che rendono possibile la corretta illumi- 
nazione della scena. Come già visto nel capitolo dedi- 
cato alle luci, le istruzioni in questo blocco creano due 
delle sorgenti di luce possibili in Java3D, una tenue 
luce ambientale ed una luce direzionale. Alle luci vie- 
ne infine assegnata un'area di influenza simile a que- 
la dei Comportamenti. 

Finalmente arriviamo al gruppo di istruzioni che ren- 
dono possibile la navigazione del nostro universo tri- 
dimensionale. Come potete osservare, il listato è pres- 
soché identico a quello degli altri due Comportamen- 
ti utilizzati in precedenza, ad eccezione del fatto che 
qui non è necessario fornire un oggetto Alpha che si 
occupi di innescare gli eventi che modifichino gli at- 
tributi del solido. L' inutilità di questo oggetto è data 
dal fatto che non più lo scorrere del tempo, quanto in- 
vece l'input dell'utente, serve da stimolo al Compor- 
tamento per essere innescato. Ma vediamo nel detta- 
glio il funzionamento. Innanzitutto, poiché ciò che in- 
tendiamo modificare è la posizione del punto di vista 
dell'utente, occorre recuperare questo oggetto rac- 
chiuso all'interno della classe SimpleUniverse. Di que- 
sto si occupa la prima linea di codice del blocco dedi- 
cato all'interazione. Successivamente, altro non serve 
che procedere come visto prima per gli altri due Com- 
portamenti, e cioè costruendo un oggetto di tipo 
Comportamento che compia le azioni che ci interes- 
sano, impostarne i limiti di influenza ed aggiungen- 
dolo alla scena. Le uniche differenze qui sono date 
dall'assenza dell'oggetto Alpha e dall' aver aggiunto il 
Comportamento non al Trasformatore, poiché esso 
deve occuparsi solo della modifica del solido, bensì 
all'oggetto che lo contiene, cioè il Gruppo che andre- 
mo poi ad aggiungere all'universo. Fatto ciò non resta 
che terminare il programma come fatto più volte, as- 
sociando il gruppo all'universo, compilando e mo- 
strando il tutto. 



CONCLUSIONI 

Gli argomenti trattati oggi sono veramente solo una 
breve introduzione su un argomento vastissimo che 
meriterebbe un libro intero. E infatti possibile, utiliz- 
zando animazioni ed interazione, arrivare a risultati 
incredibili in un prodotto immediato e potente come 
Java3D. Gli strumenti presenti nelle API permettono 
infatti profonde manipolazioni, effetti di morphing, 
sostituzioni di oggetti, textures, etc.etc. Starà a voi, al- 
la vostra fantasia e voglia di sperimentare, arrivare a 
generare ambienti tridimensionali animati ed intera- 
gibili che possano essere utilizzati nelle vostre appli- 
cazioni. A me non resta che augurarvi di riuscire sem- 
pre ad orientarvi in un mondo affascinante e com- 
plesso come quello della programmazione grafica tri- 
dimensionale. 

Giuliano Uboldi 



40 ►►► F e b b 



r a i o 



2 3 



http://www.itportal.it 



Biblioteca 



ON LINE 



Flash MX - Tutto & Oltre 



DevShed 

Un sito interamente dedi- 
cato alla comunità degli 
sviluppatori. Si distingue 
per i frequentatissimi fo- 
rum messi a disposizione 
(ASP, XML, Perl, Visual 
Basic, Flash, C++, ecc, 
ecc). 



[-■ |De> 

E 


reloperShed 


*fS<-^— wcT" ^"^ , 


&T"— 


i 


■ui^wjy™ 




La collana Tutto & oltre di Apogeo, punto di riferimento degli utenti avanzati e 
professionali, si pregia di un nuovo testo dedicato al linguaggio Flash, vera 
rivoluzione per il supporto allo sviluppo di pagine Web. Il testo mostra passo passo 
come sfruttare al meglio il più potente programma di animazione vettoriale che ha 
rivoluzionato il modo di progettare e creare pagine Web. Ricco di illustrazioni, 
esempi e dimostrazioni pratiche a cura di esperti del settore, è sicuramente un libro 
che non può mancare nella biblioteca di chi desidera costruire lavori di qualità. Tra 
gli argomenti trattati: 

• Introduzione all'uso di Flash 

• I nuovi strumenti di disegno 

• Contenuto caricato dinamicamente nei progetti Web 

• Utilizzo di Action Script e dei componenti precostituiti 

• Effetti dinamici, audio MP3, giochi interattivi in Flash 



http://www.devshed.com/ 

DevBuzz 

DevBuzz.COM è un sito 
dedicato a chi si cimenta 
giorno per giorno nella 
programmazione dei Poc- 
ket PC. Mette a disposi- 
zione una vasta serie di 
tool, tecniche di pro- 
grammazione e soluzioni 
a svariate tipologie di 
problemi. 




.NET 247 

Per dirla così come si 
auto-sponsorizza il sito: il 
primo sito dedicato al fra- 
mework .NET, interamen- 
te indipendente. .NET 
problem? .NET answer. 
http://www.dotnet247.com/ 




247reference/default.aspx 



Nel CD-ROM allegato: software in versione trial e shareware, aggiunte, plug-in, 
modelli e file degli esempi trattati nel testo. 

Difficoltà: Medio-Alta • Autori: Reinhardt Robert, Dowd Snow • Editore: Apogeo 
http://www.apoqeonline.com • ISBN: 88-503-2070-1 • Anno di pubblicazione: 2002 
Lingua: Italiano • Pagine: 1048 • Prezzo: € 55,00 • Contiene 1 CD-Rom 

Beginning database with MySQL 

MySQL rappresenta il prodotto più popolare tra gli RDBMS Open Source, 

rinomato soprattutto per velocità e potenza di elaborazione. Il testo si propone 

come guida di riferimento alla scoperta del database, analizzandone, 

approfonditamente, tutte le funzioni più importanti. Un tour alla scoperta di 

MySQL, che guida il lettore, passo passo, dall' installazione alla sua 

configurazione, all'esecuzione di comandi, semplici e complessi, sia per 

T amministrazione del sistema che per il suo utilizzo pratico. Molti esempi 

mostrano come integrare la potenza di MySQL all'interno dei più comuni 

linguaggi di programmazione orientati al Web. 

Difficoltà: Medio-Alta • Autori: Richard Stones, Neil Matthew • Editore: WROX 
http://www.qorilla.it • ISBN: 1-861006-92-6 • Anno di pubblicazione: 2002 • Lingua: Inglese 

Pagine: 608 • Prezzo: $39,99 




Building an ASP.NET Intranet 



e 



■&£&! 



Building An 

ASP.NET 

Intranet 



Il libro giusto per tutti coloro che vogliono apprendere i concetti di base per lo 
sviluppo di applicazioni Intranet, utilizzando le nuove funzionalità messe a 
disposizione dalla tecnologia ASP.NET. In questo testo gli autori hanno posto 
T accento più sull'aspetto pratico che teorico, mostrando, di fatto, un esempio 
reale di applicazione, nella fattispecie IBuySpy Portai. 

• Qual è la differenza tra un'applicazione Intranet e un'applicazione Internet? 

• Quali i requisiti per creare un'applicazione Intranet? 

• Come gestire la sicurezza di un'applicazione Intranet? 

Queste alcune delle domande che trovano risposta nel testo. 

Difficoltà: Medio-Alta • Autori: Vari • Editore: WROX http://www.qorilla.it • ISBN: 1-861007-49-3 
Anno di pubblicazione: 2002 • Lingua: Inglese • Pagine: 480 • Prezzo: $49,99 



http: //www. itportal.it 



3 ►►► 



41 



Tips&Tricks 



I trucchi 
del mestiere 



La rubrica raccoglie trucchi e piccoli pezzi di codice che solitamente non trovano posto nei manuali, ma sono frutto dell'esperienza di 
chi programma. Alcuni trucchi sono proposti dalla Redazione, altri provengono da una ricerca sulla Rete delle Reti, altri ancora ci 
giungono dai lettori. Chi vuole contribuire potrà inviarci i suoi tips&tricks preferiti che, una volta scelti, verranno pubblicati nella 
rubrica. Il codice completo dei tips lo trovate nel CD allegato nella directory \tips\. 



► Visual Basic.NET 



► ►►►►►► 



Come sfruttare 

l'ereditarierà visuale in Visual Basic .NET 

Visual Basic ha sempre avuto come punto di forza una estrema 
semplicità nella costruzione delle interfacce utente, 
il punto in cui pagava dazio ad altri linguaggi come C++ e Java 
era lo scarso supporto alle più avanzate funzionalità Object 
Oriented. Questo gap è stato ampiamente superato con Visual 
Basic.NET. Nell'esempio che andiamo ad illustrare vedremo 
proprio come sfruttare l'ereditarietà nelle interfacce utente. 



Supponiamo di voler distribuire un'ap- 
plicazione in cui tutte le form presen- 
tino il marchietto dell'azienda com- 
mittente in alto a destra. Grazie alla eredita- 
rietà potremo creare una volta per tutte la 
struttura base della form ed ereditarla in 
tutte le altre. Inoltre, se ci troveremo a di- 
stribuire la stessa applicazione per un'altra 
azienda, potremo cambiare il marchio stes- 
so o la sua posizione, ottenendo che al mo- 
difica si ripercuota a cascata in tutte le form. 

CREIAMO 

LA CLASSE BASE 

Ricordando che anche una form altro non è 
che una classe, apriamo un nuovo progetto 
in Visual Studio .NET e creiamo una nuova 
libreria di classi: avere qui la nostra forma 



Categorie 



- 1 El.iN.n" •->.! i-'.'jj.i ' •_ L».jfc 

si Interface 
■m Codice 
_| Dati 



mm 



m § 

arni Controllo 



Form per applicano 
Nome: J ioForrn.vb 



base ci consentirà di aggiungerla successi- 
vamente in qualsiasi applicazione sviluppa- 
ta in seguito. Chiameremo questa libreria 
LibreriaForm. In questa libreria andremo ad 
aggiungere una nuova form, chiamiamola 
ioForm (Fig. 1). 







1 Y-'Ìbogrammo a 




Fig. 1: Aggiunta di un nuovo elemento. 



Fig. 2: Interfaccia dell'applicazione. 

Per aggiungere il logo utilizziamo una Pic- 
tureBox, andando a indicare il percorso in 
cui si trova l'immagine relativa. Posizionia- 
mo la PictureBox in alto a destra e andiamo 
a individuare fra le proprietà quella relativa 
all'ancoraggio. Per default, l'ancoraggio è 
fissato in alto a sinistra, noi lo sposteremo in 
altro a destra. Questo accorgimento consen- 
tirà di tenerlo nell'angolo, alla corretta di- 
stanza dai bordi, qualsiasi sia la dimensione 
della finestra (Fig. 2). Quando in seguito de- 
riveremo una form dalla form base, tutti i 




M 



ROGRAMMO : 



ìriaForm" (p i 
- /p LibreriaForm 

+■■ |S| References 
3 Assemblylnfo.vb 
S» Esplora soluzioni | ^ Cerca | 




Fig. 3: Modifier 

controlli che abbiamo sistemato nella form 
di libreria saranno presenti anche nella 
form derivata. Le proprietà di questi con- 
trolli non potranno essere modificate se i 
corrispondenti controlli nella form base 
hanno la proprietà Modifier impostata a Pri- 
vate o Friend. Per lasciare alle classi derivate 
la possibilità di modificare le caratteristiche 
dei controlli è dunque necessario impostare 
la proprietà Modifier dei controlli a Public 
oppure Protected. Andiamo ad operare in 
questo modo sul controllo relativo al logo. 



<! > x 


msmummamna^m KE1 




\*\ ifii e 






:. ili 1 [Hill I H il II -fi-I Ufi 11 II-! Il 

fi- snHJuasa 






m 


Rigenera 




_J Aggiungi nuovo elemento. . . 

Aggiungi gemente esistei ite .. 
' i Nuova cartella 


y 
m 

X 


jferirnento... 
rimento Web... 


Aggiungi Windows Form , . . 


tome progetto 


-^ Aggiungi form ereditato.,. . 


Jd] Aggiungi controllo utente,.. ^ 
jj] Aggiungi controllo ereditato. , . 


estLibreria 


Aggiungi so jsione e controllo de codice sorgente . 


Aggiungi componente. , . 
Aggiungi modulo,.. 
%$ Aggiungi classe.., 


Incolla 
Rimuovi 
Rinomina 






Proprietà 



Fig. 4: AggiungiFormDerivata 

CREIAMO 

LA FORM DERIVATA 

Prima di poter sfruttare la libreria a cui stia- 
mo lavorando, è necessario compilare il pro- 
getto. E' bene tenere presente che, al fine di 
rendere effettive le modifiche, è necessario 
ricompilare il progetto ogni volta che andia- 
mo a modificare la form base. Per provare la 
libreria appena creata, imposteremo un nuo- 
vo progetto ma, ovviamente, la nostra Libre- 



42»*> F e b b 



http: //www. itportal.it 



R I 



riaForm può essere utilizzata da qualsiasi 
progetto .NET, anche già esistente. Il nuovo 
progetto lo chiameremo TestLibreria e lo 
creiamo come applicazione VB.NET. Andia- 
mo dunque ad aggiungere una form eredi- 
tata, cliccando con il tasto destro sul nodo 
TestLibreria di Esplora Soluzioni. Se la form da 
cui vogliamo derivare si trova in un proget- 
to diverso da quello corrente, dovremo spe- 
cificare il percorso in cui si trova la DLL re- 
lativa alla classe base: nel nostro caso XLibre- 
riaForm\bin. Così 
facendo avremo 
nel nostro proget- 
to una form del 
Fig. 5: Notate la tutto identica a 

piccola freccia in alto 
a sinistra. q uella presente in 



1M 



ROGRAMMO 



libreria. Se guardate con attenzione il con- 
trollo relativo al logo, potete notare una pic- 
cola freccia in alto a sinistra. La freccia sta a 
indicare che il controllo è stato ereditato. 



MODIFICHE 

Grazie al fatto che abbiamo dichiarato pu- 
blic la proprietà Modifier della classe base, 
possiamo aggiornare l'aspetto ed il compor- 
tamento della classe derivata. Proviamo, ad 
esempio, a cambiare la posizione del logo, 
spostandolo neir angolo in alto a sinistra e 
modificando la relativa proprietà di anco- 
raggio con 'Top, Left". A questo punto pos- 
siamo anche aggiornare il logo con uno più 
recente, modificando la proprietà Image... 



□ ^^^^^^™fc D 

È :::::::::::::::::::::::::::::::::::::::::::::::::::::::: | 



Fig. 6: Risultato finale. 

Nella figura trovate il risultato dei nostri 
sforzi: l'ereditarietà visuale è servita! Sul 
CD potete trovare i progetti in Visual 
Studio .NET relativi all'esempio pre- 
sentato. 



► C 



+ + 



► ►►►►►► 



► ► ► ► 



stamento ed il ridimensionamento delle finestre. 



« 



Come risolvere equazioni 
di secondo grado 



Una piccola applicazione che si occupa di risolvere equazioni qua- 
dratiche del tipo Ax 2 + Bx + C = e che implementa due funzioni 
specifiche: numRoots(a, b, e) e quadSolve(a, b, e); la prima determina il 
numero di radici, mentre la seconda si occupa di trovare le radici. 

Come leggere un file riga per riga 

Utilizzando le Standard Template Library, questo piccolo codice con- 
sente di accedere ad un file e leggerlo riga per riga. Per immagazzi- 
nare i dati così ottenuti viene utilizzato un vettore: ogni riga è me- 
morizzata in una cella di questo vettore. 

Come calcolare il numero di nepero 

Utilizzando le serie di Taylor, questo piccolo pezzo di codice si occu- 
pa di calcolare il numero di Nepero. Non particolarmente veloce, ha 
nella semplicità la sua forza. 

Come ridurre lo sfarfallio durante 
il ridimensionamento delle finestre 

Come tutti sanno, il messaggio WM_PAINT è inviato ad una finestra 
ogni qual volta si rende necessario ridisegnarla. Dunque, general- 
mente, scriviamo tutte le istruzioni relative al layout della finestra 
nell'handler di WM_PAINT, incluse le istruzione relative allo sfondo. 
Quello che accade in realtà è che prima di WM_PAINT è inviato il 
messaggio WM_ERASEBKGND, la cui implementazione di default 
cancella l'area corrispondente alla finestra con un rettangolo bianco. 
Per migliorare l'efficienza può essere utile individuare gli oggetti che 
non cambiano sullo schermo, il codice che si occupa di disegnare 
questi oggetti può essere dunque spostato dall'handler di 
WM_PAINT a quello di WM_ERASEBKGND, avendo l'accortezza di 
ritornare un valore diverso da zero per indicare che non è più ne- 
cessaria la cancellazione riferita a quell'oggetto. 
Con questa soluzione si riduce la complessità delle operazioni di di- 
segno di una finestra e si elimina l'effetto di sfarfallio durante lo spo- 



► Java 



► ► ► ► ► 



► ►►►►►► 




Come assegnare 

la dimensione di un array 

a run-time 

Grazie al fatto che in Java un array non è altro che un oggetto, la sua 
dimensione è trattata come una proprietà dell'oggetto stesso e può 
dunque essere assegnata a run time. Questa caratteristica diviene di 
fondamentale importanza in tutti i casi in cui abbiamo bisogno di un 
array per immagazzinare dei dati ma non possiamo conoscere la di- 
mensione esatta prima di eseguire l'applicazione. 

Come implementare una funzione 
di search&replace 

Una classe semplice ed utile che consente di effettuare la classica 
funzione di "trova e sostituisci" all'interno di una stringa. Il metodo 
riportato sul CD accetta tre parametri: la stringa su cui effettuare la 
ricerca, la stringa di caratteri da cercare e la stringa di caratteri che 
andrà a sostituire quella originale. 

Come semplificare l'utilizzo 
degli switch 

I programmatori C++ sono abituati ad analizzare gli argomenti pas- 
sati dalla linea di comando attraverso i parametri "ini arge" e "char 
*argv[]" della funzione maini). Un utilizzo del tutto simile dei para- 
metri è possibile attuarlo in Java per impostare le opzioni di avvio di 
un'applicazione. La classe presente sul CD rappresenta un utile fra- 
mework su cui basare una propria implementazione degli switch. 

Come caricare una classe da un file Jar 

Una semplice, benché completa, implementazione di un class loader 
per recuperare delle classi java da un file JAR durante l'esecuzione 
di un'applicazione. Il codice allegato, ampiamente commentato, può 
essere facilmente personalizzato al fine di essere integrato nei nostri 
progetti. 



http: //www. itportal.it 



3 ►►► 43 



T I 



► V 



s u a I B a s 



► ► ► ► 



&s 



Come sfumare lo sfondo 



Con il codice qui presentato avremo a disposizione un metodo sem- 
plice ed efficace per ottenere il classico effetto di sfumatura dello 
sfondo tipico, ad esempio, di molte applicazioni di installazione. La 
sfumatura andrà a schiarirsi dal basso verso l'alto, mentre la scelta 
del colore base si effettua attraverso la combinazione dei tra para- 
metri booleani accettati dalla funzione (rosso, verde e blu). Ad esem- 
pio, per avere la sfumatura blu come sfondo è sufficiente scrivere il 
seguente codice nella procedura Form_Load: 

FadeForm Me, False, False, True 

Come mostrare i font durante 
la selezione 

La prima cosa da fare è popolare la ComboBox con i nomi dei font 
disponibili nel sistema, per fare ciò è sufficiente aggiungere il se- 
guente codice a Form_Load() 

For I = To Screen.FontCount - 1 

' Put each font into list box. 

cboFont.Addltem Screen.Fonts(I) 

Next I 

Non resta che gestire l'evento Click aggiungendo il codice che impo- 
sta il font del ComboBox: 

Private Sub cboFont_Click() 

'Set the FontName of the combo box 

'to the font that was selected. 

cboFont. FontName = cboFont.Text 

End Sub 

Come salvare la dimensione e la 
posizione di una Form 

Molti di voi avranno notato che, all'avvio, alcune applicazioni "ri- 
cordano" la posizione e la dimensione in cui si trovavano al mo- 
mento dell' ultimo utilizzo. In questo tip spieghiamo come realizza- 
re lo stesso effetto in un'applicazione Visual Basic. In un modulo del- 
l'applicazione specifichiamo una costante di questo tipo: 

Public Const ApplicationName = "Nome Applicazione" 

Questo nome serve a distinguere l'applicazione nel registro di Win- 
dows. Nell'evento Form_Load richiamiamo la funzione di recupero 
delle impostazione, passando come argomento il riferimento alla 
form corrente: 

Cali LoadFormDisplaySettings(Me) 

Mentre nell'evento Form_Unload richiamiamo la funzione di salva- 
taggio delle impostazioni: 

Cali SaveFormDisplaySettings(Me) 

Da notare che come effetto indesiderato di questo metodo si ha che 



nel registro di Windows restano le impostazioni che abbiamo defini- 
to anche dopo che l'applicazione viene disinstallata. Se si vuole in- 
tervenire su questo aspetto, le informazioni si trovano in: 

HKEY_CURRENT_USER\Software\VB and VBA Program 

Settings\My Application Name\. 

Nel CD trovate il codice delle due funzioni di salvataggio e ripristi- 
no delle impostazioni, codice che va inserito in un modulo dell'ap- 
plicazione. 

Come controllare l'input 

Capita spesso di utilizzare dei textbox per effettuare l'input di dati di 
tipo numerico. Per accertarsi che l'utente non digiti caratteri alfabe- 
tici è possibile effettuare un controllo a posteriori rispetto all'immis- 
sione, anche se sarebbe preferibile impedire direttamente in fase di 
digitazione l'immissione di caratteri diversi da quelli numerici: pro- 
prio quello che consente il codice qui presentato. 



► D e I p h 



► ►►►►►► 




Come nascondere 
l'applicazione nella task bar 



Per alcune applicazioni può essere utile inibire la visualizzazione del 
pulsante relativo sulla task bar. Per ottenere questo è sufficiente im- 
postare la proprietà ShowMainForm di Application a False. In Win- 
dows 2000 e in Windows XP l'applicazione continuerà a essere visi- 
bile tra i processi presenti nel Task Manager: proprio dal task mana- 
ger sarà possibile fermare l'applicazione, fare in modo che l'applica- 
zione giri in modalità nascosta, la rende assimilabile ad un servizio. 

Come utilizzare tipi enumerateci come 
variabili di controllo in un loop 

Una caratteristica interessante de cicli for. ..do è quella di poter usare 
tipi enumerated al posto dei più comuni interi. Utilizzando questa 
proprietà possiamo incrementare notevolmente il livello di leggibi- 
lità del nostro codice, così com'è possibile notare nella porzione di 
codice riportata sul CD. 

Come visualizzare informazioni 
relative alla occupazione di memoria 

Il box "About" standard ingloba alcune interessanti informazioni sta- 
tistiche sulla memoria. In particolare, attraverso il metodo Physica- 
lAvMemLbl è possibile conoscere la quantità di memoria complessi- 
vamente disponibile, mentre con MemorylnUseLbl si può ottenere la 
percentuale di memoria fisica occupata. 

Come impostare le proprietà comuni 
a più controlli 

Capita spesso di dover settare la medesima proprietà su più control- 
li: un caso tipico è la proprietà visible o anche enabled nelle interfac- 
ce. La procedura allegata al CD si occupa di impostate la proprietà 
visible di un gruppo di oggetti TControl. La stessa procedura può es- 
sere facilmente modificata ed estesa per accedere ad altre proprierà 
degli oggetti: 

SetVisibleProp([NewBtn,OpenBtn,SaveBtn],UserState <> usNotAuthorized); 



44 ►►► F e b b 



http: //www. itportal.it 



Torneo 



C R o b o t s 



Il Torneo 



DI CROBOTS 2K2 



E dodici. Tanti sono gli anni che 

ci separano dal primo torneo di 

crobots, tenutosi nell'orma! 

lontano 1991, quando la potenza 

dei computer si misurava in Mhz 

e l'interfaccia grafica sui P.C. era 

un lusso che pochi potevano 

permettersi. Eppure, a dispetto 

del tempo trascorso, l'attività di 

assemblare mostriciattoli in Ansi 

C non smette di attirare nuovi 

adepti... 






"onostante il numero dei robot inviati 
annualmente si mantenga sempre 
più o meno costante, la scomposizio- 
ne per autore del parco combattenti mostra caratteristi- 
che sorprendenti: accanto a quei sei o sette veterani, che 
non saltano una competizione da tempi immemorabili, 
troviamo, infatti, di volta in volta nomi nuovi che pren- 
dono il posto di quanti, per motivi di tempo o di calo di 
interesse non partecipano più alla manifestazione. Nu- 
merosi e graditissimi sono anche i ritorni: autori che, 
dopo una pausa di riflessione, si ripresentano ai nastri 
di partenza per sfidare nuovamente la sorte, sia per ani- 
mati propositi di vittoria, sia per dire, semplicemente, 
'eccomi, sono tornato'. Spulciando l'elenco degli autori 
dei 54 programmi che quest'anno si sono confrontati 
(per la verità sarebbero di più, ma alcuni sono stati in- 
viati a manifestazione oramai conclusa, un vero pecca- 
to), cercando di aggiudicarsi il premio messo in palio da 
ioProgrammo, ritroviamo con piacere Marco e Luca 
Pranzo, Tommaso de Prà e Fabio Luciano (confesso di 
non sapere quale sia il nome), un concorrente che non si 
vedeva dal lontano 1994. Tra le defezioni segnalo, per 
l'importanza dell'autore, quella di Dario Serino. A cau- 
sa degli esami universitari non ha potuto essere dei no- 
stri, ma ha promesso un ritorno in grande stile per il 
prossimo anno. Con lui in campo, forse, le cose sareb- 
bero andate diversamente. Assai gradita, giunge poi la 
conferma di Franco Cartieri che, con Copter2 e Kyash_2 
ribadisce in tutte le competizioni gli ottimi piazzamen- 
ti della scorsa stagione. Numerose le matricole, tra le 
quali si segnala senza dubbio la notevole performance 
di Antonio Barone che, con il robot TheSlayer, caccia 
molti veterani, tra i quali il sottoscritto, dalle posizioni 




nobili della classifica: a una prima analisi il suo pro- 
gramma appare lineare ed efficiente. 
Senza dubbio fornirà nuovi spunti per la prossima edi- 
zione. 



I MICROROBOT 

Anche quest'anno, come già era accaduto per il prece- 
dente evento, la maggior parte dei partecipanti ha, de- 
ciso di iscrivere un combattente solo a questa categoria: 
ben 23 dei 54 sfidanti, infatti, erano al di sotto delle 500 
istruzioni. Il girone ha salutato la vittoria di regis.r (Da- 
niele Nuzzo) nella modalità flf e di tigre.r (Alessandro 
Carlin) per la specialità 4vs4. Il calcolo combinato delle 
efficienze che, lo ricordo, attribuisce un rapporto di 5 a 
1 ai pesi delle due competizioni, ha decretato l'afferma- 
zione finale del piccolo appartenente alla scuderia di 
Daniele. 



IL TORNEO 'CLASSICO' 

A questo punto, i microbi, uniti ai 16 mini-robot perve- 
nuti, si sono affrontati per decidere il vincitore nella ca- 
tegoria del crobots 'storico'. Per dovere di cronaca va 
detto che questi classicbots poco 
hanno a che spartire con i 
combattenti scritti nell'epoca 
delle 1000 istruzioni effetti- 
ve. Molti di loro, anzi, so- 
no tranquillamente in gra- 
do di battere persino i 
macro robot del torneo 
2001. Qui la superiorità 
del microcampione è stata 
addirittura imbarazzante: 
bruenor.r ha dominato il 
primo girone, mentre 
regis.r si è comportato 
in maniera superlati- 
va anche in presenza 
di avversari più cor- 
pulenti, andando a 
vincere in solitudine 
il proprio round. La fi- 
nale è stata a senso uni- 
co, con Bruenor in grado di 
infliggere un distacco di ben 5 
punti percentuali a Enigma.r, di Ales- 
sandro Carlin (ancora lui!). 



Torneo 

CRobots 2k2 




http://www.itportal.it 



2 



3 ►►► 45 




Torneo 

CRobots 2k2 



Ó 



Spunti tecnici 

Archiviata la pra- 
tica del 2002 è 
iniziato il confronto 
semi-ufficiale teso a 
trovare i 32 robot più 
forti mai scritti, contro 
i quali allenare i propri 
sfidanti alla prossima 
competizione. Mentre 
scrivo il torneo è anco- 
ra in corso di svolgi- 
mento: potrete trova- 
re i risultati sul sito 
ww, itportal . it/crobots 

e su 

go.to/crobots 

Il 2002 termina con un 
verdetto meno con- 
traddittorio di quello 
fornito dalla passata 
edizione: si assiste, in- 
fatti, alla convergenza 
delle tattiche vincenti 
tra microbi, classici e 
macrorobot. 



IL TORNEO 2K2 

Finalmente si fa sul serio: i primi tre giorni di combat- 
timenti sono stati poco più che un prologo alla manife- 
stazione principale. La domanda aleggia nell'aria: riu- 
scirà qualcuno ad opporsi allo strapotere Nuzziano? 
La fase eliminatoria incorona vincitori Drizzt.r (Danie- 
le Nuzzo), Yerba.r e MoveOn.r (di Michelangelo Messi- 
na). Quest'ultimo si è così confermato il dominatore 
delle qualifiche: oramai da anni non perde un colpo! 
Fermo restando che i primi otto qualificati di ogni 
round hanno passato direttamente il turno, i piazzati 
dal nono al sedicesimo posto hanno poi dato vita al ri- 
pescaggio, che ha fornito i nomi degli 8 robot mancan- 
ti alla lista dei 32 finalisti. Finalmente, può prendere il 
via lo scontro decisivo. Scontata l'affermazione neir/2/ 
di Wulfgar, con uno stratosferico 84%. I migliori tra gli 
altri, Zorn.r, Drizzt.r e Obelix.r si fermano intorno al 
74%. Inizia l'ultima battaglia. Drizzi si porta subito al 
comando e, durante il primo 10% del torneo è abbon- 
dantemente avanti a tutti, arrivando ad accumulare un 
vantaggio intorno al 2% su Zorn. È praticamente cam- 
pione. Ma a questo punto succede l'incredibile: Zorn 
inizia una lenta ma costante risalita. Al 25% è dietro so- 



Pos. 


Nome 
del Crobot 


Eff . 4vs4 


Eff. f2f 


Eff. Totale 


1 


Zorn 


43,79 


73,16 


48,69 


2 


Drizzt 


41,50 


74,48 


47,00 


3 


Rudolf_7 


41,51 


64,65 


45,37 


4 


Wulfgar 


38,15 


80,57 


45,22 


5 


Bruenor 


36,93 


67,23 


41,98 


6 


Yerba 


36,35 


64,58 


41,06 


7 


MoveOn 


35,27 


61,50 


39,64 


8 


Regis 


31,52 


56,80 


35,73 


9 


Enigma 


29,46 


60,34 


34,61 


10 


TheSlayer 


29,35 


53,71 


33,41 


11 


Obelix 


24,35 


70,08 


31,97 


12 


Todos 


25,77 


51,10 


29,99 


13 


Asterix 


24,06 


59,45 


29,96 


14 


MedioMan 


24,19 


50,23 


28,53 


15 


Doom2099 


22,09 


58,58 


28,17 


16 


Tomahawk 


23,41 


48,83 


27,65 


17 


Pippo2a 


25,36 


35,20 


27,00 


18 


Jedi5 


21,03 


53,26 


26,40 


19 


Padawan 


15,84 


53,35 


22,09 


20 


Tigre 


19,28 


34,91 


21,89 


21 


Mind 


16,05 


49,36 


21,60 


22 


Remus 


16,09 


48,35 


21,47 


23 


Colosseum 


19,37 


30,87 


21,29 


24 


Idefix 


19,10 


28,91 


20,74 


25 


Ska 


15,06 


39,10 


19,07 


26 


Supernov 


19,30 


17,38 


18,98 


27 


Stanlio 


16,20 


24,77 


17,63 


28 


Mazinga 


14,12 


27,33 


16,32 


29 


Kyash_2 


7,56 


58,16 


15,99 


30 


Harpo 


14,14 


22,63 


15,56 


31 


Romulus 


11,13 


32,71 


14,73 


32 


Dynamite 


7,00 


23,69 


9,78 



Tab. 1: La classifica del torneo 2K2. 



lo di un quarto di punto. Al 30% è davanti, seppur di 
poco. Dal 40% in avanti il vantaggio si stabilizza intor- 
no al 2%. E siamo, infine al 100%. Il calcolo combinato 
delle efficienze decreta che il campione sia, ancora una 
volta, e per la seconda volta consecutiva, Alessandro 
Carlin (che si aggiudica in questo modo la microcame- 
ra messa in palio dalla Logitech). 
Secondo complessivo è Drizzt, che però, nel solo 4vs4, 
subisce l'onta di essere superato anche da Rudolf?, en- 
nesimo esponente della numerosa famiglia di Alessan- 
dro. Anche quest'anno impressionanti sono state le 
performance mostrate dai microrobot nella competi- 
zione generale. Daniele trova una parziale consolazio- 
ne piazzando regis.r all'ottavo posto complessivo, mi- 
gliore tra gli under 500, e bruenor. r al quinto, primo tra 
gli under 1000. Ma lasciamo ora la parola al campione 
2002, che, per inciso, strappa a Daniele anche un altro 
primato: da quest'anno, infatti, i bicampioni sono ben 
due. 

"Innanzitutto devo dire che sono molto soddisfatto per il 
successo che ancora una volta ha avuto il torneo e per la 
sorprendente partecipazione di un congruo numero di 
matricole che si è unito ai tanti veterani e ad alcuni gra- 
diti ritorni. Un torneo (seguito in diretta su internet gra- 
zie all' eff icenza di Simone) che anche quest'anno si è ri- 
velato com-battutissimo e incerto e nel quale non sono 
mancate le sorprese. 

Ad esempio sono rimasto stupito per la notevole per- 
formance della matricola Theslayer che, all'esordio, si 
piazza nella top ten con un codice molto originale e sem- 
plice, e dalla straordinaria efficienza di molti robots di 
piccola taglia capaci di dimostrarsi competitivi con av- 
versari di taglia superiore (primo su tutti Regis), a di- 
mostrazione del fatto che i margini di miglioramento ga- 
rantiti dalle 2000 istruzioni sono ancora in gran parte da 
sfruttare. Venendo a Zorn direi che il suo movimento ba- 
se si può descrivere come una fortunata fusione di Fizban 
e Rudolf _6 che ottimamente si erano comportati l'anno 
scorso. Infatti il movimento a "quadrato" del primo è 
stato trasformato in un rettangolo che, di volta in volta, 
porta Zorn ad avvicinarsi, e quindi ad attaccare, uno dei 
robots più vicini. Per quanto riguarda gli scontri 1 con- 
tro 1, si tratta di un upgrade della stessa routine di Ru- 
dolf _6 con un movimento oscillatorio al centro dell'are- 
na, che in Zorn è però unito ad un movimento rettilineo 
Nord-Sud. 

Questa scelta è stata dettata dalla complementarietà del- 
le due soluzioni: a seconda della situazione Zorn utilizza 
una routine o l'altra cercando di adattarsi all'avversario 
che ha di fronte. Un importante aiuto mi è stato dato dal 
debugger, novità del 2002, che permette di ottimizzare le 
temporizzazioni del robot. Sono così riuscito a evitare i 
tempi morti dovuti alla ricarica del cannone e a mante- 
nere sempre una velocità elevata nei cambi di direzione. 
Non mi rimane che dare appuntamento a tutti al torneo 
2003 ma prima ancora in MailingList per discutere e se- 
guire il torneo 91-2k2 tuttora in svolgimento/' 

Simone Ascheri 



46^^ F e b b 



http://www.itportal.it 



<<<<<<<<<<<<<<<<<<<<<<<< Sistema 



Ottimizzare 



PROGRAMMI DELPHI 




Ambienti di sviluppo sempre più 

complessi e computer di ultima 

generazione dalle prestazioni 

strabilianti sembrano aver reso 

inutile l'ottimizzazione del 

codice. Vediamo come, quando e 

perché non abbassare la guardia. 



Sono in molti a sostenere, non a sproposito, che 
T ottimizzazione sia un'arte. In effetti scrivere 
del "buon codice" significa anche sapere 
amalgamare capacità tecniche e creatività, senza di- 
menticare una generosa dose di passione. 
Il know-how necessario per ottimizzare, in modo 
adeguato, un programma risulta spesso fuori dalla 
portata del programmatore alle prime armi. E' ne- 
cessario infatti conoscere a fondo: le caratteristiche 
dell' architettura hardware, del sistema operativo, 
del compilatore e del linguaggio di programmazio- 
ne. 

In questo articolo, rivolto principalmente a pro- 
grammatori che si avvicinano per la prima volta al- 
l'argomento, analizzeremo metodi, strumenti e 
trucchi utilizzabili per aumentare Y efficienza del 
codice prodotto ed evitare gli errori più grossolani. 



CONTRO E PRO 

Può sembrare strano, ma non è facile giustificare Y ot- 
timizzazione, in quanto aumentare le prestazioni di 
un programma costa in termini di: 

• Tempo: cercare soluzioni migliori significa impie- 
gare del tempo prezioso, è perciò molto improba- 
bile che il codice ottimale si concili con il time-to- 
market; 

• Stabilità: i trucchi usati per raggiungere certe pre- 
stazioni possono minare il corretto funzionamen- 
to del programma; 

• Portabilità e manutenibilità: Y impiego di alcune 
ottimizzazioni lega il codice ad un numero relati- 
vamente ristretto di architetture e/o compilatori. 
Inoltre, in assenza di commenti si rischia di otte- 
nere "spaghetti code", ossia sorgenti intricati, po- 
co comprensibili e difficilmente mantenibili. 



A volte però il conseguimento di prestazioni eleva- 
te rientra tra i requisiti del progetto ed in ogni caso 
T efficienza è una discriminante non indifferente: 
uno dei fattori chiave nella scelta di un programma 
rispetto ad un altro similare. Considerate poi che 
nei dispositivi mobili, di strategica importanza per 
il futuro, le risorse sono limitate e la razionalizza- 
zione del software diventa una necessità imprescin- 
dibile. 

La "qualità del codice" è direttamente proporziona- 
le air esperienza del programmatore, la conoscenza 
delle tecniche di ottimizzazione rappresenta dun- 
que un influente biglietto da visita. 
Nel prosieguo dell' articolo verranno illustrate le re- 
gole più semplici e generali per ridurre la dimen- 
sione dell'eseguibile, dello spazio occupato in me- 
moria e dei tempi di calcolo. 



DA DOVE PARTIRE 

In generale per ottimizzare un programma è necessa- 
rio operare (almeno) a due livelli di astrazione: 

• Livello algoritmo/strutture dati: lo studio della 
complessità computazionale fornisce una misura 
oggettiva della "bontà" di un algoritmo e aiuta il 
programmatore nella scelta del metodo più ido- 
neo alla risoluzione di un problema. E' bene non 
dimenticare che ogni struttura dati ha delle pecu- 
liarità che potrebbero viziare in maniera determi- 
nante le prestazioni; 

• Livello implementazione: solo dopo aver esami- 
nato in modo esaustivo il livello precedente si 
può pensare di "mettere mano al codice" e cerca- 
re i costrutti, le funzioni di libreria ed i trucchi del 
mestiere che garantiscono la maggiore efficienza. 

Entrambi i livelli prevedono una casistica stermina- 
ta e come spesso accade i punti di vista sono i più 
disparati, in alcuni casi nettamente contrapposti, mi 
limiterò dunque a fornire tecniche applicabili in ge- 
nerale. 

Per motivi di spazio trascureremo argomenti im- 
portanti come la programmazione parallela (multi- 
threading, presenza di GPU, ...) e Fuso delle pro- 
prietà dei dispositivi hardware (branch prediction, 
pipelining, vincoli di accesso alla memoria cache, 
...). Spero che una volta letto l'articolo termini qua- 
li profiler e memory leak risultino meno astrusi. 



Sistema 



File sul CD 

\soft\codice 
\Ottimizzazione Delphi\ 



Eseguibili 

r& Per ottenere ese- 
<J guibili dalle di- 
mensioni ridotte biso- 
gna rinunciare alla VCL 
e scrivere programmi 
procedurali basati sulla 
API di Windows. In al- 
ternativa si pud utiliz- 
zare la libreria open- 
source KOL/MCK prele- 
vabile da 
http://xcl.cjb.net 
Sul CD è presente 1/7- 
AndOut, un programma 
di soli 6K in grado di 
posizionarsi nella tray- 
bar ed aprire/chiudere 
il lettore CD-ROM. 



http://www.itportal.it 



3 ►►► 47 




Sistema 



Ottimizzare 

Programmi Delphi 



Assert 

r& Durante la fase di 
^-J debugging/otti- 
mizzazione di un algo- 
ritmo è possibile ricor- 
rere alle asserzioni. La 
procedura Assert, de- 
scritta nella documen- 
tazione di Delphi, valuta 
un'espressione boolea- 
na e nel caso in cui ri- 
sulti falsa genera un'ec- 
cezione di tipo EAs- 
sertionFailed. Con As- 
sert si possono scovare 
con maggiore facilità 
bug subdoli: usatela 
senza parsimonia in fa- 
se di sviluppo! 



EFFICIENZA TEMPORALE 

Anche se i programmatori Delphi fanno ampio ricor- 
so a componenti scritti da terze parti, prima o poi sor- 
ge, per chiunque, l'esigenza di scontrarsi con l'imple- 
mentazione di routine a "basso livello". 



ories/Conditionals 
Forms Application 



Version Info Packages 

Compiler Linker 



e jeneration 

|7 Optimization 

f Stack frames 

r Pentium-safe FDIV 

[g 7T Record field alignmenf 



- Runtime errors 

f Flange checking 

\7 I/O checking 

I - verflow checking 



;•: options 

W Strict var-strings 

\~ Complete boolean eval 

Exfended syritan 

Typed @ operator 
(7 Opengarameters 

Hugestrings 

Assignable typed constanti: 



DeLiuyyiriy 


r~ Debug information 


I - Locai symbols 


I - Re|erence info 


(? Definifions onli; 


lAsseitioni: 


r Use Debug DCUs 



- Messages 

|7 Show hinfs 
\7 Showwi 



p Default 



Fig. 1 Queste impostazioni "suggeriscono" al 
compilatore di ottimizzare al meglio il codice. 



Come tutti i compilatori moderni Delphi prevede 
una lunga serie di ottimizzazioni automatiche (Fig. 
1), vedremo come aiutarlo nel produrre codice per- 
f ormante (Fig. 2). 



-° 
















f( 


"V 








y 


cq 


(n) 




^^ 





















Fig. 2: Con OllyDbg i curiosi possono studiare il 
codice prodotto dai compilatori. Nell'immagine un 
ciclo FOR. 

Tra le ottimizzazioni automatiche troviamo: 

• Eliminazione del codice: il compilatore scarta 
tutte le istruzioni inutili o comunque non rag- 
giungibili. Le istruzioni considerate utili vengono 
marcate con un pallino dopo la compilazione, le 
altre sono completamente ignorate. Per esempio 
nessuna delle istruzioni della procedura seguente 
comparirà nell'eseguibile: 



Proced 


lire Contengo, 


_Solo_ 


_Codice_ 


.Inutile; 


var i,k 


Integer; 








const e 


= 0; 








begin 



if e = 


1 then for i: = 


= 1 to 100 do k: = k+l 
// Istruzione 


nutile 


(c= 


= 0) 


i:=0; 


// Istruzione 


inutile 












k:=0 


// Istruzione 


inutile 












end; 



• Variabili nei registri: esaminando il "tempo di vi- 
ta" delle variabili Delphi è in grado di memoriz- 
zare, senza bisogno di direttive esplicite, le varia- 
bili nei registri della CPU. In questo modo vengo- 
no drasticamente ridotti i tempi di accesso ed il 
numero di istruzioni necessarie. Per sfruttare al 
massimo i registri conviene dichiarare variabili 
locali e progettare procedure o funzioni con un 
numero minimo di parametri. 

• Gestione avanzata dello stack: scrivere funzioni 
con al massimo tre parametri evita inoltre la crea- 
zione di uno stack frame. Le procedure annidate, 
note anche come procedure locali, hanno un impat- 
to negativo sulle prestazioni per via della gestio- 
ne dello stack: meglio farne a meno. 

// TODO: mai assegnare un progetto ad un 

programmatore che scrive cose del genere! 

Procedure Scarse_Prestazioni (var V:array of char; 

K:integer; var C: char; var R: Real); 

var i: Integer; 

Function Non_Dovrei_Essere_Qui (A,B,C: Integer; 

X,Y,Z: Real) : Real; 

begin 

Non_Dovrei_Essere_Qui : = (A+B+C)/(X+Y+Z); 
end; 

begin 

For i:= 1 TO K DO 

V[i]:=C; 

R:=Random; 

end; 

• Variabili loop induction: eliminazione delle com- 
mon subexpression, loop unrolling, function Mining, 
etc. Per avere una descrizione dettagliata, corre- 
data da esempi, delle tecniche elencate fate riferi- 
mento al box Sul Web. 

Se volete migliorare le vostre applicazioni con il mi- 
nimo sforzo tenete in considerazione che: 

• E' bene ridurre il numero di finestre create auto- 
maticamente: oltre a rallentare la fase di avvio 
consumano molta memoria. Nel pannello Forms 
delle opzioni di progetto (Fig. 3) è opportuno spo- 
stare, compatibilmente con le esigenze del pro- 
gramma, le form non necessarie nella lista Availa- 
ble Forms. Queste ultime, per non incorrere in vio- 
lazioni di accesso o sprechi di memoria, verranno 
create e distrutte dinamicamente solo al momen- 
to del bisogno: 



48 ►►► F e b b 



http: //www. itportal.it 



procedure TM 


iaFinestra.CreaDinamicamente; 


var 


Mia Finestra: 


TMiaForm; 




begin 


MiaFinestra 


:= TMiaForm 


.Create(Application); 


try 


MiaFinestra. ShowModal; 


// Mostra la finestra modale 


finally 


MiaFinestra. Free; // Libera le risorse 


end; 


end; 




Fig. 3: Le risorse vanno allocate solo quando 
servono, gli utenti vi ringrazieranno! 



I parametri di tipo strutturato o stringa che non 
vengono modificati all'interno di una procedura 
/funzione dovrebbero sempre essere preceduti 
dalla parola chiave const, come dimostra l'esem- 
pio incluso sul CD, Y incremento delle prestazioni 
è ragguardevole. Un discorso analogo vale per gli 
array dinamici o aperti; 

//Notate la presenza della parola chiave const! 

function Scansione_Stringa(const s: string; const e: 

char): integer; 

var 

i: integer; 

begin 

Result := 0; 

// Esamina la stringa s 

for i := 1 to Length(s) do begin 

// Alla prima occorrenza del carattere e esce dal loop 

if s[i] = e then begin 

Result := i; 

break; 

end; 

end; 

end; 

Le istruzioni di controllo del flusso abort, break, 
continue e exit, nonostante contribuiscano al peg- 
gioramento dello stile di programmazione, posso- 



no tornare utili per ottimizzare un algoritmo; 

È importante scegliere oculatamente la migliore 
combinazione tra prestazioni e precisione quando 
si opera con tipi reali. Come regola generale si do- 
vrebbe evitare l'utilizzo di tipi reali differenti nel- 
la stessa istruzione. L'esperienza dimostra che, se 
possibile, conviene usare Round al posto di Trunc; 

Per dare una mano al compilatore le selezioni 
vanno organizzate in maniera intelligente: date la 
priorità alla condizione più probabile, non di- 
menticate l'esistenza del costrutto case e raggrup- 
pate i rami del case per valori vicini; 

Le operazioni di I/O compiute su dati residenti in 
memorie di massa devono essere gestite attraver- 
so buffer al fine di minimizzare gli accessi. Una 
soluzione "sporca" consiste nel caricamento inte- 
grale del file in memoria centrale: 

Procedure Copia_File (const Sorgente,Destinazione:Sthng); 

var 

MioFile2: TMemoryStream; 

Buffer: String; 

MioFilel:TFileStream; 

begin 

MioFilel : = TFileStream.Create(Sorgente, 

fmOpenRead); // Apre il file sorgente 

try 

MioFilel .Seek(0, soFromBeginning); 

MioFile2 := TMemoryStream.Create; 

try 

MioFile2.CopyFrom(MioFilel, 0); 

// Letture e scritture avvengono direttamente 

nella RAM 

MioFile2.Read(Buffer, SizeOf( Buffer)); 

MioFile2.Write(Buffer, SizeOf(Buffer)); 

// Per programmi non "didattici" si può usare il 

metodo LoadFromFile 

finally 

MioFile2.SaveToFile(Destinazione); // Salva il file 

su disco 

MioFile2.Free; 

end; 

finally 

MioFilel.Free; 

end; 

end; 

Quando le prestazioni sono davvero importanti si 
possono realizzare routine in linguaggio Assem- 
bly ed integrarle nell'applicazione oppure accon- 
tentarsi dell' inline assembler. Non è però sempre 
vero che routine scritte in Assembly risultino più 
veloci di quelle implementate in Object Pascal, a 
meno che non sia assolutamente indispensabile 
state alla larga dalle complicazioni della program- 
mazione a basso livello. 




Sistema 



Ottimizzare 

Programmi Delphi 



Bottleneck 

y-S Letteralmente 
-■J colli di bottiglia, 
rappresentano le por- 
zioni di codice che ri- 
chiedono la maggiore 
quantità di risorse di 
calcolo. È fondamenta- 
le concentrare i nostri 
sforzi sull'eliminazio- 
ne, anche solo parziale, 
dei colli di bottiglia. 



http://www.itportal.it 



3 ►►► 49 



m 




Sistema 



Ottimizzare 

Programmi Delphi 



VCL 

y-S La Visual Compo- 
^J nent Library è la 
vera responsabile delle 
dimensioni, non di rado 
spropositate, degli ese- 
guibili. Grazie alle chia- 
mate di sistema e a li- 
brerie come la KOL è 
possibile ottenere pro- 
grammi funzionali a 
partire da 5K. 



Ovviamente non ha senso ottimizzare ogni singola li- 
nea di codice, ecco perché sono disponibili degli stru- 
menti che misurano i tempi di esecuzione e fornisco- 
no statistiche dettagliate sui colli di bottiglia: i prof iter. 
Oltre ai numerosi prodotti commerciali esistono an- 
che soluzioni open-source, per i nostri scopi adottere- 
mo il profiler GpProfile. Il funzionamento di base è 
molto semplice: GpProfile inserisce delle istruzioni nel 
vostro progetto, genera un file contenente il resocon- 
to delle misurazioni e al termine dell'esecuzione lo 
interpreta. I passi da compiere sono essenzialmente 
quelli riportati di seguito: 

1) Aggiungiamo GpProfile al menu Tools dell'am- 
biente Delphi; 

2) Dopo aver fatto una copia di sicurezza del pro- 
getto dobbiamo "instrumentare" il codice con la 
combinazione di tasti Ctrl+I; 

3) A questo punto è sufficiente scegliere le routine 
da sottoporre al cronometraggio, eseguire il pro- 
gramma ed analizzare i risultati presentati da Gp- 
Profile (Fig. 4); 




Fig. 4: L'output di GpProfile al termine dell'analisi, 
non ignorate le percentuali! 



4) Non dimentichiamo di eliminare le istruzioni in- 
serite dal profiler al punto 2 premendo contem- 
poraneamente Ctrl e F2. 

A questo punto possiamo ricavare delle informazioni 
preziose sulle porzioni di codice che più di altre con- 
tribuiscono al degrado delle prestazioni e quindi ri- 
chiedono un'implementazione ottimizzata. 



Package: i package sono normali librerie condivi- 
se DLL caratterizzate però dall'estensione bpl. 
Compilando un progetto con l'opzione Build with 
runtime packages otteniamo un eseguibile dalle di- 
mensioni minime. 

Lo svantaggio principale è che bisogna distribui- 
re anche le librerie impiegate, di conseguenza i 
package sono realmente utili solo quando vengo- 
no condivisi da diversi progetti. Se i package stan- 
dard venissero forniti con le varie versioni di 
Windows, gli eseguibili prodotti da Delphi non 
avrebbero nulla da invidiare a quelli di altri com- 
pilatori; 

Compressori: se per voi è importante il numero 
di byte occupati su disco dal programma allora la 
soluzione migliore è rappresentata dai compres- 
sori di eseguibili. Sul mercato ne troviamo per 
tutti i gusti, tra i più gettonati segnaliamo l' open- 
source UPX. L'unico problema dei compressori ri- 
siede nella gestione della memoria: i programmi 
compressi generalmente non sfruttano l'alloca- 
zione ori demand ma vengono decompressi com- 
pletamente nella RAM. Una strada alternativa è 
rappresentata dalle utility che rimuovono le se- 
zioni superflue, sul CD allegato alla rivista trova- 
te StripReloc; 

Razionalizzazione delle risorse: l'eseguibile do- 
vrebbe contenere solo le risorse essenziali, even- 
tuali risorse condivise vanno inserite in DLL ap- 
positamente create. È buona norma diminuire il 
numero di colori delle immagini, quasi sempre ne 
sono sufficienti 256, e caricarle manualmente sen- 
za impiegare le scorciatoie messe a disposizione 
dall'IDE; 

Clausole unit: per agevolare lo smart-linking non 
dovremmo includere unit inutili, inoltre a meno 
che non ci siano dipendenze mutue, la loro di- 
chiarazione deve avvenire nella uses della sezione 
implementation e non in quella della sezione inter- 
face-, 

Componenti invisibili: non cedete alla tentazio- 
ne di effettuare il drag & drop di componenti non 
visibili in fase di progettazione, l'esiguo rispar- 
mio di tempo può appesantire l'eseguibile: di- 
chiarateli manualmente nel sorgente; 



EFFICIENZA SPAZIALE 

Se il nostro obiettivo è ridurre lo spazio occupato, sia 
in fase di esecuzione sia in termini di dimensioni del- 
l'eseguibile, possiamo utilizzare una serie di metodi 
più o meno immediati. Distinguiamo innanzitutto le 
ottimizzazioni delle dimensioni da quelle relative al- 
l'occupazione della memoria. 
Per le prime possiamo affidarci a: 



• API di Windows: siete cresciuti all'ombra della 
VCL? La Visual Component Library è la vera re- 
sponsabile delle dimensioni, non di rado spropo- 
sitate, degli eseguibili. Grazie alle chiamate di si- 
stema e a librerie come la KOL è possibile ottene- 
re programmi funzionali a partire da 5K. 

Il risparmio di memoria durante l'esecuzione è otte- 
nibile applicando le regole dettate dal buonsenso: 



50*^> F e b b 



http: //www. itportal.it 



m 



Complessità 

L'efficienza di un programma può essere caratte- 
rizzata dai tempi di esecuzione (efficienza tempo- 
rale) e/o dalla memoria impiegata (efficienza 
spaziale). È possibile ottenere una misura dell'ef- 
ficienza indipendente dalle architetture hardware 
e software, analizzando la complessità temporale 
e quella spaziale di un algoritmo. Esistono molte- 
plici notazioni ideate per determinare se un algo- 
ritmo è più veloce/lento di un altro, tra le più co- 
muni possiamo annoverare le notazioni asintoti- 
che: O, 0, Q. 

O GRANDE: 

Scrivendo f(n) EO(g(n)) si intende che f(n) è de- 
finitivamente maggiorata da g(n). In altre parole 
esistono un valore k dell'ingresso ed una costan- 
te positiva e tali che: <r f(n) * cg(n) per ogni n 
> k. È importante notare che per valori di n mino- 
ri di k potrebbe 
accadere che 
f(n) sia mag- 
giore di cg (n), 
a partire da k 
risulta però cg 
(n)zf(n)! 

Nella figura a lato k vale 1. 



OMEGA GRANDE: 

Scrivendo f(n) E Q (g(n)) si intende che g (n) è 

definitivamen- 
te maggiorata 
da f(n), ovve- 
ro: 3c f k > ta- 
li che £ 
cg(n) £ f(n) 
per ogni n > k. 



20 










/ 


10 






cg| 


ny 










fi 


n) 


















2 3 4 



f(nl 



cfl(n) 



5i 










4 c 


:2g(r 


y 








/ 




f(n) 






/ ^ 














d g 


(n) 


2 4 


8 10 



THETA GRANDE: 

Scrivendo f(n) E0(g(n)) si intende che, a partire da 
n>k, f(n) è compresa tra ci g(n) e c2 g(n) dove ci 

e c2 sono due 
costanti molti- 
plicative positi- 
ve, cioè: 3 k,cl 
,c2 tali che clg 
(n) * f(n) * 
c2g(n) per 

ogni n > k. 

Di solito si valuta la complessità computazionale di 
un algoritmo facendo riferimento alla notazione O 
grande. Vediamo un piccolo esempio: vogliamo ordi- 
nare 1000 elementi (n=1000) e dobbiamo scegliere 
tra un algoritmo Bubble-Sort ed uno Quick-Sort. Do- 
po "ore" spese in considerazioni formali determinia- 
mo che il primo ha, in generale, una complessità 
0(n*2) quindi risulta O(l.OOO.OOO), il secondo ha un 
caso medio che "costa" solo 0(n log n) e dunque 
O(10.000). Un bel risparmio di tempo! Se vi è venuta 
voglia di approfondire l'argomento vi consiglio di 
consultare un qualsiasi testo accademico di informa- 
tica di base. 



mente necessarie. Le altre verranno create e di- 
strutte via codice; 

• Rinunciamo ai fronzoli e agli abbellimenti grafici 
eccessivi concentrando Y attenzione sulle caratte- 
ristiche fondamentali; 

• Impieghiamo al meglio la gestione delle eccezio- 
ni, in particolare i blocchi try. . .finally. 

L'ultimo passo consiste nel verificare la presenza 
dei temuti memory leaks, ovvero di sprechi di me- 
moria dovuti a errori di allocazione e deallocazio- 
ne. Per fortuna esistono delle suite di strumenti, 
più o meno sofisticate e costose, che svolgono gran 
parte del lavoro al posto nostro. Memproof è un tool 
gratuito che ci permette di scovare i bug più sub- 
doli: gli sprechi di memoria. Gli eseguibili proces- 
sati da Memproof devono essere compilati con le 
informazioni di debug, si faccia riferimento alla se- 
zione Linker delle opzioni di progetto oppure allo 
switch -v del compilatore da linea di comando. 




Non creiamo automaticamente tutte le form pre- 
viste dall' applicazione, ma solo quelle stretta- 



Fig. 5: MemProof segnala eventuali sprechi di 
memoria (ed altri errori comuni). 



Dopo aver caricato l'eseguibile da testare in Mem- 
Proof si avvia l'analisi con il tasto ¥9, ad analisi ter- 
minata si ha un resoconto approfondito con tanto 
di descrizione del problema (Fig. 5). 



CONCLUSIONI 

Nello spazio che mi è concesso ho tentato di mette- 
re molta carne sul fuoco in modo da stuzzicare la 
vostra curiosità. L'ottimizzazione è un argomento 
interessante ma al tempo stesso tra i più complessi, 
spero di avervi invogliato a testare i vostri pro- 
grammi con gli strumenti descritti, potreste avere 
delle sorprese! La programmazione parallela, l'otti- 
mizzazione degli applicativi database e client/ ser- 
ver, il nuovo Delphi 7 ed il futuro Delphi .NET me- 
riterebbero intere serie di articoli... 
È per questo che vi consiglio di non perdere i pros- 
simi numeri! 

Salvatore Meschini 




Sistema 



Ottimizzare 

Programmi Delphi 



Complessità 

j-& Nella tabella di 
^J fianco troviamo 
una breve disamina 
sulla complessità e sul- 
la misura dell'efficien- 
za. 



http://www.itportal.it 



3 ►►► 51 



<<<<<<<<<<<<<<<<<<<<<<<< Sistema 



Ottimizzare 



PROGRAMMI DELPHI 




Ambienti di sviluppo sempre più 

complessi e computer di ultima 

generazione dalle prestazioni 

strabilianti sembrano aver reso 

inutile l'ottimizzazione del 

codice. Vediamo come, quando e 

perché non abbassare la guardia. 



Sono in molti a sostenere, non a sproposito, che 
T ottimizzazione sia un'arte. In effetti scrivere 
del "buon codice" significa anche sapere 
amalgamare capacità tecniche e creatività, senza di- 
menticare una generosa dose di passione. 
Il know-how necessario per ottimizzare, in modo 
adeguato, un programma risulta spesso fuori dalla 
portata del programmatore alle prime armi. E' ne- 
cessario infatti conoscere a fondo: le caratteristiche 
dell' architettura hardware, del sistema operativo, 
del compilatore e del linguaggio di programmazio- 
ne. 

In questo articolo, rivolto principalmente a pro- 
grammatori che si avvicinano per la prima volta al- 
l'argomento, analizzeremo metodi, strumenti e 
trucchi utilizzabili per aumentare Y efficienza del 
codice prodotto ed evitare gli errori più grossolani. 



CONTRO E PRO 

Può sembrare strano, ma non è facile giustificare Y ot- 
timizzazione, in quanto aumentare le prestazioni di 
un programma costa in termini di: 

• Tempo: cercare soluzioni migliori significa impie- 
gare del tempo prezioso, è perciò molto improba- 
bile che il codice ottimale si concili con il time-to- 
market; 

• Stabilità: i trucchi usati per raggiungere certe pre- 
stazioni possono minare il corretto funzionamen- 
to del programma; 

• Portabilità e manutenibilità: Y impiego di alcune 
ottimizzazioni lega il codice ad un numero relati- 
vamente ristretto di architetture e/o compilatori. 
Inoltre, in assenza di commenti si rischia di otte- 
nere "spaghetti code", ossia sorgenti intricati, po- 
co comprensibili e difficilmente mantenibili. 



A volte però il conseguimento di prestazioni eleva- 
te rientra tra i requisiti del progetto ed in ogni caso 
T efficienza è una discriminante non indifferente: 
uno dei fattori chiave nella scelta di un programma 
rispetto ad un altro similare. Considerate poi che 
nei dispositivi mobili, di strategica importanza per 
il futuro, le risorse sono limitate e la razionalizza- 
zione del software diventa una necessità imprescin- 
dibile. 

La "qualità del codice" è direttamente proporziona- 
le air esperienza del programmatore, la conoscenza 
delle tecniche di ottimizzazione rappresenta dun- 
que un influente biglietto da visita. 
Nel prosieguo dell' articolo verranno illustrate le re- 
gole più semplici e generali per ridurre la dimen- 
sione dell'eseguibile, dello spazio occupato in me- 
moria e dei tempi di calcolo. 



DA DOVE PARTIRE 

In generale per ottimizzare un programma è necessa- 
rio operare (almeno) a due livelli di astrazione: 

• Livello algoritmo/strutture dati: lo studio della 
complessità computazionale fornisce una misura 
oggettiva della "bontà" di un algoritmo e aiuta il 
programmatore nella scelta del metodo più ido- 
neo alla risoluzione di un problema. E' bene non 
dimenticare che ogni struttura dati ha delle pecu- 
liarità che potrebbero viziare in maniera determi- 
nante le prestazioni; 

• Livello implementazione: solo dopo aver esami- 
nato in modo esaustivo il livello precedente si 
può pensare di "mettere mano al codice" e cerca- 
re i costrutti, le funzioni di libreria ed i trucchi del 
mestiere che garantiscono la maggiore efficienza. 

Entrambi i livelli prevedono una casistica stermina- 
ta e come spesso accade i punti di vista sono i più 
disparati, in alcuni casi nettamente contrapposti, mi 
limiterò dunque a fornire tecniche applicabili in ge- 
nerale. 

Per motivi di spazio trascureremo argomenti im- 
portanti come la programmazione parallela (multi- 
threading, presenza di GPU, ...) e Fuso delle pro- 
prietà dei dispositivi hardware (branch prediction, 
pipelining, vincoli di accesso alla memoria cache, 
...). Spero che una volta letto l'articolo termini qua- 
li profiler e memory leak risultino meno astrusi. 



Sistema 



File sul CD 

\soft\codice 
\Ottimizzazione Delphi\ 



Eseguibili 

r& Per ottenere ese- 
<J guibili dalle di- 
mensioni ridotte biso- 
gna rinunciare alla VCL 
e scrivere programmi 
procedurali basati sulla 
API di Windows. In al- 
ternativa si pud utiliz- 
zare la libreria open- 
source KOL/MCK prele- 
vabile da 
http://xcl.cjb.net 
Sul CD è presente 1/7- 
AndOut, un programma 
di soli 6K in grado di 
posizionarsi nella tray- 
bar ed aprire/chiudere 
il lettore CD-ROM. 



http://www.itportal.it 



3 ►►► 47 




Sistema 



Ottimizzare 

Programmi Delphi 



Assert 

r& Durante la fase di 
^-J debugging/otti- 
mizzazione di un algo- 
ritmo è possibile ricor- 
rere alle asserzioni. La 
procedura Assert, de- 
scritta nella documen- 
tazione di Delphi, valuta 
un'espressione boolea- 
na e nel caso in cui ri- 
sulti falsa genera un'ec- 
cezione di tipo EAs- 
sertionFailed. Con As- 
sert si possono scovare 
con maggiore facilità 
bug subdoli: usatela 
senza parsimonia in fa- 
se di sviluppo! 



EFFICIENZA TEMPORALE 

Anche se i programmatori Delphi fanno ampio ricor- 
so a componenti scritti da terze parti, prima o poi sor- 
ge, per chiunque, l'esigenza di scontrarsi con l'imple- 
mentazione di routine a "basso livello". 



ories/Conditionals 
Forms Application 



Version Info Packages 

Compiler Linker 



e jeneration 

|7 Optimization 

f Stack frames 

r Pentium-safe FDIV 

[g 7T Record field alignmenf 



- Runtime errors 

f Flange checking 

\7 I/O checking 

I - verflow checking 



;•: options 

W Strict var-strings 

\~ Complete boolean eval 

Exfended syritan 

Typed @ operator 
(7 Opengarameters 

Hugestrings 

Assignable typed constanti: 



DeLiuyyiriy 


r~ Debug information 


I - Locai symbols 


I - Re|erence info 


(? Definifions onli; 


lAsseitioni: 


r Use Debug DCUs 



- Messages 

|7 Show hinfs 
\7 Showwi 



p Default 



Fig. 1 Queste impostazioni "suggeriscono" al 
compilatore di ottimizzare al meglio il codice. 



Come tutti i compilatori moderni Delphi prevede 
una lunga serie di ottimizzazioni automatiche (Fig. 
1), vedremo come aiutarlo nel produrre codice per- 
f ormante (Fig. 2). 



-° 
















f( 


"V 








y 


cq 


(n) 




^^ 





















Fig. 2: Con OllyDbg i curiosi possono studiare il 
codice prodotto dai compilatori. Nell'immagine un 
ciclo FOR. 

Tra le ottimizzazioni automatiche troviamo: 

• Eliminazione del codice: il compilatore scarta 
tutte le istruzioni inutili o comunque non rag- 
giungibili. Le istruzioni considerate utili vengono 
marcate con un pallino dopo la compilazione, le 
altre sono completamente ignorate. Per esempio 
nessuna delle istruzioni della procedura seguente 
comparirà nell'eseguibile: 



Proced 


lire Contengo, 


_Solo_ 


_Codice_ 


.Inutile; 


var i,k 


Integer; 








const e 


= 0; 








begin 



if e = 


1 then for i: = 


= 1 to 100 do k: = k+l 
// Istruzione 


nutile 


(c= 


= 0) 


i:=0; 


// Istruzione 


inutile 












k:=0 


// Istruzione 


inutile 












end; 



• Variabili nei registri: esaminando il "tempo di vi- 
ta" delle variabili Delphi è in grado di memoriz- 
zare, senza bisogno di direttive esplicite, le varia- 
bili nei registri della CPU. In questo modo vengo- 
no drasticamente ridotti i tempi di accesso ed il 
numero di istruzioni necessarie. Per sfruttare al 
massimo i registri conviene dichiarare variabili 
locali e progettare procedure o funzioni con un 
numero minimo di parametri. 

• Gestione avanzata dello stack: scrivere funzioni 
con al massimo tre parametri evita inoltre la crea- 
zione di uno stack frame. Le procedure annidate, 
note anche come procedure locali, hanno un impat- 
to negativo sulle prestazioni per via della gestio- 
ne dello stack: meglio farne a meno. 

// TODO: mai assegnare un progetto ad un 

programmatore che scrive cose del genere! 

Procedure Scarse_Prestazioni (var V:array of char; 

K:integer; var C: char; var R: Real); 

var i: Integer; 

Function Non_Dovrei_Essere_Qui (A,B,C: Integer; 

X,Y,Z: Real) : Real; 

begin 

Non_Dovrei_Essere_Qui : = (A+B+C)/(X+Y+Z); 
end; 

begin 

For i:= 1 TO K DO 

V[i]:=C; 

R:=Random; 

end; 

• Variabili loop induction: eliminazione delle com- 
mon subexpression, loop unrolling, function Mining, 
etc. Per avere una descrizione dettagliata, corre- 
data da esempi, delle tecniche elencate fate riferi- 
mento al box Sul Web. 

Se volete migliorare le vostre applicazioni con il mi- 
nimo sforzo tenete in considerazione che: 

• E' bene ridurre il numero di finestre create auto- 
maticamente: oltre a rallentare la fase di avvio 
consumano molta memoria. Nel pannello Forms 
delle opzioni di progetto (Fig. 3) è opportuno spo- 
stare, compatibilmente con le esigenze del pro- 
gramma, le form non necessarie nella lista Availa- 
ble Forms. Queste ultime, per non incorrere in vio- 
lazioni di accesso o sprechi di memoria, verranno 
create e distrutte dinamicamente solo al momen- 
to del bisogno: 



48 ►►► F e b b 



http: //www. itportal.it 



procedure TM 


iaFinestra.CreaDinamicamente; 


var 


Mia Finestra: 


TMiaForm; 




begin 


MiaFinestra 


:= TMiaForm 


.Create(Application); 


try 


MiaFinestra. ShowModal; 


// Mostra la finestra modale 


finally 


MiaFinestra. Free; // Libera le risorse 


end; 


end; 




Fig. 3: Le risorse vanno allocate solo quando 
servono, gli utenti vi ringrazieranno! 



I parametri di tipo strutturato o stringa che non 
vengono modificati all'interno di una procedura 
/funzione dovrebbero sempre essere preceduti 
dalla parola chiave const, come dimostra l'esem- 
pio incluso sul CD, Y incremento delle prestazioni 
è ragguardevole. Un discorso analogo vale per gli 
array dinamici o aperti; 

//Notate la presenza della parola chiave const! 

function Scansione_Stringa(const s: string; const e: 

char): integer; 

var 

i: integer; 

begin 

Result := 0; 

// Esamina la stringa s 

for i := 1 to Length(s) do begin 

// Alla prima occorrenza del carattere e esce dal loop 

if s[i] = e then begin 

Result := i; 

break; 

end; 

end; 

end; 

Le istruzioni di controllo del flusso abort, break, 
continue e exit, nonostante contribuiscano al peg- 
gioramento dello stile di programmazione, posso- 



no tornare utili per ottimizzare un algoritmo; 

È importante scegliere oculatamente la migliore 
combinazione tra prestazioni e precisione quando 
si opera con tipi reali. Come regola generale si do- 
vrebbe evitare l'utilizzo di tipi reali differenti nel- 
la stessa istruzione. L'esperienza dimostra che, se 
possibile, conviene usare Round al posto di Trunc; 

Per dare una mano al compilatore le selezioni 
vanno organizzate in maniera intelligente: date la 
priorità alla condizione più probabile, non di- 
menticate l'esistenza del costrutto case e raggrup- 
pate i rami del case per valori vicini; 

Le operazioni di I/O compiute su dati residenti in 
memorie di massa devono essere gestite attraver- 
so buffer al fine di minimizzare gli accessi. Una 
soluzione "sporca" consiste nel caricamento inte- 
grale del file in memoria centrale: 

Procedure Copia_File (const Sorgente,Destinazione:Sthng); 

var 

MioFile2: TMemoryStream; 

Buffer: String; 

MioFilel:TFileStream; 

begin 

MioFilel : = TFileStream.Create(Sorgente, 

fmOpenRead); // Apre il file sorgente 

try 

MioFilel .Seek(0, soFromBeginning); 

MioFile2 := TMemoryStream.Create; 

try 

MioFile2.CopyFrom(MioFilel, 0); 

// Letture e scritture avvengono direttamente 

nella RAM 

MioFile2.Read(Buffer, SizeOf( Buffer)); 

MioFile2.Write(Buffer, SizeOf(Buffer)); 

// Per programmi non "didattici" si può usare il 

metodo LoadFromFile 

finally 

MioFile2.SaveToFile(Destinazione); // Salva il file 

su disco 

MioFile2.Free; 

end; 

finally 

MioFilel.Free; 

end; 

end; 

Quando le prestazioni sono davvero importanti si 
possono realizzare routine in linguaggio Assem- 
bly ed integrarle nell'applicazione oppure accon- 
tentarsi dell' inline assembler. Non è però sempre 
vero che routine scritte in Assembly risultino più 
veloci di quelle implementate in Object Pascal, a 
meno che non sia assolutamente indispensabile 
state alla larga dalle complicazioni della program- 
mazione a basso livello. 




Sistema 



Ottimizzare 

Programmi Delphi 



Bottleneck 

y-S Letteralmente 
-■J colli di bottiglia, 
rappresentano le por- 
zioni di codice che ri- 
chiedono la maggiore 
quantità di risorse di 
calcolo. È fondamenta- 
le concentrare i nostri 
sforzi sull'eliminazio- 
ne, anche solo parziale, 
dei colli di bottiglia. 



http://www.itportal.it 



3 ►►► 49 



m 




Sistema 



Ottimizzare 

Programmi Delphi 



VCL 

y-S La Visual Compo- 
^J nent Library è la 
vera responsabile delle 
dimensioni, non di rado 
spropositate, degli ese- 
guibili. Grazie alle chia- 
mate di sistema e a li- 
brerie come la KOL è 
possibile ottenere pro- 
grammi funzionali a 
partire da 5K. 



Ovviamente non ha senso ottimizzare ogni singola li- 
nea di codice, ecco perché sono disponibili degli stru- 
menti che misurano i tempi di esecuzione e fornisco- 
no statistiche dettagliate sui colli di bottiglia: i prof iter. 
Oltre ai numerosi prodotti commerciali esistono an- 
che soluzioni open-source, per i nostri scopi adottere- 
mo il profiler GpProfile. Il funzionamento di base è 
molto semplice: GpProfile inserisce delle istruzioni nel 
vostro progetto, genera un file contenente il resocon- 
to delle misurazioni e al termine dell'esecuzione lo 
interpreta. I passi da compiere sono essenzialmente 
quelli riportati di seguito: 

1) Aggiungiamo GpProfile al menu Tools dell'am- 
biente Delphi; 

2) Dopo aver fatto una copia di sicurezza del pro- 
getto dobbiamo "instrumentare" il codice con la 
combinazione di tasti Ctrl+I; 

3) A questo punto è sufficiente scegliere le routine 
da sottoporre al cronometraggio, eseguire il pro- 
gramma ed analizzare i risultati presentati da Gp- 
Profile (Fig. 4); 




Fig. 4: L'output di GpProfile al termine dell'analisi, 
non ignorate le percentuali! 



4) Non dimentichiamo di eliminare le istruzioni in- 
serite dal profiler al punto 2 premendo contem- 
poraneamente Ctrl e F2. 

A questo punto possiamo ricavare delle informazioni 
preziose sulle porzioni di codice che più di altre con- 
tribuiscono al degrado delle prestazioni e quindi ri- 
chiedono un'implementazione ottimizzata. 



Package: i package sono normali librerie condivi- 
se DLL caratterizzate però dall'estensione bpl. 
Compilando un progetto con l'opzione Build with 
runtime packages otteniamo un eseguibile dalle di- 
mensioni minime. 

Lo svantaggio principale è che bisogna distribui- 
re anche le librerie impiegate, di conseguenza i 
package sono realmente utili solo quando vengo- 
no condivisi da diversi progetti. Se i package stan- 
dard venissero forniti con le varie versioni di 
Windows, gli eseguibili prodotti da Delphi non 
avrebbero nulla da invidiare a quelli di altri com- 
pilatori; 

Compressori: se per voi è importante il numero 
di byte occupati su disco dal programma allora la 
soluzione migliore è rappresentata dai compres- 
sori di eseguibili. Sul mercato ne troviamo per 
tutti i gusti, tra i più gettonati segnaliamo l' open- 
source UPX. L'unico problema dei compressori ri- 
siede nella gestione della memoria: i programmi 
compressi generalmente non sfruttano l'alloca- 
zione ori demand ma vengono decompressi com- 
pletamente nella RAM. Una strada alternativa è 
rappresentata dalle utility che rimuovono le se- 
zioni superflue, sul CD allegato alla rivista trova- 
te StripReloc; 

Razionalizzazione delle risorse: l'eseguibile do- 
vrebbe contenere solo le risorse essenziali, even- 
tuali risorse condivise vanno inserite in DLL ap- 
positamente create. È buona norma diminuire il 
numero di colori delle immagini, quasi sempre ne 
sono sufficienti 256, e caricarle manualmente sen- 
za impiegare le scorciatoie messe a disposizione 
dall'IDE; 

Clausole unit: per agevolare lo smart-linking non 
dovremmo includere unit inutili, inoltre a meno 
che non ci siano dipendenze mutue, la loro di- 
chiarazione deve avvenire nella uses della sezione 
implementation e non in quella della sezione inter- 
face-, 

Componenti invisibili: non cedete alla tentazio- 
ne di effettuare il drag & drop di componenti non 
visibili in fase di progettazione, l'esiguo rispar- 
mio di tempo può appesantire l'eseguibile: di- 
chiarateli manualmente nel sorgente; 



EFFICIENZA SPAZIALE 

Se il nostro obiettivo è ridurre lo spazio occupato, sia 
in fase di esecuzione sia in termini di dimensioni del- 
l'eseguibile, possiamo utilizzare una serie di metodi 
più o meno immediati. Distinguiamo innanzitutto le 
ottimizzazioni delle dimensioni da quelle relative al- 
l'occupazione della memoria. 
Per le prime possiamo affidarci a: 



• API di Windows: siete cresciuti all'ombra della 
VCL? La Visual Component Library è la vera re- 
sponsabile delle dimensioni, non di rado spropo- 
sitate, degli eseguibili. Grazie alle chiamate di si- 
stema e a librerie come la KOL è possibile ottene- 
re programmi funzionali a partire da 5K. 

Il risparmio di memoria durante l'esecuzione è otte- 
nibile applicando le regole dettate dal buonsenso: 



50*^> F e b b 



http: //www. itportal.it 



m 



Complessità 

L'efficienza di un programma può essere caratte- 
rizzata dai tempi di esecuzione (efficienza tempo- 
rale) e/o dalla memoria impiegata (efficienza 
spaziale). È possibile ottenere una misura dell'ef- 
ficienza indipendente dalle architetture hardware 
e software, analizzando la complessità temporale 
e quella spaziale di un algoritmo. Esistono molte- 
plici notazioni ideate per determinare se un algo- 
ritmo è più veloce/lento di un altro, tra le più co- 
muni possiamo annoverare le notazioni asintoti- 
che: O, 0, Q. 

O GRANDE: 

Scrivendo f(n) EO(g(n)) si intende che f(n) è de- 
finitivamente maggiorata da g(n). In altre parole 
esistono un valore k dell'ingresso ed una costan- 
te positiva e tali che: <r f(n) * cg(n) per ogni n 
> k. È importante notare che per valori di n mino- 
ri di k potrebbe 
accadere che 
f(n) sia mag- 
giore di cg (n), 
a partire da k 
risulta però cg 
(n)zf(n)! 

Nella figura a lato k vale 1. 



OMEGA GRANDE: 

Scrivendo f(n) E Q (g(n)) si intende che g (n) è 

definitivamen- 
te maggiorata 
da f(n), ovve- 
ro: 3c f k > ta- 
li che £ 
cg(n) £ f(n) 
per ogni n > k. 



20 










/ 


10 






cg| 


ny 










fi 


n) 


















2 3 4 



f(nl 



cfl(n) 



5i 










4 c 


:2g(r 


y 








/ 




f(n) 






/ ^ 














d g 


(n) 


2 4 


8 10 



THETA GRANDE: 

Scrivendo f(n) E0(g(n)) si intende che, a partire da 
n>k, f(n) è compresa tra ci g(n) e c2 g(n) dove ci 

e c2 sono due 
costanti molti- 
plicative positi- 
ve, cioè: 3 k,cl 
,c2 tali che clg 
(n) * f(n) * 
c2g(n) per 

ogni n > k. 

Di solito si valuta la complessità computazionale di 
un algoritmo facendo riferimento alla notazione O 
grande. Vediamo un piccolo esempio: vogliamo ordi- 
nare 1000 elementi (n=1000) e dobbiamo scegliere 
tra un algoritmo Bubble-Sort ed uno Quick-Sort. Do- 
po "ore" spese in considerazioni formali determinia- 
mo che il primo ha, in generale, una complessità 
0(n*2) quindi risulta O(l.OOO.OOO), il secondo ha un 
caso medio che "costa" solo 0(n log n) e dunque 
O(10.000). Un bel risparmio di tempo! Se vi è venuta 
voglia di approfondire l'argomento vi consiglio di 
consultare un qualsiasi testo accademico di informa- 
tica di base. 



mente necessarie. Le altre verranno create e di- 
strutte via codice; 

• Rinunciamo ai fronzoli e agli abbellimenti grafici 
eccessivi concentrando Y attenzione sulle caratte- 
ristiche fondamentali; 

• Impieghiamo al meglio la gestione delle eccezio- 
ni, in particolare i blocchi try. . .finally. 

L'ultimo passo consiste nel verificare la presenza 
dei temuti memory leaks, ovvero di sprechi di me- 
moria dovuti a errori di allocazione e deallocazio- 
ne. Per fortuna esistono delle suite di strumenti, 
più o meno sofisticate e costose, che svolgono gran 
parte del lavoro al posto nostro. Memproof è un tool 
gratuito che ci permette di scovare i bug più sub- 
doli: gli sprechi di memoria. Gli eseguibili proces- 
sati da Memproof devono essere compilati con le 
informazioni di debug, si faccia riferimento alla se- 
zione Linker delle opzioni di progetto oppure allo 
switch -v del compilatore da linea di comando. 




Non creiamo automaticamente tutte le form pre- 
viste dall' applicazione, ma solo quelle stretta- 



Fig. 5: MemProof segnala eventuali sprechi di 
memoria (ed altri errori comuni). 



Dopo aver caricato l'eseguibile da testare in Mem- 
Proof si avvia l'analisi con il tasto ¥9, ad analisi ter- 
minata si ha un resoconto approfondito con tanto 
di descrizione del problema (Fig. 5). 



CONCLUSIONI 

Nello spazio che mi è concesso ho tentato di mette- 
re molta carne sul fuoco in modo da stuzzicare la 
vostra curiosità. L'ottimizzazione è un argomento 
interessante ma al tempo stesso tra i più complessi, 
spero di avervi invogliato a testare i vostri pro- 
grammi con gli strumenti descritti, potreste avere 
delle sorprese! La programmazione parallela, l'otti- 
mizzazione degli applicativi database e client/ ser- 
ver, il nuovo Delphi 7 ed il futuro Delphi .NET me- 
riterebbero intere serie di articoli... 
È per questo che vi consiglio di non perdere i pros- 
simi numeri! 

Salvatore Meschini 




Sistema 



Ottimizzare 

Programmi Delphi 



Complessità 

j-& Nella tabella di 
^J fianco troviamo 
una breve disamina 
sulla complessità e sul- 
la misura dell'efficien- 
za. 



http://www.itportal.it 



3 ►►► 51 




LEGO 



Sul Web ET 

Sito ufficiale LEGO 

http://mindstorms.lego. 
com/enq/default.asp 

Lego Shop 

http://shop.lego.com 

Dave Baum's NQC 

http: //www, baumfamily. 
org/nqc/ 



LEGO 



MINDSTORMS ROBOTICS INVENTION 
SYSTEM 2.0 



Potrebbe, a prima vista, 

sembra un classico gioco Lego, 

in realtà nasconde una vera e 

propria meraviglia tecnologica, 

che unisce con estrema 

semplicità robotica, 

cibernetica e informatica. 



Il kit Lego Mindstorms consente di creare robot 
dotati di articolazioni, sensori ottici e tattili, ecc. 
utilizzando i mattoncini Lego e l'RCX, un micro- 
processore programmabile mediante un kit fornito 
dalla Lego, o tramite appositi SDK per Visual Basic, 
C++, ecc. 

Utilizzando il software incluso nel kit si può' scri- 
vere un programma in grado di far muovere i pic- 
coli robot in modo che possano evitare gli ostacoli, 
seguire un percorso o una fonte luminosa. Il kit 
(Fig.l) si compone di ben 718 pezzi. 
Tra questi troviamo: 

• Microcomputer RCX; 

• CD-ROM con software RCXCode (sviluppo vi- 
suale sul PC); 

• Constructopedia: una raccolta di istruzioni per 
costruire robot di esempio; 

• 3 Guided Challenges; 

• 6 Pro Challenges; 



1 1 

■ ■ 

1 1 





• Dispositivo di trasmissione ad infrarossi per la 
comunicazione tra PC e microcontroller RCX 

• 718 pezzi LEGO, (2 motori, 2 sensori di contatto, 
1 sensore di luminosità). 

In aggiunta, è possibile acquistare separatamente 
altri sensori e motori passo passo. In particolar mo- 
do sono disponibili sensori di temperatura, di pros- 
sima, di angolazione. 

Il progetto lo si deve ad un matematico del MIT 
(Massachusetts Institute of Technology), promotore,tra 
T altro, del LOGO, linguaggio di programmazione 
diffuso nelle scuole per far apprendere i concetti ba- 
se della programmazione ai più piccoli. 

IL CUORE 

DEL LEGO MINDSTORMS 

Il Lego Mindstorms funziona grazie alla presenza 
di una sorta di microcomputer capace di coordina- 
re i diversi pezzi che l'utente assembla. 
RCX, questo il nome del microcontroller a 8 bit, ap- 
positamente realizzato dalla Hitachi, che rappre- 
senta il cervello delle invenzioni di Lego MindStor- 
ms. 

Tale microcontroller può essere programmato gra- 
zie all'interfacciamento ad un comune PC; la con- 
nessione avviene meditante un'apposita porta ad 
infrarosso compresa nella confezione. 
Nel kit è altresì presente un CD-Rom contenente un 
linguaggio visuale per creare gli schemi di funzio- 
namento dell' RCX, il programma, molto semplice 
ed intuitivo da utilizzare, consente di creare com- 



Fig. 1: La scatola contenente i 718 pezzi del Lego 
Mindstorms. 




Fig. 2: Il cuore del Lego Mindstorms: l'RCX 



52 ►►► Febbraio 



2 3 



http://www.itportal.it 



plessi schemi di funzionamento, gestibile anche da 
un ragazzino di 12 anni poco pratico dei linguaggi 
di sviluppo. 

Tuttavia, esistono diversi SDK e kit di sviluppo (Le- 
go Mindstorms SDK, Bricx, NQC - Not Quite C) 
che permettono allo sviluppatore, più avanzato, di 
creare vere e proprie applicazioni in linguaggio C, 
Visual Basic; esistono, in giro per la Rete, anche kit 
di sviluppo Java, Delphi, C#. 



Requisiti tecnici minimi 

• Sistema operativo: Windows 98; 

• CPU: Pentium II 233 MHz; 

• RAM: 32 MB; 

• Spazio disco disponibile su hard disk: 115 MB; 

• Mouse: Windows compatibile; 

• Scheda: Sound Blaster 16 Windows compatibile; 

• CD-ROM: 8X; 

• Video display: 800 X 600 SVGA con 4 MB RAM, 
16 bit di colore. 



_} 

else if (EYE>=tooBright) 

J 

Off(RIGHT); 

On(LEFT); 

_} 

else 

J 

On(LEFT+RIGHT); 

} 



Santo Serra 



IL LINGUAGGIO C 
PER LO SVILUPPO 

Il listato che segue (NQC) mostra come realizzare 
una semplice applicazione in linguaggio; C si trat- 
ta di un'applicazione che consente, al robot mo- 
strato in Fig. 3, di seguire il tracciato di una riga ne- 
ra segnata su uno sfondo chiaro. 

#define EYE SENSOR_2 

#define LEFT OUT_A 

#define RIGHT OUT_C 

int tooDark; 

int tooBright; 

void SetupQ 

{ 

tooBright=EYE; 

PlaySound (SOUNDJJP); 

Wait (300); 

tooDark=EYE; 

int delta = (tooBright-tooDark)/3; 

tooDark+=delta; 

tooBright-=delta; 

} 

task main() 

{ 

SetSensor (EYE,SENSOR_LIGHT); 

SetupQ; 

On (LEFT+RIGHT); 

while(true) 

{ 

if (EYE<=tooDark) 

{ 

Off(LEFT); 

On(RIGHT); 





LEGO 



Lego 

Mindstorms 
Robot ics Invention 
System 2.0 



§ÌD Biblioteca 

• DEFINITIVE GUIDE 
TO LEGO MINDSTORMS 
II Edition 
Dave Baum's 




Fig. 3: Un semplice robot, dotato di sensore di 
luminosità. Notate come il robot segue, 
automaticamente, il tracciato nero. 



(Apress) 

ISBN: 1-59050-063-5 

Prezzo: US $29.99 

Si tratta di un testo, in 
lingua inglese, che con- 
sente di seguire passo 
passo la realizzazione 
di ben 14 robot. Scritto 
dal creatore del lin- 
guaggio NQC, da la 
possibilità, a chiunque 
ne abbia voglia, di rea- 
lizzare il proprio Robot, 
analizzandone ogni 
aspetto, finanche le 
leggi fisiche che ne re- 
golano il comportamen 
to. Ogni progetto rea- 
lizzato è ben illustrato 
e documentato. 
Per ognuno dei robot 
presentati, viene rea- 
lizzato il codice di fun- 
zionamento, sia in lin- 
guaggio C, sia median- 
te l'apposito kit visuale 
fornito insieme al Lego 
Mindstorms. 
Un testo che non può 
mancare nella bibliote- 
ca di ogni appassionato 
dei Lego Mindstorms. 



http: //www. itportal.it 



3 ►►► 53 



Un Software 



DI CONTROLLO PER MOTORI 
PASSO- PASSO 




Nello scorso numero è stato 

proposto uno schema elettronico 

adatto alla gestione di motori 

passo passo unipolari: in queste 

pagine proponiamo il relativo 

software di controllo, scritto con 

il linguaggio di programmazione 

Delphi. Realizzando la semplice 

scheda hardware proposta in 

precedenza ed utilizzando il 

programma riportato in questa 

sede, si ottiene un sistema 

semplice ed affidabile per la 

gestione di motori passo passo. 



precedenza non è sufficiente al controllo del motore, 
senza un idoneo programma che ne gestisca le caratte- 
ristiche. Abbiamo visto inoltre che questo tipo di mo- 
tori possono essere azionati in diversi modi, utilizzan- 
do diverse sequenze di commutazione delle linee, ot- 
tenendo prestazioni diverse che si adattano a differen- 
ti applicazioni. In queste pagine vogliamo proporre un 
programma che sia in grado di gestire un motore pas- 
so passo, mediante lo schema elettrico proposto in pre- 
cedenza, dando modo al lettore di potere variare senso 
di rotazione, velocità e modo di funzionamento di 
questo importante componente elettromeccanico. Si 
assume che venga utilizzato un sistema dotato di WIN 
9X oppure Millennium e che venga utilizzata una por- 
ta parallela con impostazioni standard LPT1 ( Indiriz- 
zi 0378h, 0379h 037 Ah ). 



Motori 

passo-passo 



Si potrebbe dire che l'uomo, nel trascorrere della 
sua storia, abbia sempre cercato un modo per fa- 
cilitare la propria esistenza. In epoca moderna, 
costruendo macchinari che svolgono il lavoro in modo 
autonomo, Tessere umano ha avuto bisogno di svaria- 
ti sistemi di propulsione ed azionamento delle proprie 
apparecchiature che sono divenute sempre più com- 
plesse con il passare del tempo. La semplice propul- 
sione non è sufficiente però senza una qualche forma 
di controllo: inoltre quanto più T algoritmo di gestione 
è Intelligente' e maggiore è la flessibilità delT apparec- 
chiatura. Ritornando ai nostri motori passo passo, pos- 
siamo sicuramente affermare che il circuito proposto in 



■ -ln|x| 



5'eppe; 


"*■ 


r Direction 




ff FWD 




r REW 




r Continuous Mo 


itoring 



<T One Phase On 
C Two Phase On 




Warning: Use this program and this circuit at your own risica wrong use may damage your system. 
Read the 'Licence and Disclaimer' file before using it. SpuntoSoft@tiscali.it 



Fig. 1: Lanciando il programma 'SpuntoStepperMo- 
tor.exe' incluso nel CD, si ottiene la schermata di 
figura, sulla quale sono direttamente disponibili 
tutti i comandi necessari alla gestione del motore. 



IL PROGRAMMA 

DI GESTIONE 

PER MOTORI PASSO PASSO 

Nel CD allegato alla rivista il lettore può trovare il pro- 
gramma di gestione completo, compilato e funzionan- 
te, completo di codice sorgete e componenti Delphi per 
la gestione di motori passo passo. Il programma, come 
dicevamo è in grado di generare una sequenza di com- 
mutazione sulle quattro linee del motore, in modo tale 
da permetterne la rotazione. In Fig. 1 si riporta una 
schermata del programma e della sua finestra princi- 
pale. Appare evidente, fin dal primo sguardo, lo sche- 
ma elettrico del circuito pilota, adatto ad azionare pic- 
coli motori: nel caso si impieghino componenti che ne- 
cessitano di una potenza maggiore, andrà modificato 
tutto lo stadio finale, utilizzando transistor di potenza, 
dotati di alette di raffreddamento ed altri svariati ac- 
corgimenti (configurazioni darlington ad esempio). 
Sul lato sinistro troviamo i comandi essenziali per la 
gestione del motore: la prima checkbox 'Stepper Motor 
Running' stabilisce, quando selezionata, se il motore 
deve essere in rotazione oppure no; si è preferito l'uti- 
lizzo di questo componente visuale anziché di un pul- 
sante per facilitare il lettore in eventuali modifiche. Di 
seguito sono disponibili due Radiobutton 'FWD' e 
'REW: che definiscono il senso di rotazione del moto- 
re, avanti ed indietro appunto. La checkbox che segue, 
chiamata 'Continuous Monitoring' indica al programma 
se deve effettuare il controllo dello stato logico della 
porta parallela o meno: apre inoltre la finestra del 'Va- 
rcale Pori Manager', che consente di visualizzare istan- 



m 



D 



File sul CD 

\soft\codice 
\StepperMotor.zip 



Ó 



One Phase ON 

Utilizzando la se- 
quenza di funzio- 
namento 'One phase ON' 
si procede ad alimentare 
il motore commutando 
una fase alla volta: in 
questo modo si ottiene 
una ragionevole dissipa- 
zione di potenza quando 
non sono richiesti eleva- 
ti valori di coppia del 
motore. 



http: //www. itportal.it 



3 ►►► 55 



t t 




Motori 

passo-passo 



Un Software 

di controllo per 
motori Passo-Passo 



3 



Two Phase ON 

La sequenza 'Two 
phase ON' per- 
mette un maggiore va- 
lore di coppia, dal mo- 
mento che vengono ali- 
mentate due fasi per 
volta, a discapito di una 
elevata dissipazione di 
potenza. 



Half Step 

^sl Quando si rende 
J necessaria una ele- 
vata precisione di movi- 
mento del motore ed 
una maggiore fluidità di 
rotazione, viene utilizza- 
ta la sequenza 'Half 
Step', che permette di 
raddoppiare il numero di 
passi che il motore deve 
effettuare per compiere 
una rotazione completa: 
in questo modo di fun- 
zionamento il valore di 
coppia disponibile non è 
costante, dal momento 
che vengono alimentate 
alternativamente una e 
due fasi. 



taneamente ogni variazione di stato delle linee di in- 
gresso/uscita della porta. Nella casella di Spinedit 'De- 
lay between Steps (Msec)', come il lettore potrà immagi- 
nare, è possibile selezionare il ritardo espresso in milli- 
secondi che deve intercorrere tra un passo e l'altro: ov- 
viamente il reciproco di questo valore esprime la fre- 
quenza di funzionamento misurata in Kilohertz. Nella 
parte bassa della finestra abbiamo infine tre RadioBut- 
tons denominati 'Pattern che indicano il tipo di se- 
quenza che il motore deve seguire: One phase ON, Two 
phase ON, oppure Half Step: maggiori dettagli in meri- 
to verranno riportati in seguito. 

LA STRUTTURA 
DEL PROGRAMMA 

Di seguito si riporta il listato relativo al programma di 
controllo, scritto in Delphi e comunque facilmente tra- 
sportabile in qualunque altro linguaggio di program- 
mazione. Nella prima parte del programma, ed in par- 
ticolare nella clausola 'USES' si può notare l'utilizzo 
dei due componenti cardine del programma per la 
parte di monitoring della porta, ovvero 'SpuntoLed- 
Component e UnitPortaParallela . 

I± // 

// TSpuntoStepperMotor Delphi 6 Application Ver 1.0 // 

// Copyright 2002 Luca Spuntoni Sept. 2002 // 

// spuntosoft@tiscali.it // 

l± // 

unit SpuntoStepperMotorUnitl; 

interface 

uses 

Windows, Messages, SysUtils, Variants, Classes, 
Graphics, Controls, Forms,Buttons, 

Dialogs, ExtCtrls, Menus, StdCtrls, 
SpuntoLedComponent, UnitPortaParallela, 

UnitAbout, Spin, Math; 

Nella dichiarazione dei tipi, oltre alla classe principale 
del programma, troviamo l' array 'TStepperMotorPat- 
tern , che dovrà contenere la sequenza scelta dall'uten- 
te, mediante la selezione di uno dei radiobuttons 'Pat- 
tern . 

type 

yy********* StepperMotor related arrays ********// 
TStepperMotorPattern = Array[0..7] of Word; 

// Array of step patterns 

La classe principale discende ovviamente da TForm e 
viene riportata nella sua integrità per motivi di chia- 
rezza: contiene tutte le procedure utilizzata nel pro- 
gramma per la gestione dei motori. In particolare, nel- 
la parte delle dichiarazioni 'Public troviamo Stepper- 
MotorSteps, una variabile del tipo 'TStepperMotorPat- 
tern deputata a contenere la sequenza di commutazio- 



ne in uso, oltre alla variabile 'PresentStep che ha il com- 
pito di memorizzare quale particolare passo della se- 
quenza è attivo, in modo tale da rendere possibile l'e- 
ventuale inversione del senso di rotazione del motore. 

jjif.if.if.if.if.if.if.if.if.if.if.if.if.if.if. Mgjn C|3SS ifififififififififififififififll 

TSpuntoStepperMotorForm = class(TForm) 

StepperMotorPanel: TPanel; 

MainMenul: TMainMenu; 

Filesl: TMenuItem; 

Exitl: TMenuItem; 

ParallelManagerl: TMenuItem; 

ShowManagerl: TMenuItem; 

Aboutl: TMenuItem; 

Labell: TLabel; 

Label2: TLabel; 

StepperMotorAttivoCheckBox: TCheckBox; 

DirectionGroupBox: TGroupBox; 

FWDRadioButton: TRadioButton; 

REWRadioButton: TRadioButton; 

DelayToStepSpinEdit: TSpinEdit; 

DelaytoStepTimer: TTimer; 

ContinuousMonitoringCheckBox: TCheckBox; 

PatternGroupBox: TGroupBox; 

OnePhaseOnRadioButton: TRadioButton; 

TwoPhaseOnRadioButton: TRadioButton; 

HalfStepRadioButton: TRadioButton; 

Imagel: TImage; 

Label3: TLabel; 

procedure ShowManagerlClick(Sender: TObject); 

procedure ExitlClick(Sender: TObject); 

procedure AboutlClick(Sender: TObject); 

procedure FormShow(Sender: TObject); 

procedure FormCreate(Sender: TObject); 

procedure StepperMotorControllalngressi; 

procedure StepFWD; 

procedure StepREW; 

procedure DelaytoStepTimerTimer(Sender: TObject); 
procedure DelayToStepSpinEditChange( 

Sender: TObject); 

procedure ContinuousMonitoringCheckBoxClick( 

Sender: TObject); 

procedure WritePort(PortAddress, PortData:word); 

procedure SelectMotorPattern; 

procedure OnePhaseOnRadioButtonClick( 

Sender: TObject); 

private 

{ Private declarations } 

public 

{ Public declarations } 

StepperMotorSteps : TStepperMotorPattern; 

// Array of present pattern 

PresentStep : Integer; 

end; 

Tra le costanti dichiarate di seguito nel programma, 
troviamo la dichiarazione di tre array corrispondenti 
alla sequenze di commutazione delle fasi del motore: si 
può notare che gli array in questione sono formati da 



56^^ F e b b 



http: //www. itportal.it 



otto elementi, anche se soltanto la sequenza 'Half Step' 
ha otto passi differenti, mentre per le altre due vengo- 
no semplicemente ripetuti i primi gruppi di quattro 
passi. Il lettore avrà senz'altro notato che il numero in- 
tero corrispondente a ciascuna posizione del motore 
corrisponde alla codifica decimale del valore binario 
che deve essere inviato alla porta parallela: Ad esem- 
pio per eseguire il primo passo della sequenza 'One 
phase ON' dobbiamo alimentare la fase corrispondente 
al bit DO della porta parallela, collegata al relativo sta- 
dio di potenza: per ottenere ciò occorre inviare alla 
porta il valore binario '00000001 ' corrispondente al va- 
lore decimale T . 




Per lanciare la routine di 'monitorizzazione' della porta 
parallela, è sufficiente selezionare l'opzione 'Show Mo- 
nitor' del menu 'Par allei Manager' , oppure semplice- 
mente attivare la checkbox 'Continuous Monitoring' sul- 
la finestra principale. In questo modo si attiva la fine- 
stra del 'Parallel Port Manager' già abbondantemente 
descritto negli appuntamenti precedenti, e che sta ri- 
scuotendo un notevole successo da parte dei lettori, co- 
me comprovato dal flusso di e-mail che l'autore riceve 
continuamente sull'argomento. 
Come si può notare dalla figura che segue, si assume 
che le impostazioni della porta parallela siano quelle 
standard di LPT1, cioè utilizzanti gli indirizzi fisici 



■^Jn|x| 



[ 





~r"v 


MY 


1 S« 


Data Port Control Port Status Port 


y\co 


.X 




Hex:0378 Hex:037A Hex:0379 


1 


1 








do _cj co jj # so 

« 01 _J « CI jj «SI 

1 • D2^J # C2^J # S2 

2 • ° 3 jj • c3 _lI g s3 

« D4^J # C4jJ « S4 
3 D5 JjJ % C5 _J # S5 




ì 


K « DG_bJ * CG_G_ 
« D7^J « C7^J 


« se 

O S7 






^L 


[ 



Warning: Use this program and this circuit at your own risk:a wrong use may damage your system. 
Read the 'Licence and Disclaimer' file before using it. SpuntoSoft@tiscali.it 



Fig. 2: Selezionando la Checkbox 'One Phase ON', 
si richiede al programma di alimentare il motore 
in modo tale da attivare una fase alla volta allo 
scopo di ottenerne la rotazione. 



0378h, 0379h e 037Ah. Di seguito si riportano le proce- 
dure che provvedono ad attivare il monitor della por- 
ta parallela: il loro funzionamento è abbastanza intui- 
tivo, pertanto per motivi di brevità se ne lascia l'anali- 
si al lettore. 

procedure TSpuntoStepperMotorForm 

.ShowManagerlClick(Sender: TObject); 

begin 

ContinuousMonitoringCheckBox.Checked : =True; 

FormPortaParallela.Show; 

FormPortaParallela.StepperMotorPortaParallela 

.SpuntoContinuousMonitoring: = 

ContinuousMonitoringCheckBox.Checked; 

end; 

procedure TSpuntoStepperMotorForm 

.ContinuousMonitoringCheckBoxClick( 

Sender: TObject); 

Begin 

FormPortaParallela.StepperMotorPortaParallela 

.SpuntoContinuousMonitoring:=ContinuousMonitoring- 

CheckBox.Checked; 

If ContinuousMonitoringCheckBox.Checked Then 

FormPortaparallela.Show else FormPortaparallela.Hide; 
end 

Per la gestione della visualizzazione delle varie fine- 
stre di dialogo accessorie del programma e della ge- 
stione della chiusura del programma, vengono utiliz- 
zate le procedure che seguono, il funzionamento delle 
stesse è abbastanza ovvio e sul quale non ci dilunghia- 
mo per problemi di spazio. 



# 



procedure TSpuntoStepperMotorForm 


ExitlClic 
Sender: 


TObject); 


begin 


SpuntoStepperMotorForm.Close; 


end; 


procedure TSpuntoStepperMotorForm. AboutlClick( 

Sender: TObject); 


begin 


SpuntoAbout.ShowModal; 


end; 


procedure TSpuntoStepperMotorForm. FormShow( 

Sender: TObject); 


begin 


SpuntoAbout.ShowModal; 


end; 



Quando l'utente varia il valore di ritardo nello Spine- 
dit di nome 'DelayToStep' , viene eseguito l'event hand- 
ler 'DelayToStepSpinEditChange' che provvede sempli- 
cemente ad impostare il valore del ritardo sul timer 
'DelayToStepTimer' , variando il tempo che intercorre tra 
due passi consecutivi del motore. 

procedure TSpuntoStepperMotorForm 

.DelayToStepSpinEditChange(Sender: TObject); 




Motori 

passo-passo 



Un Software 

di controllo per 
motori Passo-Passo 



Monitorizzazione 

r% Per lanciare la 
^ routine di 'moni- 
torizzazione' della por- 
ta parallela, è suffi- 
ciente selezionare l'op- 
zione 'Show Monitor' 
del menu 'Parallel Ma- 
nager', oppure sempli- 
cemente attivare la 
checkbox 'Continuous 
Monitoring' sulla fine- 
stra principale. 



http: //www. itportal.it 



3 ►►► 57 




Motori 

passo-passo 



Un Software 

dì controllo per 
motori Passo-Passo 



Sistema 
Operativo 

^ Il programma ri- 
^-J chiede un sistema 
operativo WIN 9X op- 
pure Millennium. 



Bibliografia VIO 

• CONTROLLIAMO LA 

PORTA PARALLELA 

CON DELPHI 6 

(Luca Spuntoni) 

ioProgrammo 

Aprile 2002 



begin DelayToStepTimer.Interval: = 

DelaytoStepSpinEdit.Value; 

end; 

All'avvio del programma si rendono necessarie alcune 
azioni di predisposizione della finestra principale e di 
inizializzazione delle variabili di controllo del pro- 
gramma. Occorre inoltre selezionare il tipo di sequen- 
za da fare seguire al motore, tramite l'esecuzione della 
procedura 'SeledMotorF 'atterrì ' . 

procedure TSpuntoStepperMotorForm.FormCreate( 

Sender: TObject); 

Var 

I:Integer; 

V:Variant; 

S:String; 

begin 

//Inizializzazione Variabili di controllo 

StepperMotorAttivoCheckBox.Checked: = False; 

ContinuousMonitoringCheckBox.Checked: = False; 

DelayToStepTimer.Interval: = DelaytoStepSpinEdit.Value; 

//Selezione del tipo di pattern del motore 

SelectMotorPattern; 

end; 



■ -|n|x| 



I 



ESSE 



f^ 



■ -i i*1 
Data Pori Control Pori Status Pori 

Hex:0378 Hex:037A Hex:0379 



do jj 
D,.ij 

D 2 ^j 
D3^J 
D4 _jj 
D5 JjJ 

D6 JìJ 
07^J 



CO jj 

<=_*] 

C4^J 
USj] 

C7^J 




Warning: Use this program and this circuit at your own risica wrong use may damage your system. 
Read the 'Licence and Disclaimer' file before using it. SpuntoSoft@tiscali.it 



Fig. 3: Selezionando la Checkbox A Two Phase ON', 
si richiede al programma di alimentare il motore 
due fasi alla volta, per ottenere il massimo valore 
di coppia. 

La selezione del tipo di sequenza da utilizzare avviene 
attraverso la procedura 'SelectMotorPattern , che asse- 
gna semplicemente all'array 'StepperMotorSteps' i valo- 
ri contenenti in una delle costanti 'OnePhaseOnMotor- 
Steps' ', 'TwoPhaseOnMotorSteps' , oppure 'HalfStepMo- 
torSteps'. 



Entrando nel vivo del funzionamento del programma, 
vediamo come è stato risolto il problema della gestio- 
ne temporale dell'invio della sequenza di passi alla 
porta parallela. Il programma comprende un compo- 
nente TTimer, di nome 'DelaytoStepTimef '; l'event 
handler di questo componente che si occupa della ge- 
stione dell' evento 'OriTimer' è la procedura 'Delayto- 
StepTimerTimer' '. In parole più semplici, ogni volta che 
il timer genera un messaggio 'OriTimer' la procedura 
'DelaytoStepTimerTimer' viene eseguita. Questa proce- 
dura, si preoccupa del controllo dello stato delle uscite 
della porta parallela, chiamando 'StepperMotorControl- 
lalngressi' che viene riportata di seguito. Se l'utente ha 
deciso di fare ruotare il motore in avanti viene esegui- 
to 'StepFWD' altrimenti viene lanciato 'StepREW. 

procedure TSpuntoStepperMotorForm 

.DelaytoStepTimerTimer(Sender: TObject); 

begin 

StepperMotorControllalngressi; 

end; 

procedure TSpuntoStepperMotorForm 

.StepperMotorControllalngressi; 

Begin 

If StepperMotorAttivoCheckBox.Checked then begin 
If FWDRadioButton.Checked then StepFWD 
else StepREW; 

End; 

End; 

Le procedure 'StepFWD' e 'StepREW sono molto simi- 
li, in breve stabiliscono su quale indirizzo fisico devo- 
no inviare la codifica del passo corrente, attraverso il 
valore contenuto in 'MYPortAddress' , dopo di ciò prov- 
vedono ad incrementare o a decrementare il valore del- 
la variabile globale 'PresentStep' a seconda se il motore 
debba ruotare in un senso, oppure neir altro: viene 
operato a questo punto un controllo per verificare se la 
sequenza è giunta in uno degli estremi ed in questo ca- 
so viene fatta ripartire dall'inizio. Con questo sistema 
la variabile 'PresentStep' avanza od indietreggia tra un 
valore compreso tra e 7, numero che ci permette a 
questo punto di ricavare il valore da inviare alla porta 
da uno degli array contenente le sequenze di passi. Fi- 
nalmente viene inviato in uscita il valore corrispon- 
dente alla codifica binaria della sequenza di attivazio- 
ne delle fasi del motore attraverso la procedura 'Write- 
Port'. 



procedure TSpuntoStepperMotorForm.SelectMotorPattern; 
Begin 

If OnePhaseOnRadioButton.Checked then 
StepperMotorSteps: =OnePhaseOnMotorSteps; 

If TwoPhaseOnRadioButton.Checked then 
StepperMotorSteps: =TwoPhaseOnMotorSteps; 

If HalfStepRadioButton.Checked then 

StepperMotorSteps : = HalfStepMotorSteps; 

End; 



procedure TSpuntoStepperMotorForm .StepFWD; // Step FWD 

Var 

W,MyPortAddress:Word; 

Begin 

MYPortAddress: = Form PortaParallela 

.StepperMotorPortaParallela.SpuntoPortDataAddress; 

PresentStep : = PresentStep+ 1 ; 

If PresentStep>7 then PresentStep :=0; 

W:=StepperMotorSteps[PresentStep]; 



58^^ F e b b 



http: //www. itportal.it 



t t 



WritePort(MyPortAddress,W); 

End; 

procedure TSpuntoStepperMotorForm.StepREW; 

// Step REW 

Var 

W,MyPortAddress:Word; 

Begin 

MYPortAddress: = FormPortaParallela 

.StepperMotorPortaParallela.SpuntoPortDataAddress; 

PresentStep : = PresentStep- 1 ; 

If PresentStep<0 then PresentStep:=7; 

W:=StepperMotorSteps[PresentStep]; 

WritePort(MyPortAddress,W); 

End; 

La scrittura del valore numerico sulla porta parallela 
avviene per mezzo della procedura 'WritePorf. In que- 
sta occasione il linguaggio Assembler ci viene in aiuto, 
facilitando l'accesso alle risorse hardware del nostro di- 
spositivo parallelo. A causa dell'accesso diretto alle ri- 
sorse di sistema, è conveniente utilizzare sistemi ope- 
rativi WIN 9X, oppure Millennium, dal momento che 
con WIN2000, oppure XP è possibile che il sistema ri- 
fiuti T esecuzione di questa parte di codice, innalzando 
un'eccezione di 'Privileged Instruction . 

procedure TSpuntoStepperMotorForm.WritePort( 

PortAddress, PortData:word); 

// Write PortData over PortAddress if Port Writing is enabled 

begin 

PortData := (PortData*256)+PortData; 

asm 

Mov ax, PortData 

Mov dx, PortAddress 

Out dx,ax 

end; 



Efes PaiaIN Manager Aboul 












|7 Stepper Motor 
[-Direction 


unning 


Data Pori Control Pori Status Pori 

Hex:0378 Hex:037A Hex:0379 

% DO Ji\ % CO jj % SO 

• DijJ • crjj • a 

01 • D2^J # C2^J * 
D2 • D3^J # C3_^J Q ss 

« D4^J « C4^J « S4 
D3 D5 JjJ « C5 _5j # S5 
GK • D6 Jl| • C6 jj % SO 

« D7jj « C7jJ O S7 


>T\_ 


tepper MotOE 




<? FWD 
r REW 




; 


7co Ml 


+5V 










17 Contine Monrtorrng 


!.. 


~i 




500 jtj 








C OnePhaseOn 
C TwcPhaseOn 
C HalfStep 


ri (? 


] | Sk 












«orS Eara^lelaT 






Warning: Use this program 


and this circuit at your own risk:a wrong use may damage your system. 


Read the 'Licenc 


e and Disclaimer' file before using it. SpuntoSoft@tiscali.it 







end; 



Fig. 4: Selezionando la Checkbox 'Half Step', si ri- 
chiede al programma di alimentare il motore con 
una sequenza tale da raddoppiarne il numero di 
passi nominali. 



mente in funzione della applicazione che si desidera 
realizzare, tuttavia si vogliono dare alcune indicazioni 
per ovviare ad alcuni problemi di semplice risoluzione 
che potrebbero presentarsi al lettore. Nel caso in cui il 
motore non accenni affatto a muoversi, si provi a veri- 
ficare se l'albero è libero di ruotare oppure se rimane 
fisso in una certa posizione: nel primo caso significa 
che probabilmente il motore non viene alimentato, nel 
secondo che vi è qualche errore di cablaggio, in ogni ca- 
so per risolvere il problema provvediamo a controllare 
tutte le connessioni. Se il motore si muove ma anziché 
ruotare vibra, oppure procede a scatti irregolari, signi- 
fica che la connessione delle fasi del motore non è cor- 
retta, quindi occorre verificarne nuovamente i collega- 
menti. Può verificarsi un eccessivo surriscaldamento 
dei transistor, nel caso in cui questi siano sottodimen- 
sionati rispetto alle caratteristiche del motore: in questo 
caso provvediamo a sostituirli con finali di potenza 
maggiore, eventualmente in configurazione Darlington 
e dotiamoli di una aletta dissipatrice: in casi estremi in- 
stalliamo una ventola di raffreddamento. 



* 



Motori 

passo-passo 



Un Software 

di controllo per 
motori Passo-Passo 



Parametri 
della Porta 
Parallela 



ó 



Si assume che nel 
sistema utilizzato 
sia disponibile una 
porta parallela con 
parametri standard 
LPT1 (Indirizzi 0378h, 
0379h 037Ah). 



COLLAUDO DEL SISTEMA 

Una volta realizzato il circuito di controllo, provvedia- 
mo a collegarlo alla porta parallela del PC, mediante 
un cavo di prolunga a 25 poli pin to pin, facendo at- 
tenzione a verificare che il cavo sia effettivamente di 
questo tipo. Procediamo ad alimentare il circuito prima 
di accendere il PC e lanciamo il programma di control- 
lo. Per provare che tutto funzioni come dovrebbe im- 
postiamo un ritardo di 500 mSec tra un passo e l'altro, 
in modo da verificare il movimento del motore con ac- 
curatezza. 

RISOLUZIONE 
DEI PROBLEMI 

Come è già stato detto più volte quanto riportato in 
questa sede riveste una veste generale e di studio, il cir- 
cuito di controllo infatti andrebbe disegnato apposita- 



CONCLUSIONI 

In questo speciale dedicato ai motori passo passo ab- 
biamo appreso come realizzare un circuito di controllo 
per questi motori, abbiamo esaminato le tecniche rela- 
tive al loro controllo ed abbiamo analizzato un pro- 
gramma completo per la loro gestione. Per motivi di 
spazio non abbiamo analizzato alcune tecniche avan- 
zate per il controllo della coppia e della velocità di ro- 
tazione dei motori. A questo proposito ricordiamo che 
l'utilizzo delle tecniche, del codice e del progetto elet- 
tronico discussi in quest'articolo, deve essere effettuato 
con estrema cautela, dal momento che Fautore e l'edi- 
tore non possono essere accreditati di alcuna respon- 
sabilità implicita od esplicita conseguente dall'uso e 
dal funzionamento del software e dell'hardware espo- 
sto in questa sede. 

Luca Spuntoni 
(spuntosoft@tiscalinet.it) 



http: //www. itportal.it 



3 ►►► 59 



E I 



t t 




Un server 

WEB NEL TASCHINO DELLA GIACCA 



Micro 

Controller 



3 



Distribuita da.. 

Area SX S.r.l. 

INFORMATICA & 
MICROELETTROIMICA 
http://www.areasx.com 
info@areasx.com 
Via Luigi Robecchi Bri- 
chetti, 13 
00154 - Roma 
Tel. 06 57.17.26.79 
Fax. 06 57.17.26.95 



Si chiama Rabbit, un completo 

sistema a microprocessore, dalle 

ridotte dimensioni (più piccolo di 

un pacchetto di sigarette), in 

grado di "dialogare' 7 in rete, 

tramite protocollo TCP/IP. 

Dotato di diverse porte di 

input/output consente, per 

esempio, di pilotare tramite la 

rete Internet qualunque 

apparecchiatura elettronica. 



Un modulo Rabbit è una particolare scheda 
elettronica, di dimensioni ridottissime (Fig.l), 
che riesce ad assolvere a svariati compiti. Il si- 
stema ospita un microprocessore Rabbit a 8 bit con 
clock interno a 22.1Mhz, una memoria Flash da 256 
KByte, memoria RAM da 128 KByte, porta Ethernet 
lOBase-T da 10Mbit, 26 linee di I/O di uso generale, 4 
porte seriali sincrone con baud rate sino a 345.600 bps, 
un orologio Real-Time con datario, 5 timer a 8 bit, 1 ti- 
mer a 10 bit,un Watchdog timer. 
Un modulo Rabbit può essere così inserito in qualun- 
que progetto elettronico e assolvere a diversi compiti, 
tra cui, forse quello più spettacolare, il telecontrollo; 
pensate alla possibilità di interfacciare il modulo ad un 
qualunque apparato elettrico e comandare quest'ulti- 
mo, da qualunque parte del pianeta, tramite una sem- 
plice connessione Web. 

Unico vincolo, il costante interfacciamento del modulo 
alla connessione Internet (tramite normale cavo RJ45), 
ma con ADSL questo non dovrebbe essere un proble- 
ma. 







1 1 




% . " 


^ -u 


$M 


*- JÈ2v "^* I 


^22»^%. 


■ i 








'" V Jà 


. . \ ^tp^ 


^ÉlS 


\3^^^S%*&£aSk 






li \ "yak 


Wgm0 ) 



Il modulo Rabbit viene fornito (separatamente) dal- 
l'ambiente di sviluppo Dynamic C 7.26TSE2, che per- 
mette di programmare il modulo a seconda delle pro- 
prie esigenze. Esistono diversi modelli di Rabbit, quel- 
lo di cui ci occuperemo in questo articolo, è TRCM2200 
che tra l'altro rappresenta anche il modello più econo- 
mico della gamma. 

Il modello, come già accennato in precedenza, dispone 
di una porta Ethernet che consente di interfacciarlo ad 
una connessione di Rete, permette quindi di gestire 
una serie di protocolli di rete, tra i quali: http, ftp, tel- 
net, POP, SMTP. Nei core modules Rabbit coesistono 
diverse caratteristiche tipiche dei microcontroller: me- 
moria flash, basso assorbimento, linee di I/O TTL, ecc. 
e caratteristiche tipiche dei PC quali: connessione di 
Rete, gestione dei protocolli TCP /IP, file system, am- 
biente di programmazione IDE in linguaggio C, multi- 
tasking, ecc. 

In Italia il prodotto è distribuito da AreaSX (www.area- 
sx.com) di Sergio Tanzilli, all'interno del sito troverete 
tutte le indicazioni utili per acquistare sia i moduli che 
l'ambiente di sviluppo. AreaSX produce anche una 
scheda, denominata demo board SX01 che, interfaccian- 
dosi con il modulo Rabbit RCM2200, aiuta gli svilup- 
patori ad effettuare prototipazioni veloci di progetti. 
La demo board (Fig.2) può essere acquistata indipen- 
dentemente dal development kit e dai moduli Rabbit, 
in versione già montata e collaudata. 




Fig. 1: Il modulo Rabbit RCM2200. 



Fig. 2: La demo board SX01 

I MODULI 

DELLA SERIE 2000 

Il Rabbit 2000 è un microprocessore basato su una ar- 
chitettura a 8 bit, con aritmetica a 16 bit. La serie 2000 
dei Core Modules comprende 4 modelli principali, 
identificati rispettivamente dalle sigle RCM2000, 
RCM2100, RCM2200, RCM2300. Ciascuno di questi 
modelli ha diverse versioni. 



&()►►► F e b b r 



http: //www. itportal.it 



t t 





RCM20xO 

Ali 'interno di questa classe si trovano le versioni RCM2000, 
RCM2010 ed RCM2020 

Tutti questi modelli sono equipag- 
giati con 40 linee I/O, 4 porte seria- 
li, 5 timer,Real Time Clock; non so- 
no dotati invece di porta ethernet. 
Sono indicati per progetti entry level e low cost, dove 
l'accesso alla rete non è utilizzato. Le differenze tra le 
varie versioni risiedono solamente nella velocità del 
clock (25.8 MHz per le versioni 2000 e 2010, 18.4 MHz 
per la versione 2020) e nella dotazione di SRAM. 

RCM21xO 

Ali 'interno di questa classe si trovano le versioni RCM2100, 
RCM2110, RCM2120 ed RCM2130 

Sono Core Module di dimensioni 
meno contenute rispetto ad altri 
modelli equivalenti (misurano 89 x 
51 x 22 mm) e sono tutti dotati di 
porta ethernet; le due versioni 2100 e 2110 hanno il 
connettore RJ45 con led a bordo, mentre i modelli 2120 
e 2130 mettono a disposizione solamente i segnali 
ethernet sui piedini, consentendo il montaggio di una 
presa RJ-45 esterna. 

Sono modelli superati dagli equivalenti della classe 
RCM2200, che forniscono più o meno la stessa dota- 
zione hardware in uno spazio più contenuto; l'unico 
vantaggio di questi modelli è la presenza di alcune li- 
nee di I/O in più. 

RCM22xO 

Ali 'interno di questa classe si trovano le versioni RCM2200, 
RCM2210 ed RCM2250 

Questi modelli, molto simili tra lo- 
ro, sono sicuramente tra i più inte- 
ressanti della serie, per le ridotte di- 
mensioni e la dotazione hardware 
veramente notevole. Comprendono infatti, su una 
scheda di 4x6 cm, 26 porte di I/O, 4 seriali, una porta 
ethernet, un RTC, linee di espansione (4 indirizzi, 8 da- 
ti ed un I/O Read-Write), timer e watchdog. La diffe- 
renza tra i modelli 2200 e 2210 consiste nel fatto che il 
primo ha il connettore ethernet ed i led di attività 
(LNK e ACT) montati a bordo, mentre il secondo ha 
solamente i segnali ethernet portati sui piedini, con- 
sentendoci di montare un nostro connettore e dei led 
esterni. 

Il modello RCM2250 è sostanzialmente identico al 
2200 ma ha un superiore quantitativo di memoria sia 
Flash che SDRAM (512K per entrambe). 

RCM23xO 

Questa classe comprende il solo modello RCM2300 

Questo Core Module ha caratteri- 
stiche sicuramente notevoli: nono- 
stante le sue dimensioni estrema- 
mente ridotte (misura 4x3 cm) che 

consentono una alta integrazione, fornisce una dota- 





zione hardware di tutto rispetto, comprendente 29 li- 
nee di I/O, 4 porte seriali, 5 timer ad 8 bit, un timer a 
10 bit, real time clock, watchdog. 
Altra caratteristica di rilievo è quella di essere pin to 
pin compatibile con i modelli della serie RCM22xO. 
Questo significa che nel momento in cui sviluppiamo 
un progetto basato su questo Core Module possiamo, 
senza modificare l'hardware realizzato, aggiungere la 
possibilità di avere la porta ethernet, semplicemente 
sostituendo il Core Module stesso. 

I MODULI 

DELLA SERIE 3000 

I modelli della serie 3000 sono solamente 3, identifica- 
ti rispettivamente dalle sigle RCM3000, RCM3100 ed 
RCM3200. Sono caratterizzati da dimensioni maggiori 
rispetto ai modelli serie 2000, ma hanno caratteristiche 
di tutto rilievo. La prima differenza fondamentale è 
che il microcontrollor ha un core a 16 bit, rispetto agli 
8 del Rabbit 2000; questo gli garantisce tutta una serie 
di vantaggi, tra cui un notevole aumento di velocità ed 
un maggiore spazio di memoria indirizzabile. La 
quantità di periferiche è notevole, si va dalle 6 porte se- 
riali, alle 56 linee di I/O, unitamente alla capacità di es- 
sere alimentato da 1.5V a 3.6V, mantenendo comunque 
la possibilità di ricevere ingressi TTL (da a 5V). 

RCM30xO 

All'interno di questa classe si trovano le due versioni 
RCM3000 ed RCM3010 

Questi Core Module, oltre alle do- 
tazioni "di serie" ereditate dalla se- 
rie 2000 (52 linee di I/O, 6 porte se- 
riali, 10 timer, real time clock, wat- 
chdog, linee di espansione), possiede caratteristiche 
del tutto innovative: una porta seriale ad infrarossi 
SDLC/HDLC (con IrDA), 4 porte SPI, 4 uscite PWM 
(Pulse Width Modulation), un decoder in quadratura 
per encoder ottici. 

Di dimensioni leggermente più grandi della maggior 
parte dei core module serie 2000 (misura infatti 69 _ 47 
_ 22 mm), è una scelta validissima per tutti i progetti, 
anche i più complessi 

RCM31xO 

Modelli in questa classe sono VRCM3100 e VRCM3110 

Due core modules adatti per tutti 
quei progetti in cui non sia richiesta 
una porta ethernet. Infatti in soli 
4742 mm integrano tutte le perife- 
riche presenti nei modelli della classe RCM30xO, man- 
tenendo con questi anche la compatibilità pin to pin. 
Questo consente, analogamente al modello RCM2300, 
di sviluppare applicazioni che non abbiano bisogno 
della connettività ethernet e poi migrare, semplice- 
mente sostituendo il core module con uno della classe 
RCM30xO, ad applicazioni che ne facciano uso. 
La differenza tra i due modelli risiede solamente nella 






Micro 

Controller 



Un server 

WEB nel taschino 
della giacca 



Ambiente 
di sviluppo 



Caratteristiche 
dell'ambiente IDE 
Dynamic C SE: 



Ó 



• Un editor per poter 
scrivere i sorgenti da 
compilare 

• Un compilatore ANSI C 

• Un loader per scarica- 
re il codice compilato 
sul modulo Rabbit 

• Un debugger per po- 
ter eseguire passo pas- 
so i propri programmi 

• Una raccolta di libre- 
rie standard pronte 
all'uso 

• Una completa docu- 
mentazione tecnica (in 
inglese) 



http: //www. itportal.it 



F e b b r a 



2 3 ►►► 61 



t t 




Micro 

Controller 



Un server 

WEB nel taschino 
della giacca 



Ó 



Demo Board 
SX01 

La demo board 
SX01 è una sche- 
da progettata e prodot- 
ta da Area SX srl. 
http://www.areasx.com 
per aiutare gli svilup- 
patori ad effettuare 
prototipazioni veloci di 
progetti basati sui mo- 
duli della Rabbit Semi- 
conductor RCM2200. 




quantità di memoria a bordo (512K di flash ed altret- 
tanta di SDRAM per TRCM3100, la metà per il 3110). 

RCM32xO 

Unico modello in questa classe è URCM3200 

Il Core Module più potente e com- 
pleto della gamma. Di dimensioni 
l ™ abbastanza contenute (69_47 mm) la- 

vora con un clock a 44 Mhz e possiede una dotazione 
di memoria di tutto rispetto: 512Kb di Flash e 768Kb di 
SDRAM (divisa tra programma e dati). Oltre alle dota- 
zioni "standard" della classe 3000 (52 I/O, 6 seriali, 
SDLC/HDLC, RTC, ecc.) possiede anche il supporto 
per convertitori MIR/SIR Ir DA. 
E' il prodotto da utilizzare per i progetti più complessi, 
dove siano richieste tutta la velocità e la potenza che 
questo Core Module può offrire; in progetti meno com- 
plessi è preferibile sicuramente un modello delle due 
classi precedenti. 

UNA PROVA PRATICA 
DEL RABBIT RCM2200 

Il kit di sviluppo per RCM2200 nella versione estesa si 
compone delle seguenti parti: 

• Un CD contenente l'ambiente di sviluppo della Z- 
World Dynamic C SE. 

• Un programmatore in-circuit da collegare tra una 
porta seriale RS232 libera del nostro PC ed il mo- 
dulo Rabbit da programmare. 

• Un modulo Rabbit RCM2200. 

• Una demo board prodotta dalla Rabbit Semicon- 
ductor. 

• Una scheda di registrazione del prodotto. 

• Un piccolo manuale in lingua inglese. 

In questa prima prova pratica facciamo riferimento al- 
la scheda SX01 prodotta da Area SX con cui è possibi- 
le effettuare diverse prove di sviluppo. Maggiori infor- 
mazioni sulla SX01 sono accessibili sul sito www.area- 
sx.com 

La prima operazione da compiere, consiste nell'instal- 
lazione dell'ambiente di sviluppo installando il relati- 
vo software direttamente dal supporto CD-Rom forni- 
to nel development kit. 

Terminata la fase di installazione, appariranno sul no- 
stro desktop alcune icone ognuna corrispondente ad 
altrettanti collegamenti a parti dell'SDK: L'icona DC 
7.26TSE RFU è il collegamento al programma Rabbit 
Field Utility ovvero un loader che consente di scaricare 
un programma già compilato direttamente sul rabbit 
senza richiedere l'intero ambiente di sviluppo. E' mol- 
to utile in fase di produzione o distribuzione dei nostri 
lavori ma per ora non dovremo utilizzarla. 
L'icona DCSE TCPIP 7.26TSE è il collegamento al vero 
e proprio ambiente di sviluppo. L'icona TCPIP 7.26TSE 
Docs è il collegamento a tutta la documentazione di- 
sponibili sul CD. Infatti come avrete certamente notato 



con il kit di sviluppo non viene fornito alcun manuale 
se non un brevissimo "Getting started". Su CD invece è 
presente una notevole mole di documentazione, sche- 
mi elettrici, applicazioni d'esempio, ecc. sia in formato 
HTML consultabile con il browser, sia in formato PDF 
più adatto per ottenere una copia su carta. Tutta la do- 
cumentazione è disponibile purtroppo solo in lingua 
inglese. 

INSTALLAZIONE 
DEL MODULO 

Prima di avviare l'SDK occorre collegare l'hardware di 
cui disponiamo. Iniziamo dal programmatore. Colle- 
ghiamo il connettore a vaschetta femmina a 9 sulla no- 
stra porta seriale (la stessa che abbiamo specificato du- 
rante l'installazione) e disponiamo l'altra estremità sul- 
la nostra scrivania. A questo punto innestiamo sulla 
doppia fila di connettori 13x2 pin posti sulla scheda 
SX01, il nostro modulo RCM2200, così come indicato 
in Fig. 3. 




Fig. 3: Inserimento del modulo Rabbit sulla demo- 
board SX01. 



La serigrafia sullo stampato ci aiuterà a posizionare 
correttamente il modulo. Togliamo lo jumper JP1 sulla 
scheda SX01 situato nei pressi del ponte raddrizzatore 
GÌ e colleghiamo al morsetto J4 un alimentatore con 
tensione compresa tra 9 e 15 volt da almeno 500mA. 
Per quanto riguarda l'alimentatore c'è da sottolineare 
di badare bene alla corrente erogabile (non inferiore a 
500mA) e la tensione in uscita, ricordiamo ancora una 
volta compresa tra i 9 e i 15 volt. Non ha importanza se 
la tensione in uscita sia in continua o alternata o il tipo 
di spinotto di cui dispone. In tutti i casi dovremo ta- 
gliare lo spinotto, spellare i due fili ed inserirli nel mor- 
setto J4. Non è necessario prestare alcuna attenzione al 
verso di inserimento dei due fili grazie alla presenza 
del ponte raddrizzatore GÌ che penserà a dare alla cir- 
cuiteria la giusta alimentazione. 
Colleghiamo l'alimentatore alla rete elettrica e reinse- 
riamo al suo posto il ponticello JP1 (Fig.4) 
Il led rosso power dovrebbe accendersi ad indicare che 
il circuito è correttamente alimentato. 
Inseriamo il connettore contrassegnato con l'etichetta 
PROG sul connettore a 5x2 pin presente direttamente 
sul modulo Rabbit facendo attenzione che la banda 



62 ►►► Febbraio 



2 3 



http: //www. itportal.it 




Fig. 4: Colleghiamo l'alimentatore al circuito. 

rossa del cavo fiat si trovi in direzione della scritta Jl 
presente sullo stampato del Rabbit. 
Avviamo quindi l'SDK cliccando sull'icona DCSE TC- 
PIP 7.05TSE. L'applicazione inizierà ad effettuare una 
scansione delle librerie presenti seguito da un tentati- 
vo di comunicazione con il modulo Rabbit. Se appare 
qualche messaggio di errore, probabilmente abbiamo 
sbagliato porta seriale, oppure non abbiamo acceso la 
nostra scheda SX01 o il programmatore non è stato in- 
serito in modo corretto. 

Se tutto è stato alimentato seconda la norma, e il pro- 
grammatore è stato inserito in modo corretto ma no- 
nostante ciò riceviamo ancora un messaggio d'errore, 
proviamo a cambiare il numero di porta seriale acce- 
dendo al menù Options -> Communications cambiando 
nel campo Port il numero di porta seriale. 
Dal menù Compile quindi selezioniamo la voce Reset 
Target/ Compile BIOS per richiedere un nuovo tentativo 
di connessione tra l'SDK ed il modulo Rabbit. 



:pk m feljSa X fl^l a ^ S.&] Edi, | Compiisi As Semb | Regs | Stacfc j _f] 



| COMI: 57600 



Fig. 5: L'ambiente di sviluppo. 

UN PRIMO 
PROGRAMMA DI TEST 

Sulla scheda demoboard SX01 sono presenti due led, 
uno rosso, l'altro verde,comunemente chiamati led di 
test. In questa prima applicazione, giusto per verifica- 
re il funzionamento dell'intera struttura, scriviamo 



una semplice applicazione di test, che si limiterà a far 
lampeggiare alternativamente i due diodi led di test. 
Selezioniamo dal menù File la voce New per creare un 
nuovo programma da trasferire al Rabbit. Si aprirà una 
nuova finestra di editing che consentirà di scrivere i 
nostri programmi in linguaggio C. Digitiamo quindi il 
seguente sorgente: 

nodebug void msDelay(unsigned int ams) 

{ 

auto unsigned long tO; 

for( tO = MS_TIMER; MS_TIMER< ams+tO; ) ; 

> 

// Inizio programma 

main () 

{ 

// Imposta la porta D come linea di ingresso/uscita 

WrPortI(PDFR, &PDFRShadow, 0x0); 

// Imposta la porta PD3 come uscita 

BitWrPortI(PDDDR, &PDDDRShadow, 1,3); 

// Esegue un loop infinito 

while(l) 

j 

// Attende 5Q0mS 

msDelay(5Q0); 

// Accende il led verde TESTI 

BitWrPortI(PDDR, &PDDRShadow, 1, 3); 

// Spegne il led verde TEST2 

BitWrPortI(PBDR, &PBDRShadow, 0, 7); 

// Attende altri 500mS 

msDelay(5Q0); 

// Spegne il led verde TESTI 

BitWrPortI(PDDR, &PDDRShadow, 0, 3); 

// Accende il led verde TEST2 

BitWrPortI(PBDR, &PBDRShadow, 1, 7); 

_} 

} 

Clicchiamo il pulsante Compile presente sulla barra de- 
gli strumenti. 

Selezioniamo dal menu Run la voce Run. Sulla scheda 
SX01 dovremo vedere i diodi led TESTI e TESTI, lam- 
peggiare alternativamente con una frequenza di mez- 
zo secondo. 

Per bloccare l'esecuzione del programma selezioniamo 
la voce Stop dal menu Run. 

CONCLUSIONI 

Si conclude qui questa prima panoramica sul modulo 
Rabbit, nei prossimi appuntamenti approfondiremo il 
discorso, mostrando come realizzare un'applicazione, 
e relativa scheda di interfaccia al modulo, per coman- 
dare tramite un'applicazione Flash sul Web, una serie 
di led posti come interfaccia al modulo RCM2200. 

Santo Serra 



# 




Micro 

Controller 



Un server 

WEB nel taschino 
della giacca 



& Sul Web 

Tutto il materiale de- 
scritto in questo artico- 
lo è reperibile presso il 
sito: 

http://www.areasx.com 

Dal sito è possibile al- 
tresì acquistare il mo- 
dulo RCM2200, la demo 
board SX01 e il develop- 
ment kit, quest'ultimo 
per lo sviluppo di appli- 
cazioni in linguaggio C. 



http: //www. itportal.it 



3 ►►► 63 



Gli Exploit della progra 



azione ► ► ► ► ► ► ► 



Non c'è 

PASSWORD CHE TENGA! 



L'exploit di questo mese riguarda un problema di sicurezza che affligge 
alcuni modelli di router ADSL della Telindus (www.telindus.com) e della 
Arescom (www.arescom.com), che sembrano gestire le password di 
accesso con troppa leggerezza. 



Premettiamo che non si tratta di un 
vero e proprio "exploit" di program- 
mazione (non c'è un codice da com- 
pilare), ma è comunque interessante studia- 
re questa lacuna di sicurezza, per approfon- 
dire le conoscenze sui pacchetti di rete e per 
esercitare un po' di crittoanalisi. I prodotti 
affetti dal problema sono la serie Telindus 
112x e Arescom NetDSL 1000: si tratta di rou- 
ter per connessioni ADSL, dotati di un 
hub/switch interno, accessibili e configura- 
bili via TCP /IP mediante una utility di 
amministrazione remota proprietaria. L'ex- 
ploit non è realizzabile da remoto, cioè non 
può essere usato da un intruso esterno per 
violare la sicurezza del router, ciò nono- 
stante ritorna molto utile usato dall'interno 
della propria LAN. 

L'OCCORRENTE 

L'exploit richiede Fuso dei seguenti softwa- 



1) Packet Sniffer (prelevabile da Internet). 

2) Telindus 9100 Maintenance Application 

(fornita col router o prelevabile da In- 
ternet). 

Dove e come reperirli? Un packet sniffer è 
un programma capace di intercettare i pac- 
chetti in transito su una interfaccia di rete; è 
un software molto utile per la diagnostica, 
ma, se usato in maniera diversa, è una delle 
armi più potenti in mano agli hacker. Due 
ottimi sniffer per Windows 2000 /XP sono 
Sniff-em (www.sniff-em.com) oppure Sniffer 
XP {www.ufasoft.com), che sono sufficiente- 
mente attrezzati per i nostri scopi. L'utility 
di amministrazione Telindus 9100 MA. è 
invece un programma capace di identifica- 



re un router Telindus presente su una LAN 
e connettersi ad esso per gestirne, mediante 
interfaccia grafica, la configurazione. Que- 
sto programma è in genere fornito col rou- 
ter stesso, ma è anche prelevabile (in via 
non-ufficiale) al link http://www.weethet.nl 
/downloads /Telindus _Local.rar. Una volta pre- 
disposto l'occorrente, può iniziare l'attacco: 
per prima cosa bisogna eseguire lo sniffer e 
metterlo in ascolto sull'interfaccia di rete 
della nostra LAN, quindi lanciare l'applica- 
zione Telindus 9100 MA. e catturare i pac- 
chetti in transito sulla rete. L'indirizzo IP di 
default assegnato al router è in genere quel- 
lo standard 192.168.1.1. 

ANALISI DI 

UN PACCHETTO UDP 

L'exploit prende spunto da queste conside- 
razioni, rilevabili dall'analisi dei pacchetti 
catturati dallo sniffer (Fig. 1): appare evi- 
dente che l'utility di amministrazione 
comunica col router usando il protocollo 
UDP sulla porta 9833; l'utility però non 
conosce a priori l'indirizzo IP assegnato al 
dispositivo; l'unica certezza è che router e 
computer su cui l'utility è in esecuzione si 



□ NetBSUl 

' QTofcenRjno 

□ KM* 

Bn- 
Bue* 

Packeb 



£?$tn4tai W-5frK-X-9e« 
Ptetowi CKWQ 
• ]P 

tare? 192- 164.1-2 
ttetintfci 192.168. 1-2 
Pretowl IJ 

■ Ut*» 

tare? Pere 98» 



F7 Sav* 
(7 Al 



mz 



_E*_J 



Fig. 1: Lo sniffer in azione, non perde 
neanche un pacchetto! 



trovano sulla stessa subnet e hanno quindi 
due indirizzi della forma 192.168.1. x. Come 
fa quindi l'applicazione Telindus 9100 MA. 
a scovare il router? Ricorre ad un semplice 
algoritmo di flooding, che prevede l'invio 
di un pacchetto UDP (discovery packet) in 
broadcast a tutti gli indirizzi IP della rete 
(192.168.1.255); l'unico dispositivo in grado 
di reagire a questo pacchetto sarà il router 
(se presente), che prontamente risponderà 
al mittente, segnalando la sua presenza. 
Questa prima sessione di identificazione 
dura pochi attimi ma è completamente rile- 
vabile seguendo i pacchetti intercettati 
dallo sniffer, che evidenziano, a questo 
punto, l'esistenza di un canale di comuni- 
cazione tra il router (192.168.1.1) e il com- 
puter che sta eseguendo l'utility di ammini- 
strazione remota (ad esempio 192.168.1.2). 

UN PROTOCOLLO NON 
PROPRIO SICURO 

Superata questa prima fase si noterà un 
fatto strano nel momento in cui l'utility di 
amministrazione attende l'immissione 
della password di accesso al router. 
Seguendo l'istinto, la prima cosa che ci 
viene in mente è quella di provare ad entra- 
re con qualche password comune, speran- 
do nell'aiuto della dea bendata, ecco quindi 
un primo tentativo (a vuoto), un secondo. . . 
ma al terzo tentativo notiamo qualcosa di 
strano! Nessun pacchetto, diretto al router, 
viene catturato dallo sniffer durante i tenta- 
tivi di accesso, questo significa una sola 
cosa: l'utility di amministrazione conosce la 
password ed esegue la verifica in memoria 
e non via rete, come ci saremmo aspettati. 
Quando si tenta l'accesso con una pas- 
sword sbagliata, l'utility di amministrazio- 
ne dovrebbe trasmettere via rete la pas- 



64»*> F e 



http://www.itportal.it 



G I 



sword al router, attendere la verifica (fatta 
dal dispositivo) e ricevere la comunicazio- 
ne dell'esito; tutto ciò in realtà non avviene, 
perché il programma Telindus 9100 M.A. 
non trasmette niente al router, quindi cono- 
sce a priori la password, che evidentemen- 
te gli è stata trasmessa dal router nella ses- 
sione iniziale descritta prima. Basta infatti 
controllare la cronologia dei pacchetti cat- 
turati per scoprirne uno insolito, più lungo 
di tutti gli altri (>200 bytes), che una volta 
analizzato rivela parecchie sorprese. . . 

UN SEMPLICE 

ATTACCO 

CRITTOANALITICO 

Il pacchetto catturato contiene infatti tutti i 
dati del router (vedi Fig. 2): nome del 
dispositivo (evidenziato in verde), serial 
number, versione del firmware e perfino la 
password di accesso (evidenziata in rosso)! 
Una banalità. . . a cui nessuno aveva pensa- 
to, ma che fornisce a chiunque la possibilità 
di entrare nel router! 



CYPHER-TEXT 

0100 00 03 02 00 08 00 00 A2 A3 2B 63 4B 73 23 AB 99 

0110 

0120 SB 7B AB 9B 28 ! > 9 89 91 Bl 82 

0130 42 29 i L Bl 71 81 71 

0140 5)1 t"! DA A3 AB 19 02 53 AB 61 01 95 SI 01 39 ■: : ! 

i 98 00 10 01 

0160 oc- 
caso ...... ' „• „j 1. __> U _'_ J „„ 2j „j U 0U 

DI 80 30 

0190 10 00 10 0A 10 00 00 05 2Ù 00 10 00 00 10 50 00 

01AÙ LO 00 00 0A 30 00 LO 00 00 ÙA A3 00 20 00 00 00 

i 00 0A 88 00 02 10 28 00 02 11 10 00 00 20 40 00 



.."sa. "{«£+□...- 

k{<»C...'r ""*,'+ 
B)jiJbla. a +'.±qni 



Fig. 2: I vecchi firmware del router 
scambiamo pacchetti con la password in 
chiaro. 

Ce da dire che la Telindus tuttavia, messa a 
conoscenza del problema, ha subitoappor- 
tato alcune modifiche al firmware, che nelle 
nuove versioni (6.x) usa un algoritmo crit- 
tografico per cifrare il pacchetto "incrimi- 
nato" e per impedire la lettura della pas- 
sword in chiaro rafforzando la sicurezza 
del router. 

Nel pacchetto crittografato la password 
non è più leggibile. Si può fare qualcosa? Si 
può solo tentare un attacco critto-analitico 
al cifrario, sperando che non usi funzioni 
complesse e confidando nella buona sorte. 
Confrontiamo il payload di un pacchetto in 
chiaro (plain-text) e di uno cifrato (cypher - 
text) per cercare di capire come sono strut- 
turati (Tab. 1). 

I due pacchetti sembrano portare la stessa 
intestazione (i primi 2+3+2 byte), dopo i 
quali inizia la sezione informativa: il byte 
05 (evidenziato in rosso) nel pacchetto in 
chiaro indica la lunghezza del campo 
<nome router> ed è seguito infatti dalla 
stringa "DSL00" . Seguono 3 byte (termina- 



la Telindus 91 TO Ualntsnance Application 



rdindus 9100 Maintenanee Application 



Tiiìdus 9100 Mairtsrufws Àpofcfttion òtìstìsd 1 T*frn*js ADSL RotóHrtrWlgefcl 

You e*n s*ted one «outartindgs ti Ihe ntecfan tatto dnd efcfc Erta I» fjairpjtt tì*t «outMrtsndja If 

yvu ww* Co òetstt ibi mtwfa'viQt on yow locai FKtwafc «art. cfck Dtìrcl 



RoutmrtrkteNaiw | IP Adira | hUC Adira 



CQ60SC12A51F 



| Sania Sufawt 



EftiM [ Dattd [ Eri [ Help [ 



Fig. 3: Ecco come appare l'utility di 
amministrazione del router. 



zione?) e quindi il byte di lunghezza della 
password (OD, sempre in rosso) con la pas- 
sword in chiaro ("1111111111111"). Un attac- 
co di crittoanalisi si basa sulle debolezze 
del cifrario e sulla conoscenza di porzioni 
del testo in chiaro: nel nostro caso Y attacco 
è possibile, perché si conosce il nome del 
router, visto che viene mostrato (Fig. 4) dal- 
l'utility di amministrazione. Nel pacchetto 
di esempio catturato, il nome del router è 
"Telindus ADSL router", lungo 20 byte; a 
partire dal byte Al (lunghezza cifrata) ini- 
zia il campo <nome router>. Non resta che 
scrivere la tavola crittoanalitica, confron- 
tando i byte criptati con i codici ASCII reali 
(Tab. 2). Da una prima analisi appare evi- 
dente che si tratta di un alfabeto di sostitu- 
zioni, un cifrario non difficile da risolvere, 
in cui ogni lettera è associata ad un codice 
(si evince osservando le corrispondenze 
delle lettere "u", "e", "t"); tale codice è uni- 
voco in qualsiasi punto del testo cifrato. Si 
osserva inoltre che tutti i codici nelF alfabe- 
to cifrato, terminano con "B" o con "3" , ad 
eccezione delle lettere finali di parola. 
Abbiamo abbastanza materiale per passare 



System Security 



Type user nanne and pa Maintenance 

Application 



Telindus ADSL Router 



Router Password: p 



Fig. 4: Il nome del router viene mostrato 
dall'utility di manutenzione: è 
questo l'anello debole della sicurezza. 



minatori non sono cifrati), ma bisogna 
ancora scoprire le altre lettere. Costruendo 
l'alfabeto del cifrario, notiamo che "r"=93, 
s="9B", "t"=A3, "u"=AB e così via, con in- 
crementi di 8, facendo eccezione per le let- 
tere di fine parola. È facile scoprire il resto 
della password, ipotizzando 6B="m" e 
9B="s"; l'ultimo carattere, essendo di fine 
parola, avrà un codice cifrato diverso da 
quello standard, ma è comunque facile 
capire che si tratta di una "e" e che la paro- 
la chiave è "mouse". La riuscita dell'attacco 
è legata comunque alla lunghezza del 
campo <nome router>, che deve essere suffi- 
cientemente grande da consentire l'attacco 
crittoanalitico. 

Elia Florio 



Sul Web 



Advidsory sulle insicurezze dei router 
Telindus/ Arescom 

http://www.securiteam.com/security- 
news/5DP0A2K7GY.html 

Tutorial sull'hackeraggio del router 
Telindus/ Arescom 

http://www.weethet.nl/enqlish 
/adsl arescomhacked.asp 



PLAIN-TEXT 




















DSL00... 

.1111111111111.. 

tf£ + cKs#"™ 

.."_a. "{"£ + _...+ 


0100 00 03 00 


01 01 


00 


00 


H-44 53 4C 


30 


30 


01 


01 


00 


0110 H31 31 


31 31 


31 


31 


31-31 31 31 


31 


31 


31 


01 
AB 


02 

99 
2B 


CYPHER-TEXT 








■ A3 2B 63 
7B AB A3 2B 


4B 

90 


73 


23 


0100 00 03 02 


00 08 


00 


00 


0110 02 0A22 


9A 61 


02 


93 


08 


08 


00 









Tab. 1: Confronto fra il payload di un pacchetto in chiaro e di uno cifrato (alcuni byte 
sono marcatori). 



T 


e 


1 


i 


n 


d 


u 


s 




A 


D 


S 


L 




R 


o u t 


e 


r 




■ 


2B 


63 


4B 


73 


23 


■ 


99 


02 


0A 


22 


9A 


61 


02 


93 


7B |A3 


2B 


90 


crypt 


54 


65 


6C 


69 


6E 


64 


75 


73 


20 


41 


44 


53 


4C 


20 


52 


6F 75 74 


65 


72 


plain 


(*) 


(*) 










(*) 


















(*) (*) 


(*) 







Tab. 2: Tavola crittoanalitica per lo studio del cifrario. Si tratta di un 
alfabeto di sostituzione. 



all'attacco della password, che inizia subito 
dopo il terminatore 08 08 00 (Tab. 3). 
Conosciamo due caratteri della password 
("o", "u"), sappiamo che è di 5 byte (i ter- 



Lung. passwd ? 
2B 6B 


o u ? ? 
7B AB 9B 28 


Term. 
08 10 01 



Tab. 3: Conoscendo qualche carattere 
della password, è facile decifrarla tutta. 



http://www.itportal.it 



b b 



3 ►►► 65 




C o r s 



Base***'*-***'*'*'*'*'*' 



JSP 




File sul CD 

\soft\codice 
\codici_jspl3.zip 



Dispense Web 
del corso 

I r& I Diversi approfon- 
\-J | di menti legati alla 
lezione odierna e alle 
precedenti sono reperi- 
bili in Internet, tra le 
dispense Web del cor- 
so. L'URLdi riferimento 
è 

http://www.sauronsoftwa- 
re.it/dispenseweb/jsp/. 



Procedure 

MEMORIZZATE CON JDBC 

Nelle applicazioni Web progettate per lavorare da 
interfaccia verso un database si fa spesso uso di 
procedure memorizzate. Questa lezione illustra gli scopi 
ed i funzionamenti delle procedure memorizzate, 
dimostrando diversi esempi pratici di codice completo. 



Le procedure memorizzate sono delle 
query precompilate. Il loro impiego ha 
due risvolti positivi: il miglioramento 
delle prestazioni e la semplificazione del codice. 
Non tutti i DBMS supportano le procedure me- 
morizzate. Con JDBC è possibile impiegare le 
procedure memorizzate, purché siano imple- 
mentate dal gestore di database sfruttato. 



L'ESEMPIO GUIDA 

Ricollegandoci a quanto già fatto nel corso del- 
la precedente lezione, impiegheremo un databa- 
se di Access come esempio guida. Create un da- 
tabase inizialmente vuoto, quindi inserite al suo 
interno una tabella, nominata Utenti. La struttu- 
ra è riportata di seguito: 

• ID, di tipo Contatore, da impiegare come 
chiave primaria. 

• Nome, di tipo Testo. 

• Cognome, di tipo Testo. 

• Email, di tipo Testo. 

• AnnoNascita, di tipo Numerico. 



ID 


Nome 


Cognome 


Email 


Anno 
Nascita 


1 


Mario 


Rossi 


rossi@tin.it 


1958 


2 


Luigi 


Bianchi 


bianchi@libero.it 1972 


3 


Antonio 


Verdi 


verdi@tiscali.it 


1967 


4 


Franco 


Neri 


(NULL) 


1948 


5 


Vittorio 


Grigi 


(NULL) 


1979 


6 


Massimo 


Gialli 


(NULL) 


1981 



Tab. 1: Tabella popolata con dati arbitrari. 



Popolate la tabella con qualche record arbitrario 
Tab: 1. Come al solito, registriamo un DSN di si- 
stema associato alla base di dati. Scegliamo il 
nome MioDatabase. 



PREPAREDSTATEMENT 

L'interfaccia PreparedStatement, del package java 
.sql, estende la già esaminata Statement. Richia- 
miamo alla memoria le operazioni necessarie 
per interrogare un DBMS, sfruttando l'interfac- 
cia Statement. Per prima cosa, è necessario recu- 
perare un oggetto che implementi tale interfac- 
cia di programmazione. La connessione (un og- 
getto Connection aperto) può fornircelo: 

Statement statement = connection. createStatement(); 

Ottenuto un oggetto Statement, è davvero sem- 
plice interagire con il DBMS, facendo fruttare le 
regole sintattiche di SQL: 

ResultSet resultset = statement. executeQuery 

(QUERY_SQL); 

L'impiego di PreparedStatement è simile, ma non 
del tutto identico. Una PreparedStatement è una 
query SQL precompilata. Al momento della 
creazione dell'oggetto, è già necessario specifi- 
care il testo dell'interrogazione che si intende 
sottomettere al DBMS: 

PreparedStatement statement = 

connection. prepareStatement(QUERY_SQL); 

Giacché il testo della query è fornito nel mo- 
mento stesso in cui l'oggetto PreparedStatement è 
richiesto al gestore della connessione, non è più 
necessario passare un'istruzione SQL al metodo 
executeQuery (). Per ottenere i risultati ricercati, 



66^^ F e 



http: //www. itportal.it 



quindi, sarà sufficiente digitare: 

ResultSet resultset = statement. executeQuery(); 

Impiegando il database di Access allestito in 
precedenza, verifichiamo le affermazioni con 
l'esempio completo (lezione 13_01_01.jsp) che 
trovate nello zip presente nel CD. 
Quali vantaggi può avere un approccio del ge- 
nere rispetto a quello esaminato nel corso della 
lezione precedente? Come anticipato in apertu- 
ra, è possibile riscontrare due aspetti significati- 



1. L'incremento delle prestazioni. 

2. La maggiore semplicità del codice. 

Con l'esempio lezione 13_01.jsp, ad ogni modo, 
non è possibile riconoscere immediatamente 
questi due aspetti. Le procedure memorizzate 
forniscono reali vantaggi, infatti, quando se ne 
fa uso frequente e ripetuto, nel corso della stes- 
sa pagina JSP. Il metodo executeQueryO di una 
PreparedStatement può essere richiamato più di 
una volta nel medesimo documento JSP. Se una 
query deve essere eseguita più di una volta, 
quindi, l'interfaccia PreparedStatement permette 
di non dover digitare due volte la stessa stringa 
(= maggiore semplicità del codice). 
Non solo: le query SQL sottoposte al DBMS me- 
diante l'interfaccia PreparedStatement sono pre- 
compilate al momento della loro creazione (= 
incremento delle prestazioni). Nonostante que- 
sto, è improbabile che una stessa query debba 
essere eseguita più di una volta all'interno dello 
stesso frammento di codice. È più frequente che 
si debbano eseguire più query simili, ma non 
del tutto identiche. 

Ad esempio, se volessimo prima un elenco di 
tutti gli utenti nati dopo il 1970 e poi una lista di 
quelli nati dopo il 1980, dovremmo escogitare 
ed eseguire due istruzioni assai simili, eppure 
significativamente differenti: 

SELECT * FROM Utenti WHERE AnnoNascita >= 1970 
SELECT * FROM Utenti WHERE AnnoNascita >= 1980 

Con JDBC, è possibile eseguire ambo le query 
attraverso una sola PreparedStatement parame- 
trizzata: 

PreparedStatement statement = 

connection. prepareStatement( 
"SELECT * FROM Utenti WHERE AnnoNascita >= ?"); 

Osservando questa sintassi, il parametro di se- 
lezione collegato all'anno di nascita dell'utente 
non viene specificato nel momento della pre- 



compilazione dell'interrogazione. Sarà necessa- 
rio aggiungerlo in seguito, prima di eseguire la 
query, sfruttando i metodi del tipo setTipoDatoO. 
Ad esempio, nel nostro caso, potremo agire co- 
me segue: 

statement.setlnt(l, 1970); 

ResultSet resultset = statement.executeQueryQ; 

//■■■ 

statement.setlnt(l, 1980); 

resultset = statement. executeQueryO; 

Passiamo in rassegna un esempio completo, che 
soddisfa la richiesta ipotizzata in precedenza, si 
tratta del file lezione 13_02.jsp. 
Specificare i singoli parametri di una Prepared- 
Statement è molto semplice. I metodi a disposi- 
zione sono tutti del tipo: 

statement. setTipoDato(numeroParametro, 

valoreParametro); 

Tra i metodi disponibili, è importante annovera- 
re i seguenti: 

• setBooleandnt n, boolean p) 

• setBytednt n, byte p) 

• setDatednt n, Date p) 

• setDoublednt n, doublé p) 

• setFloatdnt n, float p) 

• setlntdnt n, int p) 

• setLongdnt n, long p) 

• setShortdnt n, short p) 

• setStringdnt n, String p) 

Nella documentazione ufficiale di Java potrete 
trovare maggiori informazioni su questa fami- 
glia di metodi. Più parametri possono essere 
usati simultaneamente, in una stessa Prepared- 
Statement. 
Ad esempio: 

PreparedStatement statement = 

connection. prepareStatement("SELECT * FROM Utenti 
WHERE AnnoNascita BETWEEN ? AND ?"); 

Per ottenere la lista degli utenti nati tra il 1970 
ed il 1980, a questo punto, bisognerà usare la se- 
quenza di istruzioni: 













nfnl^ 


























1 

Im 




Utenti 




Email Q 


< 








[>] 














Campo: 

Tabella: 

Ordinamento: 

Criteri: 
Oppure: 












- 


ID 




:■";•:' 




,. ■ .-■, ... 






Utenti 




Utenti 

































Is Not Nuli 
























<H 








S 


















JSP 



Parametri NULL 

r^Tl Il metodo setNullQ 
\^J\ permette di impo- 
stare sul valore nullo un 
parametro di una proce- 
dura memorizzata. Il se- 
condo parametro accet- 
tato dal metodo specifica 
il tipo SQL del campo da 
verificare. Ogni tipo sup- 
portato da JDBC è identi- 
ficato da un intero. Non è 
necessario avere una ta- 
bella delle corrisponden- 
ze, giacché la classe java 
.sql.Types fornisce una 
serie di appigli mnemo- 
nici di più semplice im- 
piego. 



Fig. 1: La procedura memorizzata NotNullMail. 



http://www.itportal.it 



b b 



3 ►►► 67 




Valori 
restituiti 

\~r&\ Le procedure me- 
\^y\ morizzate posso- 
no restituire dei valori. 
In tal caso, per poter 
leggere quanto elabo- 
rato, è necessario ri- 
correre alla sintassi: 

CallableStatement 

statement = connec- 
tion. prepareCall( 
"{? = cali NomeProce- 
dura(?, ?, ...)>"); 

Maggiori informazioni 
nella documentazione 
ufficiale ed in letture 
apposite. 



// Imposto il primo parametro. 

statement.setlnt(l, 1970); 

// Imposto il secondo parametro. 

statement.setlnt(2, 1980); 

// Eseguo la query con i parametri correnti. 

ResultSet resultset = statement. executeQuery(); 

Il meccanismo è semplice e di facile compren- 
sione. 



CALLABLESTATEMENT 

Con PreparedStatement, come abbiamo appurato, 
è possibile sfruttare delle istruzioni SQL pre- 
compilate, che garantiscono migliori prestazioni 
e maggiore chiarezza. Le query desiderate sono 
date in pasto al DBMS al momento della crea- 
zione di un oggetto PreparedStatement, e posso- 
no poi essere ripetutamente sfruttate quante 
volte si desidera. 



rS 


rifalla 
















1 








Utenti 




Nome 
Cognome 
Email v 


< 


a 


















Tabella: 
Ordinamento: 

Criteri: 


ID 


Nome 




Email 


AnnoNascita 


" 




Utenti 




Utenti 




Utenti 





























li'-;'.".-. ' -J 




v 


<H [>l 













Fig. 2: La procedura memorizzata AnnoNascita. 



Tuttavia, JDBC ed il DBMS devono ricompilare 
la medesima istruzione SQL ogni volta che il do- 
cumento JSP è richiesto da un utente. Ad ogni 
richiesta, infatti, corrisponde la creazione di un 
nuovo oggetto PreparedStatement, con tutte le 
conseguenze del caso. Si può fare di meglio, se 
il DBMS lo permette, ottenendo incrementi an- 
cora più significativi sia nelle prestazioni sia 
nella semplicità del codice. L'interfaccia Calla- 
bleStatement estende PreparedStatement, e per- 
mette di richiamare delle procedure memorizza- 
te all'interno del database. 

Una query, con CallableStatement, non deve esse- 
re specificata in linea all'interno del codice della 
pagina JSP, ma può essere memorizzata peren- 
nemente all'interno della base di dati, pronta ad 
essere sfruttata più e più volte, in quante pagine 
si desidera. Ogni DBMS impiega tecniche diffe- 
renti per la preparazione di procedure memo- 
rizzate. Sotto Access, ad esempio, è possibile 
servirsi di una comoda e semplice interfaccia 
utente. 

Riprendiamo il database sfruttato per gli esem- 
pi precedenti e dotiamolo di una procedura me- 
morizzata: 

1. Aprendo il database con Access, attiviamo la 
linguetta laterale nominata "Query". 



2. Avviamo la procedura "Crea una query in vi- 
sualizzazione struttura ". 

3. Selezioniamo la tabella Utenti come sorgente 
di dati. 

4. Nell'elenco disponibile, facciamo in modo 
che tutti i campi della tabella siano selezio- 
nati e restituiti (se non siete pratici di Access, 
fate riferimento alla Fig. 1). 

5. Sotto la colonna associata al campo Email, al- 
la voce "Criteri " , introduciamo la limitazione 
"IsNotNull". 

6. Salviamo la query generata con il nome Not- 
NullMail. 

Tramite questi passi, è stata memorizzata una 
query del tipo: 

SELECT 

IP, Nome, Cognome, Email, AnnoNascita 

FROM 

Utenti 

WHERE 

Email IS NOT NULL 

il cui scopo è restituire l'elenco di tutti gli uten- 
ti di cui è noto l'indirizzo e-mail. Adesso è pos- 
sibile richiamare la query NotNullMail diretta- 
mente da JSP: 

// Ottengo un oggetto CallableStatement che richiama 

// la procedura memorizzata NotNullMail. 

CallableStatement statement = connection. prepareCall( 

"{cali NotNullMail}" ); 

// Eseguo la query. 

ResultSet resultset = statement. executeQuery(); 

Desumerne un esempio funzionante è semplice, 
come potrete verificare visualizzando il file: le- 
zionel3_03.jsp. Il codice HTML prodotto in out- 
put mostrerà il risultato di Tab. 2. 



Nome 


Cognome 


Email 


AnnoNascita 


Mario 


Rossi 


rossi@tin.it 


1958 


Luigi 


Bianchi 


bianchi@libero . it 


1972 


Antonio 


Verdi 


verdi@tiscali.it 


1967 



Tab. 2: Risultato dell'esecuzione del codice 
"lezione 13_03.jsp". 



Anche una CallableStatement può sfruttare uno o 
più parametri. Andiamo a dimostrare un esem- 
pio di questo tipo. 

Tornando ad Access, realizziamo una nuova 
procedura memorizzata, chiamata AnnoNascita 
(Fig. 2). 



68^^ F e 



http: //www. itportal.it 



Come nel caso precedente, selezioniamo la ta- 
bella Utenti e trasportiamo tutti i campi dispo- 
nibili. 

Il criterio di restrizione, questa volta, lo appli- 
chiamo al campo AnnoN uscita, con il codice: 

Between [min] And [max] 

Questa query, sostanzialmente, corrisponde alla 
PreparedStatement già esaminata in precedenza: 

SELECT * FROM Utenti WHERE AnnoNascita BETWEEN ? AND ? 

Potrà essere richiamata alla seguente maniera: 

CallableStatement statement = connection. prepareCall( 
"{cali AnnoNascita(?, ?)}"); 

I parametri potranno essere impostati come di 
consueto: 

statement.setlnt(l, estremolnferiore); 

statement. setlnt(2, estremoSuperiore); 

L'intero codice che se ne desume è riportato di 
seguito: 

<%@ page import="java.sql.*" %> 

<%! 

// Nome del driver. 

String DRIVER = "sun.jdbc.odbc.JdbcOdbcDriver"; 

// Indirizzo del database. 

String DBJJRL = "jdbc:odbc:MioDatabase"; 

%> 

<html> 

<head> 

<title>Corso di JSP, Lezione 13, Esempio 4</title> 

</head> 

<body> 

<% 

// Carico il driver. 

Class.forName(DRIVER); 

// Preparo il riferimento alla connessione. 

Connection connection = nuli; 

try { 

// Apro la connesione verso il database. 

connection = DriverManager.getConnection(DB_URL); 
// Ottengo un oggetto CallableStatement che richiama 

// la procedura memorizzata AnnoNascita. 

CallableStatement statement = 
connection.prepareCall( "{cali AnnoNascita(?, ?)}" ); 

// Specifico i parametri. 

statement.setlnt(l, 1970); 

statement.setlnt(2, 1980); 

// Eseguo la query. 

ResultSet resultset = statement.executeQueryQ; 

%> 

<table border="l"> 

<tr> 



<tdxb>Nome</bx/td> 

<td><b>Cognome</bx/td> 

<tdxb>E-mail</bx/td> 

<tdxb>AnnoNascita</bx/td> 

</tr> 

<% 

// Scorro e mostro i risultati. 

while (resultset.nextQ) { 

String nome = resultset.getString("Nome"); 
String cognome = resultset. getString("Cogno- 

me"); 

String email = resultset.getString("Email"); 

boolean emailIsNull = resultset.wasNullQ; 

int anno = resultset.get!nt("AnnoNascita"); 

%> 

<tr> 

<td><%= nome %x/td> 

<tdx%= cognome %x/td> 

<td> 

<% if (lemailIsNull) { %> 

<a href="mailto:<%= email %>"><%= email 

%></a> 

<% } else { %> 

N.D. 

<% } %> 

</td> 

<tdx%= anno %x/td> 

</tr> 

<% 

} 

%> 

</table> 

<% 

} catch (SQLException e) { 

// In caso di errore. .. 

%xb>Eccezione:</b> <%= e.toStringQ %><% 

} finally { 

if (connection != nuli) connection.closeQ; 

_} 

%> 

</body> 

</html> 

L'output restituito comprenderà la Tab. 3. 



Nome Cognome 


Email AnnoNascita 


Luigi Bianchi 


bianchi@libero.it 1972 


Vittorio Grigi 


(NULL) 1979 



Tab. 3: Output restituito dal codice "lezione 
13_04.jsp". 



CONCLUSIONI 

Con questa lezione si conclude la panoramica 
che questo corso dedica all'impiego di JDBC. 
Eventuali approfondimenti possono essere 
svolti sfruttando la documentazione ufficiale di 
Java o dei manuali specifici per JDBC e SQL. 

Carlo Pelliccia 




Bibliografia 



• JSP, LA GUIDA COM- 
PLETA 

Phil Hanna 

(McGraw-Hill) 

ISBN 88-386-4207-9 

2001 

• IMPARARE JAVASER- 
VER PAGES IN 24 ORE 
Jose Annunziato, 
Stephanie Fesler 
Kaminaris 
(Tecniche Nuove) 
ISBN 88-481-1306-0 
2001 

• JAVA, LA GUIDA 
COMPLETA 
Patrick Naughton & 
Herbert Schiidt 
(McGraw-Hill) 
ISBN 88-386-0416-9 
1997 

• JAVA 2, TUTTO 
& OLTRE 
Jamie Jaworski 
(Apogeo) 

ISBN 88-7303-466-7 
1999 



http://www.itportal.it 



b b 



2 3 ►►► 69 




Le finestre 



Visual Basic DI DIALOGO 

NET 




Le proprietà di 
OpenFileDialog 



j% ADDEXTENSION, 
^s\ indica se viene ag- 
giunto automaticamen- 
te un'estensione ad un 
nome di file quando l'u- 
tente non la inserisce. 
CHECKFILEEXISTS, in- 
dica se nella finestra di 
dialogo viene visualiz- 
zato un avviso quando 
l'utente specifica un 
nome di file inesistente. 
CHECKPATHEXISTS, in- 
dica se nella finestra di 
dialogo viene visualiz- 
zato un avviso quando 
l'utente specifica un 
percorso inesistente. 
DEFAULTEXT, indica l'e- 
stensione del file prede- 
finita. 

DEREFERENCELINKS, 
indica se la finestra di 
dialogo restituisce la 
posizione del file a cui fa 
riferimento il collega- 
mento o se restituisce la 
posizione del collega- 
mento. 

FILENAME, contiene il 
nome del file seleziona- 
to nella finestra di dialo- 
go. È una proprietà a so- 
la lettura. 

FILENAMES, contiene i 
nomi di tutti i file sele- 
zionati nella finestra di 
dialogo. È una proprietà 
a sola lettura. 
FILTER, indica la stringa 
filtro del nome file cor- 
rente, che stabilisce le 
opzioni visualizzate nel- 
le casella relative al tipo 
di file nella finestra di 
dialogo. 




In questo nuovo appuntamento parleremo delle piccole 
finestre che appaiono sullo schermo per interagire con 
l'utente e recuperare informazioni. 



Le finestre di dialogo forniscono la consueta inter- 
faccia utente presente nelle applicazioni Win- 
dows utilizzata per mostrare dei messaggi, op- 
pure per richiedere all'utente dati necessari all'applica- 
zione. VB.NET fornisce molte finestre di dialogo stan- 
dard che è possibile adattare alle applicazioni, ad 
esempio la finestra Apri, rappresentata dal controllo 
OpenFileDialog, oppure la finestra di Stampa rappresen- 
tata dal controllo PrintDialog e così via. In VB.NET è 
possibile, inoltre, progettare finestre di dialogo com- 
pletamente personalizzate in base ad esigenze partico- 
lari. Una finestra di dialogo, in pratica, non è altro che 
una form modale con un insieme di controlli (tipica- 
mente Label, Textbox e Button), la cui proprietà Form- 
BorderStyle è impostata su FixedDialog. 

CREARE UNA FINESTRA 
DI DIALOGO DA ZERO 

Per descrivere come realizzare una finestra di dialogo 
personalizzata, realizziamo una semplice applicazione 
d'esempio per il calcolo dell'area di un rettangolo 
(rileggetevi l'articolo di Ottobre per notare le differen- 
ze). Come di consueto creiamo un nuovo progetto, dal 
nome Calcolo Area e modifichiamo il nome di Formi in 
Form Area. Nella finestra Form Area inseriamo un Button 
dal nome ButtonCalcola. Quando l'utente clicca sul pul- 
sante verrà mostrata una prima finestra di dialogo in 
cui verrà chiesto di inserire il valore della base del ret- 
tangolo, una seconda finestra di dialogo in cui verrà 
chiesto di inserire il valore dell'altezza del rettangolo, 
ed infine una terza finestra di dialogo che mostrerà il 
risultato del calcolo. Per creare la prima finestra di dia- 
logo si deve aggiungere un form al progetto e modifi- 
carne alcune proprietà, i passi da seguire saranno: 

• Selezionare la voce: Progetto /Aggiungi Windows 
Form. 

• Digitare il nome della finestra (FormDialogoBase) 
nella casella di testo Nome. 

• Cliccare sul pulsante Apri. 

• Visualizzare la finestra delle proprietà della form in 
cui modificare le seguenti proprietà per personaliz- 
zarne l'aspetto: 



70»> F e b b 



• FormBorderStyle in FixedDialog. 

• MinimizeBox e MaximizeBox su false, poiché le 
finestre di dialogo in genere non includono 
pulsanti di riduzione ad icona e di ingrandi- 
mento. 

Le finestre di dialogo vengono visualizzate come fine- 
stre modali, e cioè, come finestre a scelta obbligatoria, 
che impediscono all'utente di eseguire operazioni al di 
fuori della finestra di dialogo. Per visualizzare una fi- 
nestra come modale, si deve utilizzare il metodo Show- 
Dialog (descritto nei numeri precedenti) pertanto si de- 
ve scrivere il codice seguente: 

Private Sub ButtonCalcola_Click(ByVal sender As 

System. Object, ByVal e As System. EventArgs) Handles 

ButtonCalcola.Click 

Dim FBase As New FormBaseQ 

FBase.ShowDialogQ 

End Sub 

La finestra FormBase viene utilizzata per richiedere 
all'utente di inserire i dati relativi alla base del rettan- 
golo, quindi è importante sapere in che modo viene 
chiusa tale finestra, in altre parole se ha prodotto un 
risultato. Se ad esempio l'utente chiude la finestra dalla 
crocetta in alto a destra, i dati inseriti non vengono 
memorizzati ma eliminati. Per verificare come viene 
chiusa una finestra di dialogo si può utilizzare la pro- 
prietà DialogResult. In fase di progettazione è possibile 
impostare la proprietà DialogResult per tutti i controlli 
Button presenti nella finestra di dialogo. Nella finestra 
FormBase inseriamo una Label, un TextBox e due pul- 
santi. Visualizziamo la finestra delle proprietà e varia- 
mo le proprietà dei controlli appena disegnati: 

• Selezionando Labell variamo la proprietà Text in 
Base. 

• Selezionando TextBoxl variamo la proprietà Name 
in TextBoxBase e la proprietà Text nella stringa 
vuota. 

• Selezionando Buttonl variamo la proprietà Name in 
ButtonOk, la proprietà Text in Ok e la proprietà 
DialogResult in OK. 

http://www.itportal.it 



• Selezionando Buttonl variamo la proprietà Nume in 
ButtonCancella, la proprietà Text in Cancella e la pro- 
prietà DialogResult in Cancel. 

Dalla finestra (nel nostro caso FormCalcola) che visua- 
lizza la finestra di dialogo, chiamata anche form padre 
della finestra di dialogo, è possibile utilizzare il valore 
della proprietà DialogResult per stabilire se è stato scel- 
to OK o Annulla. 

In base alla proprietà DialogResult restituita si può 
decidere se è necessario recuperare o meno le informa- 
zioni della finestra di dialogo. 

If FBase.DialogResult = DialogResult.OK Then 

base = CDbl(FBase.TextBoxBase.Text) 

Else 

base = 

End If 

In maniera analoga disegniamo la finestra Form Altezza. 
Il risultato dell'operazione di calcolo dell'area del ret- 
tangolo, sarà infine visualizzato in una finestra di dia- 
logo predefinita, utilizzando MessageBox. 

Private Sub ButtonCalcola_Click(ByVal sender As 

System. Object, ByVal e As System. EventArgs) Handles 

ButtonCalcola.Click 

Dim base As Doublé 

Dim altezza As Doublé 

Dim risultato As Doublé 

Dim FBase As New FormBaseQ 

FBase. ShowDialogQ 

If FBase.DialogResult = DialogResult.OK Then 
base = CDbl(FBase.TextBoxBase.Text) 

Else 

base = 

End If 

Dim FAItezza As New FormAltezzaQ 

FAItezza.ShowDialogQ 

If FAItezza.DialogResult = DialogResult.OK Then 
altezza = CDbl(FAItezza.TextBoxAltezza.Text) 

Else 

altezza = 

End If 

risultato = base * altezza 

MessageBox.Show(risultato) 

End Sub 

LA FINESTRA 

DI DIALOGO MESSAGEBOX 

La finestra di dialogo MessageBox è senza dubbio quel- 
la che vi troverete ad utilizzare più spesso. Questa fine- 
stra permette di mostrare messaggi personalizzati 
all'utente, ed è in grado di accettare scelte tramite uno 
o più pulsanti. Normalmente è composta da quattro 
parti: 



• La barra del titolo che identifica lo scopo della fine- 
stra di dialogo, ad esempio "Richiesta Conferma' . 

• Il messaggio che appare nella finestra, ad esempio 
"Sei sicuro di voler continuare?" 

• Un'icona in grado di attirare l'attenzione, ad esem- 
pio l'icona con il punto di domanda. 

• Uno o più pulsanti di comando, ad esempio i pul- 
santi Si e No. 

Per visualizzare la finestra di messaggio, si deve utiliz- 
zare il metodo Show. Il metodo Show può essere richia- 
mato in più modi, riportiamo di seguito la sintassi di 
quelli più comuni: 

MessageBox.Show(testo) 

MessageBox.Show(testo, etichetta) 

MessageBox.Show(testo, etichetta, bottone, icona) 

MessageBox. Show(testo, etichetta, bottone, icona, 

bottoneDiDefault) 

In cui: 

• testo - rappresenta il messaggio che verrà visualiz- 
zato air interno della finestra di dialogo. Può essere 
una qualsiasi stringa ed è l'unico parametro obbli- 
gatorio. 

• etichetta - rappresenta la stringa visualizzata nella 
barra del titolo della finestra. Se viene omesso, 
nella barra del titolo non apparirà nessun testo. 

• bottone - permette di visualizzare uno o più pul- 
santi, tra quelli disponibili, nella finestra di dialogo. 
Se viene omesso, verrà visualizzato il bottone OK. 

• icona - permette di visualizzare un'icona, tra quel- 
le disponibili, nella finestra di dialogo. Se viene 
omesso, non verrà visualizzata nessun'icona. 

• BottoneDiDefault - permette di specificare quale 
pulsante, tra quelli visualizzati, verrà impostato 
come predefinito. L'uso di questo parametro, con- 
sente all'utente di leggere il messaggio e di preme- 
re il tasto Invio per indicare l'azione del pulsante 
predefinito. 

Analizziamo ora i possibili valori per bottone, icona e 
BottoneDiDefault. Le icone che si possono visualizzare 
nella finestra MessageBox sono: 

• Asterisk, Information - consentono di visualizzare 
un'icona contenente un simbolo formato da una 
lettera i minuscola racchiusa da un fumetto. 

• Error, Hand, Stop - consentono di visualizzare 
un'icona contenente un simbolo formato da una X 
bianca racchiusa da un cerchio su sfondo rosso. 

• Exclamation, Warning - consentono di visualizza- 
re un'icona contenente un simbolo formato da un 
punto esclamativo racchiuso da un triangolo su 
sfondo giallo. 

• Question - consente di visualizzare un'icona con- 
tenente un simbolo formato da un punto interroga- 
tivo racchiuso da un fumetto. 




Visual Basic 

.NET 




Altre proprietà 
OpenFileDialog 



a: 



I FILTERINDEX, in- 
| dica l'indice del 
filtro attualmente sele- 
zionato nella finestra di 
dialogo. 

INITIALDIRECTORY, 
Indica la directory ini- 
ziale visualizzata dalla 
finestra di dialogo. 
MULTISELECT, ottiene o 
imposta un valore che 
indica se la finestra di 
dialogo consente la se- 
lezione multipla di file. 
READONLYCHECKED, 
ottiene o imposta un 
valore che indica se è 
selezionata la casella di 
controllo di sola lettura. 
RESTOREDIRECTORY, 
indica se la finestra di 
dialogo ripristina la di- 
rectory corrente prima 
della chiusura. 
SHOWHELP, indica se 
viene visualizzato il pul- 
sante di help nella fine- 
stra di dialogo. 
SHOWREADONLY, indi- 
ca se la finestra di dia- 
logo contiene una ca- 
sella di controllo di sola 
lettura. 

TITLE, indica il titolo 
della finestra di dialogo 
che viene visualizzato 
nella barra del titolo. 




http://www.itportal.it 



3 ►►► 71 




C o r s 



B a s e ► ► ► ► 



Visual Basic 

.NET 




Alcune 

proprietà 

di ColorDialog 



VyW\ ALLOWFULLOPEN 
\-J\ indica se l'uten- 
te può utilizzare la fi- 
nestra di dialogo per 
definire colori perso- 
nalizzati. 

AIMYCOLOR, indica se 
nella finestra di dialo- 
go sono visualizzati 
tutti i colori disponi- 
bili nel set di colori di 
base. 

COLOR CONSENTE, di 
ottenere o impostare 
il colore selezionato 
dall'utente. 
CUSTOMCOLORS, 
indica il gruppo di co- 
lori personalizzati vi- 
sualizzato nella fine- 
stra di dialogo. 
FULLOPEN, indica se i 
controlli utilizzati per 
creare colori perso- 
nalizzati sono visua- 
lizzati all'apertura 
della finestra di dia- 
logo. 

SOLIDCOLORONLY, 
indica se nella fine- 
stra di dialogo la 
scelta sarà consenti- 
ta soltanto ai soli co- 
lori in tinta unita 



Le combinazioni di pulsanti che si possono visualizza- 
re nella finestra MessageBox sono: 

• AbortRetrylgnore - indica che la finestra di mes- 
saggio contiene i pulsanti Interrompi, Riprova ed 
Ignora. 

• OK - indica che la finestra di messaggio contiene il 
pulsante OK. 

• OKCancel - indica che la finestra di messaggio 
contiene i pulsanti OK ed Annulla. 

• RetryCancel - indica che la finestra di messaggio 
contiene i pulsanti Riprova ed Annulla. 

• YesNo - indica che la finestra di messaggio contie- 
ne i pulsanti Sì e No. 

• YesNoCancel - indica che la finestra di messaggio 
contiene i pulsanti Sì, No ed Annulla. 

Quando l'utente preme uno dei tasti riportati nella fi- 
nestra di dialogo, viene valorizzata la proprietà Dialog- 
Result corrispondente. I valori ammessi, per indicare 
che un pulsante di una finestra MessageBox è quello 
predefinito, sono: 

• DefaultButtonl - indica che il primo pulsante 
nella finestra messaggio deve essere il pulsante 
predefinito. 

• DefaultButton2 - indica che il secondo pulsante 
nella finestra messaggio deve essere il pulsante 
predefinito. 

• Def aultButton3 - indica che il terzo pulsante nella 
finestra messaggio deve essere il pulsante predefi- 
nito. 

Il pulsante predefinito prescelto viene valorizzato in 
ordine da sinistra verso destra. Se avete visualizzato i 
pulsanti AbortRetrylgnore ed impostate il valore di Bot- 
toneDiDefault su DefaultButton3, allora il pulsante pre- 
definito sarà il pulsante Ignora. 

Supponiamo ora di aver scritto un'applicazione che 
salva alcuni dati su database, se l'utente distratto 
chiude il programma prima di aver salvato effettiva- 
mente i dati è bene avvisarlo. 

In questo caso possiamo scrivere il codice seguente 
che visualizza il messaggio di avviso riportato in figu- 
ra: 

If MessageBox. Show("Vuoi salvare i dati prima di uscire ?", 

"Richiesta Conferma", MessageBoxButtons. YesNo- 
Cancel, MessageBoxIcon.Question, MessageBoxDefault- 
Button.Button3) = DialogResult.No Then Exit Sub 

I CONTROLLI 
FINESTRE DI DIALOGO 

VB.NET mette a disposizione alcuni controlli che per- 
mettono di visualizzare finestre di dialogo standard, 
per utilizzarli all'interno della vostra applicazione si 
deve selezionare il controllo prescelto nella casella 
degli strumenti e trascinarlo sulla form (al solito essen- 



do un controllo invisibile in fase di esecuzione verrà 
mostrato nella barra delle componenti). 
In particolare descriveremo i seguenti controlli finestre 
di dialogo standard: 

• OpenFileDialog - consente di aprire un file. 

• SaveFileDialog - consente di selezionare un file da 
salvare e la posizione in cui deve essere salvato. 

• ColorDialog - consente di selezionare o aggiunge- 
re un colore da una tavolozza predefinita. 

• FontDialog - consente di selezionare un tipo di 
carattere tra quelli installati nel sistema. 

• PrintDialog - consente di selezionare una stam- 
pante e le pagine da stampare. 

• PageSetupDialog - consente di impostare i detta- 
gli di una pagina per la stampa. 

Per visualizzare una finestra di dialogo standard, si de- 
ve utilizzare il metodo ShowDialog, così come si è visto 
in precedenza. 

Ad esempio nel caso di un controllo OpenFileDialog 
(dal nome OpenFileDialog!) si deve scrivere: 

OpenFileDialog l.ShowDialog() 

Anche le finestre di dialogo standard restituiscono la 
proprietà DialogResult. Ad esempio nel caso di un con- 
trollo OpenFileDialog, la proprietà DialogResult restitui- 
sce i valori Ok o Cancel che corrispondono, rispettiva- 
mente, ai pulsanti Apri e Annulla della finestra di dia- 
logo. 

L'utilizzo di questi controlli evita la necessità di scrive- 
re codice per implementare il disegno dell'interfaccia, 
ma resta sempre a carico del programmatore la scrittu- 
ra del codice. 

Il controllo OpenFileDialog 

La finestra di dialogo Apri permette agli utenti di navi- 
gare tra le cartelle del proprio computer locale o di 
qualsiasi computer in rete e di selezionare un file da 
aprire. La finestra di dialogo restituisce il percorso 
completo ed il nome del file selezionato nella finestra. 
Il controllo non apre e legge un file, ma è semplice- 
mente un'interfaccia che permette ad un utente di indi- 
viduare e specificare il file che l'applicazione deve 
aprire. È possibile utilizzare la proprietà Filterlndex per 
impostare l'estensione dei file che sarà possibile visua- 
lizzare, ad esempio soltanto i file testo con estensione 
.TXT. La stringa che definisce il filtro è composta da 
due elementi separati da una barra verticale (per inten- 
derci il simbolo che si trova di solito di fianco al tasto 
"1"), l'etichetta che appare nella casella di riepilogo 
Tipo File ed il filtro stesso. 

Se ad esempio si vuole permettere la visualizzazione 
dei file di tipo testo con estensione *.txt 

Text files (*.txt)|*.txt 

Si possono anche definire dei filtri multipli, in questo 



72^^^ F e b b 



http://www.itportal.it 



caso ogni filtro deve essere separato dalla barra verti- 
cale: 

Files di testo (*.txt)|*.txt| Tutti i files (*.*)|*.* 

In caso di filtri multipli, per definire il filtro visualizza- 
to di default si deve impostare la proprietà Filterlndex 
ponendola uguale all'indice numerico del filtro desi- 
derato, nel caso precedente si deve impostare Filter- 
lndex pari ad 1 oppure a 2. Per stabilire quale file è stato 
selezionato dall'utente si deve utilizzare la proprietà 
FileName, che memorizza il nome del file preceduto dal 
percorso completo in cui si trova. Se l'utente clicca sul 
tasto Annulla la proprietà FileName sarà pari alla strin- 
ga vuota "" . 

Il controllo SaveFileDialog 

La finestra di dialogo Salva con Nome assomiglia molto 
alla finestra Apri. Le uniche differenze risiedono nelle 
etichette e nella barra del titolo, dove al posto del testo 
apri viene visualizzato il testo Salva. Anche per questo 
controllo è possibile definire dei filtri sull'estensione 
del file da salvare con le stesse modalità del controllo 
OpenFileDialog. Le uniche differenze stanno nella pre- 
senza di altre proprietà come ad esempio la proprietà 
CreatePrompt o OverwritePrompt che poste a True visua- 
lizzano un messaggio nel caso venga creato un nuovo 
file o si sovrascriva un file esistente. Naturalmente il 
controllo non salva il file in automatico. 

Il controllo ColorDialog 

Il controllo ColorDialog permette di visualizzare la fine- 
stra di dialogo Colore che consente all'utente di selezio- 
nare un colore o di crearne di personalizzati. Quando 
l'utente chiude la casella di dialogo, il colore seleziona- 
to viene memorizzato nella proprietà Color. 




.olore Minta r 

unita Luminosità: 



OK | Annulla | 



Aggiungi ai colori personalizzati 



Fig. 1: Finestra di dialogo per la selezione di un 
colore. 

Ad esempio si può assegnare il colore selezionato alla 
proprietà ForeColor o BackColor di un altro controllo (ad 
esempio un TextBox) 

TextBoxl. ForeColor = ColorDialogl. Color 

La matrice CustomColor contiene tutti i colori perso- 
nalizzati definiti dall'utente. 



Il controllo FontDialog 

Il controllo FontDialog permette di visualizzare la fine- 
stra di dialogo Carattere che consente all'utente di sele- 
zionare diversi caratteri, stili e dimensioni. Ogni volta 
che l'utente seleziona un'opzione, questa finestra vi- 
sualizza una casella di anteprima con il carattere cor- 
rispondente alle scelte effettuate. 
Per recuperare le scelte effettuate dall'utente il con- 
trollo FontDialog espone le proprietà: 

• MinSize - ottiene o imposta la dimensione mini- 
ma selezionabile da un utente, espressa in punti. 

• MaxSize - ottiene o imposta la dimensione mini- 
ma selezionabile da un utente, espressa in punti. 

• FontMustExist - indica se nella finestra di dialogo 
viene descritta una condizione di errore quando 
l'utente cerca di selezionare un tipo di carattere o 
uno stile inesistente. 

• ShowEffects - ottiene o imposta un valore che 
indica se nella finestra di dialogo sono inclusi con- 
trolli che consentono all'utente di specificare 
opzioni di testo quali il barrato, la sottolineatura e 
il colore. 

• AllowVerticalFonts - ottiene o imposta un valore 
che indica se nella finestra di dialogo sono visua- 
lizzati sia tipi di carattere verticali sia orizzontali 
oppure soltanto orizzontali. 

• AllowVectorFonts - ottiene o imposta un valore 
che indica se la finestra di dialogo consente di 
selezionare tipi di carattere vettoriali. 

Ed infine la proprietà Font, che imposta o restituisce il 
font selezionato. 

Il controllo PrintDialog 

Il controllo PrintDialog permette di visualizzare la 
finestra di dialogo Stampa che consente all'utente di 
selezionare la stampante, il numero di copie e le pagi- 
ne da stampare. Prima di utilizzare il controllo Print- 
Dialog, è necessario inserire nella form il controllo 
PrintDocument ed associarlo al controllo PrintDialog 
tramite la proprietà Document (cliccando sulla freccia 
rivolta verso il basso accanto alla proprietà apparirà 
l'elenco degli oggetti PrintDocument selezionabili). 
L'oggetto PrintDocument espone la proprietà Docu- 
mentarne che "informa" la finestra di dialogo Stampa 
quale documento deve essere stampato. 

Il controllo PageSetupDialog 

Il controllo PageSetupDialog permette di visualizzare la 
finestra di dialogo Imposta pagina che consente all'u- 
tente di stabilire l'orientamento della pagina (verticale 
o orizzontale), le dimensioni del foglio e le dimensio- 
ni per i quattro margini della pagina. Anche in questo 
caso, prima di utilizzare il controllo PageSetupDialog, è 
necessario inserire nella form il controllo PrintDocu- 
ment ed associarlo al controllo PageSetupDialog trami- 
te la proprietà Document. 

Ing. Luigi Buono 




Visual Basic 

.NET 



MSG Box 



Ó 



Un metodo alter- 
nativo per visua- 
lizzare le finestre di 
messaggio è l'utilizzo 
del comando MsgBox. 
Il comando MsgBox 
era il comando utiliz- 
zato in VB6 che è 
stato conservato an- 
che in VB.NET. Le fi- 
nestre messaggio pro- 
dotte utilizzando Msg- 
Box appaiono identi- 
che a quelle scritte 
con MessageBox, la 
differenza è tutta nel- 
la scrittura del codice. 
La sintassi è la se- 
guente: 

MsgBox(testo, 
setDibottoni, etichetta) 

I parametri testo ed 
etichetta visualizzano 
il messaggio ed il tito- 
lo, così come in Mes- 
sageBox, il parametro 
set Di Bottoni ammette, 
invece, una combina- 
zione dei parametri: 
bottone, icona e bot- 
toneDiDefault separati 
dal segno più (+). Per 
visualizzare il messag- 
gio di esempio ripor- 
tato nell'articolo, uti- 
lizzando MsgBox si de- 
ve scrivere: 

MsgBox("Vuoi salvare i 

dati prima di uscire ?", 

MsgBoxStyle.YesNoCancel 

+ MsgBoxStyle.Question 

+ MsgBoxStyle 

.DefaultButton3, 

"Richiesta Conferma") 



http://www.itportal.it 



3 ►►► 73 




Passaggio 

DI ARGOMENTI, TRE CASI 
PARTICOLARI 

Il passaggio di argomenti ad un metodo, insieme con la 
ricezione dei valori di ritorno, costituisce uno dei 
capisaldi della programmazione orientata agli oggetti, 
tanto con C# quanto con altri linguaggi di 
programmazione. In questa lezione esamineremo tre 
interessanti tecniche messe a disposizione da C#, utili 
per il passaggio di argomenti in situazioni particolari. 



File sul CD 



\soft\codice 
\codici_csharp.zip 



Già abbiamo parlato di metodi e di pas- 
saggio di argomenti, in maniera ele- 
mentare. In questa lezione andremo ad 
approfondire l'argomento, esaminando alcune 
tecniche utili per fornire argomenti in situazio- 
ni particolari. 

Saranno esaminate le tre parole chiave ref, out e 
params. 

PASSAGGIO 

DI ARGOMENTI CON REF 

C#, come è stato già detto nel corso delle pre- 
cedenti lezioni, distingue tra due macro-insie- 
mi di dati: quelli gestiti per valore e quelli am- 
ministrati per riferimento. Il tipo di gestione at- 
tuato dal CLR di .NET costringe a delle rifles- 
sioni, soprattutto nel momento in cui un valore 
è trattato come argomento di ingresso di un 
qualsiasi metodo. 

Riassumendo, i tipi valore sono sempre copiati 
e duplicati, mentre i tipi riferimento utilizzano 
alias differenti per indicare una medesima area 
della memoria. 

Quando un tipo valore, ad esempio un int, è 
usato come argomento di ingresso, il CLR ne 
esegue automaticamente una copia da affidare 
al codice contenuto nel corpo del metodo che lo 
riceve. 

Modificando la copia, l'originale rimane inalte- 
rato. E' possibile variare il comportamento pre- 
definito che l'esecutore assume nei confronti 
dei tipi valore, servendosi della parola chiave 
ref. Prendiamo in esame il seguente esempio: 



class ScambiaVariabili 

{ 

public static void scambiaSenzaRef(int a, int b) 

A 

int aux = a; 

a = b; 

b = aux; 

_} 

public static void scambiaConRef(ref int a, ref int b) 

A 

int aux = a; 

a = b; 

b = aux; 

_} 

public static void mostraValori(int il, int i2) 

A 

System.Console.WriteLine("il vale " + il); 

System.Console.WriteLine("i2 vale " + i2); 

_} 

public static void MainQ 

A 

int il = 5; 

int i2 = 3; 

mostraValori(il, i2); 

scambiaSenzaRef(il, i2); 

System. Console. Writel_ine(" Dopo 

scambiaSenzaRef"); 

mostraValori(il, i2); 

scambiaConRef(ref il, ref i2); 



74 ►►► F e b b 



http://www.itportal.it 



System .Console. WriteLine("Dopo scambiaConRef"); 
mostra Valori(il, i2); 



La classe ScambiaVariabili comprende due me- 
todi dal corpo identico. Il primo, s cambia Senza- 
RefO, è formulato in maniera classica: 



public 


static void 


scambiaSenzaRef(int a, 


int 


b) 


{ 




int 


aux = a; 










a = 


b; 










b = 


= aux; 








} 



All'interno del corpo del metodo avviene uno 
scambio tra i valori conservati in a ed in b. Tut- 
tavia, questa operazione non ha alcun riscontro 
pratico. Gli interi a e b, infatti, sono sempre del- 
le copie dei valori originariamente forniti al 
metodo. 

Lo dimostra la prima parte dell'output restitui- 
to dal programma: 

il vale 5 

il vale 3 

Dopo scambiaSenzaRef 

il vale 5 

il vale 3 

Le variabili il e il dichiarate all'interno del me- 
todo Maini), come è possibile osservare, non 
hanno subito modifiche. È più che lecito che sia 
così: il e il sono passate per valore, ogni modi- 
fica sulle copie non si riflette sugli originali. Di- 
versamente avviene con il metodo scambiaCon- 
RefO, benché il corpo impiegato sia il medesi- 
mo: 



public 


static void 


scambiaConRef(ref 


int a, 


ref int 


b) 


{ 


int 


aux = a; 










a = 


b; 










b = 


aux; 










} 



L'unica differenza riscontrabile è nella lista de- 
gli argomenti di ingresso. Alla dichiarazione 
dei due interi a e b, infatti, è stato fatto prece- 
dere lo specificatore ref. La stessa parola chiave 
deve essere nuovamente digitata nel momento 
in cui il metodo viene richiamato: 

scambiaConRef (ref il, ref i2); 



guirà delle copie. Pertanto, una modifica sul 
contenuto di a si rifletterà su il, così come va- 
riando b si cambierà anche il. 
Lo dimostra l'output prodotto dal programma. 
Dopo scambiaConRef 

il vale 3 
il vale 5 

I valori conservati nelle variabili, in questo ca- 
so, sono stati invertiti. Il metodo, così formula- 
to, ha finalmente un senso pratico, che altri- 
menti non avrebbe. 



PASSAGGIO 

DI ARGOMENTI CON OUT 

Gli argomenti forniti ad un metodo devono 
sempre essere inizializzati prima di essere for- 
niti ad un metodo, indipendentemente dal loro 
tipo. In generale, vale sempre la regola "prima 
dichiari, poi inizializzi e quindi utilizzi". Il pas- 
saggio di argomenti, in effetti, è un vero e pro- 
prio utilizzo delle variabili. 
Senza l'inizializzazione, una variabile non può 
essere sfruttata, almeno in situazioni normali. 
Prendiamo in considerazione il seguente codi- 
ce: 



public static void MainQ 

{ 

int a = 5; 

int b = 3; 

int e; 

somma(a, b, ref e); 

System.Console.WriteLine("c vale " + e); 



} 



Non è possibile compilare questa classe, poiché 
l'intero e non è stato inizializzato prima di es- 
sere passato, per riferimento, al metodo som- 
mai). 
L'errore che se ne ricava è mostrato di seguito: 

error CS0165: Utilizzo della variabile locale "e" 

non assegnata. 




Argomenti 



class OutTestl 


1 r&\ Gli argomenti 
\-J\ forniti ad un 
metodo devono sem- 


{ 


public static void somma(int a, int b, ref int e) 


pre essere inizializ- 
zati prima di essere 


{ 


forniti ad un metodo, 
indipendentemente 
dal loro tipo. 


e = a + b; 


} 



In questo caso, gli interi il e il vengono trasfe- 
riti al metodo per riferimento. Il CLR non ese- 



Nonostante questo, esistono dei casi in cui si 
può desiderare di fare uso di una variabile non 



http: //www. itportal.it 



3 ►►► 75 




Dispense 
Web 

[7£] Tra le dispense 
r-J\ Web del corso 
troverete appunti, ag- 
giunte, approfondi- 
menti, risposte a do- 
mande frequenti e al- 
tre appendici legate 
alla lezione odierna. 
L'indirizzo di riferi- 
mento è 

http://www.sauronsoft - 
ware.it/dispenseweb/ 
csharp/ 



inizializzata. La seguente variante del prece- 
dente esempio ci introduce all'utilizzo della pa- 
rola chiave out: 

class OutTest2 

{ 

public static void somma(int a, int b, out int e) 

_i 

e = a + b; 

_} 

public static void MainQ 

_i 

int a = 5; 

int b = 3; 

int e; 

somma(a, b, out e); 

System.Console.WriteLine("c vale " + e); 

> 



> 



OutTestl è stata ottenuta sostituendo la parola 
out alle clausole ref già presenti in OutTestl. Di- 
venta ora possibile compilare ed eseguire il co- 
dice. Sostanzialmente, il passaggio di parame- 
tri attraverso la parola chiave out porta a due 
conseguenze: 

1. La variabile fornita viene trasferita sempre 
e comunque per riferimento, anche se è un 
tipo valore. 

2. Non è richiesto che la variabile fornita sia 
inizializzata, giacché out costituisce una tec- 
nica che si affianca a return nella restituzio- 
ne di valori al codice chiamante. 

Ad ogni modo, perché si dovrebbe utilizzare 
out per la restituzione di valori, quando si ha 
già a disposizione il ben più comodo return 7 . 
Semplicemente, potrebbe capitare che return 
non sia sufficiente. Con return è possibile resti- 
tuire un solo dato alla volta, mentre con out è 
possibile avere quanti valori di ritorno si desi- 
derano. Il vantaggio di out, dunque, non è evi- 
dente con il metodo sommai), giacché questo 
poteva più abilmente essere scritto nella forma: 



{ 



public static int 


somma(int a, 


int 


b) 


{ 


return a + b; 


} 



public static void perimetroAndArea(int I, out int per, 
out int area) 

{ 

per =1*4; 

area = 1*1; 

_} 

public static void MainQ 

i 

int I = 5; 

int p, a; 

perimetroAndArea(l, out p, out a); 

System.Console.WriteLine("Perimetro: " + p); 

System-Console. WriteLine("Area: " + a); 

} 



Prendiamo ora in considerazione questa nuova 
classe: 

class OutTest3 



} 



Il metodo perimetro And AreaO calcola il perime- 
tro e l'area di un quadrato di lato 1, in un colpo 
solo. Impiegando return, non sarebbe stato pos- 
sibile compiere entrambi i calcoli con una sin- 
gola funzione: si sarebbe potuto restituire sola- 
mente uno dei due valori calcolati, l'altro sa- 
rebbe andato perso. 

Ad ogni modo, return e out non si escludono a 
vicenda: in particolari situazioni, è possibile 
realizzare metodi che restituiscano un valore 
tramite return ed altri tramite out, simultanea- 
mente e senza conflitti. 



PASSAGGIO DI 
ARGOMENTI CON PARAMS 

In tutti i casi esaminati sinora, il numero di ar- 
gomenti forniti ad un metodo era sempre noto 
a priori. Ad esempio, il metodo sommai) com- 
preso in OutTestl accetta sempre tre argomenti: 
i due addendi e la variabile per la restituzione 
della loro somma. Ovviamente, sommai) non 
può sommare più di due addendi alla volta. 
Può essere interessante, invece, gestire un nu- 
mero di argomenti non noto a priori, ad esem- 
pio per sommare n addendi: 

class ParamsTest 

{ 

public static int somma(params int[] addendi) 

_J 

int totale = 0; 

for (int i = 0; i < addendi.Length; i++) 

{ 

totale += addendi[i]; 

} 

return totale; 

_} 

public static void MainQ 

{ 



76+» F e b b 



http://www.itportal.it 



int ti = somma(5, 3); 

System .Console. WriteLine(tl); 

int t2 = somma(2, 5, 1, 10, 9); 
System .Console. WriteLine(t2); 

int t3 = somma(6, 3, 8); 

System .Console. WriteLine(t3); 



La clausola params permette di gestire un nu- 
mero variabile di argomenti. 
Le tre chiamate: 




sono tutte valide e riferite allo stesso metodo, 
benché differiscano nel numero degli argomen- 
ti specificati. 
Con la dicitura: 

params int[] addendi 

abbiamo fatto in modo che il metodo sommai) 
dell'esempio corrente possa gestire un numero 
imprecisato di argomenti di tipo int. Di fatto, 
quello che viene fornito al corpo del metodo è 
un array di valori int. Questo corso ancora non 
ha esaminato nel dettaglio gli array. Per il mo- 
mento, è sufficiente sapere che un array è una 
collezione di valori del medesimo tipo. 
Con la proprietà: 

nomeArray.Length 

è possibile sapere quanti elementi ci sono nel- 
l'insieme. Ad ogni elemento di un array corri- 
sponde un indice numerico, da zero in poi. Il 
primo elemento di un array ha indice 0, il se- 
condo 1, il terzo 2 e così via. L'ultimo elemento 
ha sempre indice Length -2.1 singoli elementi 
della collezione possono essere selezionati at- 
traverso una coppia di parentesi quadre: 

nomeArray[0] 

nomeArray[l] 

nomeArray[2] 

nomeArray [nomeArray.Length - 1] 

In seguito, analizzeremo più nel dettaglio le 
collezioni e gli array, giacché questi costituisco- 
no una categoria di oggetti molto importante 
per la programmazione di applicazioni raffina- 
te. 



CONCLUSIONI 

C# è un linguaggio molto ricco, benché sempli- 
ce. Esistono numerosi stratagemmi per abbre- 
viare le operazioni di stesura del codice. Le tre 
caratteristiche esaminate in questa lezione, ad 
esempio, non sono indispensabili in un lin- 
guaggio orientato agli oggetti di derivazione 
Java, giacché possono essere rimpiazzate da 
tecniche alternative più complesse, ma lo stes- 
so efficaci. Proprio il linguaggio Java, ad esem- 
pio, non comprende nessuna delle tre parole 
chiave esaminate in questa sede, poiché i pro- 
gettisti di Sun le hanno giudicate ridondanti (e 
confusionarie). 

Più in generale, quindi, C# deve molto all'e- 
sperienza di Java, ma trae anche spunto dalle 
abitudini di C e C++, che gli sviluppatori han- 
no imparato ad apprezzare nel corso degli an- 
ni. 

Carlo Pelliccia 




C# Guida per 
lo sviluppatore 

ISBN: 88-203-2962-X 
Autore: Simon Robinson 
e altri 

Editore: Hoepli 
Pagine: 1188 
Costo: € 55,78 
Target: programmatori 
abbastanza esperti 



Con l'avvento di .NET, gli scaffali delle li- 
brerie cominciano a popolarsi delle prime 
edizioni dei manuali dedicati alla nuova 
piattaforma Microsoft. C#, ovviamente, è 
uno degli argomenti più discussi e richiesti 
dalla comunità degli sviluppatori. 
È comprensibile: conoscere C#, di fatto, si- 
gnifica avere la padronanza di tutti i mecca- 
nismi del nuovo framework, giacché al suo 
interno sono contenute le strutture che me- 
glio astraggono le funzionalità offerte da 
.NET. E poi, non dimentichiamolo, C# è un 
linguaggio nuovo (almeno nel nome ed in 
alcune caratteristiche), che incuriosisce e 
desta l'interesse dell'intera comunità degli 
sviluppatori Windows. 

Il manuale in questione si rivolge ai pro- 
grammatori mediamente esperti che già 
vantino nel loro curriculum esperienze con 
linguaggi analoghi a C#, soprattutto Java e 
C+ + . Il volume, come è lecito attendersi, 
presenta nei primi capitoli un'introduzione 
ai concetti di base del nuovo framework. Si 
parla quindi di .NET, di linguaggio interno, 
di codice gestito, di assembly e di altro an- 
cora. Viene poi introdotto il linguaggio C#. 
In tutti i capitoli più espressamente dedica- 
ti alle strutture del linguaggio, gli autori si 
sforzano di illustrare la programmazione 
orientata agli oggetti anche a chi proviene 
da un background differente, come i pro- 
grammatori Visual Basic. 




BSD 



Bibliografia 

• GUIDA A C# 
Herbert Schildt 
(McGraw-Hill) 
ISBN 88-386-4264-8 
2002 

• INTRODUZIONE A C# 
Eric Gunnerson 
(Mondadori Informati- 
ca) 

ISBN 88-8331-185-X 
2001 

• C# GUIDA PER LO 
SVILUPPATORE 
Simon Robinson e altri 
(Hoepli) 

ISBN 88-203-2962-X 
2001 



http: //www. itportal.it 



3 ►►► 77 







Risoluzione 

DI AMBIGUITÀ ED EREDITARIETÀ 
MULTIPLA 



Abbiamo visto una panoramica del concetto di 
ereditarietà, che rappresenta una delle differenze 
sostanziali tra programmazione procedurale e 
programmazione Object-Oriented, nonché una delle 
caratteristiche più importanti degli oggetti. Adesso 
scenderemo un pò 1 più nel dettaglio con nuovi concetti. 



File sul CD 

\soft\codice\C+ + .zip 



Nel precedente appuntamento si è esaminato 
come si possa ridefinire nella classe derivata 
ognuna delle funzioni particolari, tipiche di 
una classe (cioè il costruttore, il distruttore e l'operato- 
re di assegnazione), facendo eventualmente uso di 
quelle della classe base. Adesso, siccome siamo curio- 
si, ci chiediamo: possiamo ridefinire, nella classe deri- 
vata, una qualunque delle funzioni della classe base? 
Sebbene apparentemente sembri un problema banale, 
in cui la risposta affermativa ci sorge spontanea (quan- 
tomeno per trasporto emotivo), tuttavia l'apparenza, al 
solito, inganna: la soluzione praticamente banale è 
però molto insidiosa, e solo il bravo programmatore 
C++ sa come evitarne i pericoli. Supponiamo di avere 
le (solite) classi Scheda e Scheda Avanzata, e supponiamo 
che la derivazione tra le due sia di tipo public, mentre i 
campi nome e telefono siano stati dichiarati protected in 
Scheda: queste ultime ipotesi ci servono solo per sem- 
plificare il discorso, non sono necessarie. Il risultato 
delle nostre precondizioni, che supporremo verificate 
d'ora in avanti, è che i campi nome e telefono della clas- 
se Scheda sono a questo punto ereditati come protetti 
nella classe SchedaAvanzata (se necessario, ricontrollate 
lo schema introdotto la scorsa puntata). 
A questo punto, ignorando la possibilità di ridefinire 
l'operatore «, decidiamo di aggiungere un metodo al- 
la classe Scheda che si occupi di stampare, con oppor- 
tuna formattazione, il suo oggetto di invocazione. Una 
possibile definizione potrebbe essere: 

//nel file scheda.cpp 

void Scheda: :StampaFormattata() 

{ cout << "+ +\n"; 

cout << "| " << nome << " |\n"; 

cout << "+ +\n"; 

cout << " telefono: " << telefono << "\n"; 



In questa funzione, abbiamo trascurato la lunghezza 
della stringa nome, supponendo che sia lunga il giusto 
per apparire centrata nell'etichetta: in realtà dovrem- 
mo gestire da noi la cosa, ricavandoci la lunghezza di 
tale stringa e completando la stampa, con l'inserimen- 
to di opportuni caratteri di spaziatura oppure allun- 
gando l'etichetta del necessario. Potrebbe essere un uti- 
le esercizio per il lettore volenteroso. Il metodo appena 
scritto (supposto public nella classe Scheda) viene ades- 
so ereditato dalla classe SchedaAvanzata, rendendo così 
possibili operazioni del tipo: 

Scheda pienno("Pienno","61010610rimarrai"); 

SchedaAvanzata piero("Piero Pierrot", "0123456789", 

"pierrot@maschere.it"); 

pierino.StampaFormattataQ; 

piero.StampaFormattata(); 

Si presenta tuttavia adesso un problema. Quando ab- 
biamo deciso di creare la classe SchedaAvanzata, non 
avevamo l'intenzione di creare una nuova classe svin- 
colata dalla precedente: la nostra intenzione era di 
estendere la classe Scheda, usandola come base per la 
nuova classe. L'intenzione era poter inserire in un og- 
getto SchedaAvanzata ulteriori informazioni oltre quel- 
le inseribili in un analogo oggetto Scheda. Se adesso 
usiamo per la stampa formattata il metodo appena de- 
finito, il contenuto informativo che ha in più un ogget- 
to SchedaAvanzata rispetto ad un analogo oggetto Sche- 
da è come se non esistesse: in altre parole Scheda e Sche- 
daAvanzata dal punto di vista di questo metodo risul- 
tano indistinguibili, e il contenuto di un oggetto Sche- 
daAvanzata non è visualizzato in maniera completa (in 
quanto manca la stampa del valore del campo email). 
Non possiamo usare il campo email nel nostro metodo, 
perché esso fa parte della classe derivata (SchedaAvan- 



78^^ F e b b 



http: //www. itportal.it 



zata) e quindi nella classe base (Scheda) non esiste; non 
possiamo semplicemente spostare il metodo, opportu- 
namente modificato per la stampa del campo mancan- 
te, nella classe derivata, poiché si perderebbe la fun- 
zionalità, rappresentata dal metodo, nella classe base 
(in altre parole, potremmo stampare con questo meto- 
do solo oggetti di tipo Scheda Avanzata, ma non esiste- 
rebbe un analogo metodo per gli oggetti Scheda). Po- 
tremmo scrivere un metodo apposito per la classe de- 
rivata, ma (sebbene corretto) si costringerebbe l'utente 
della classe derivata e della classe base a ricordare la 
particolarità: è uno sforzo mnemonico superfluo. Pos- 
siamo però fare la cosa giusta, oltre che auspicabile ed 
intuitiva: ridefiniamo nella classe derivata lo stesso 
metodo della classe base. 

UN ESEMPIO 

DI RIDEFINIZIONE 

La ridefinizione si usa ogni volta che si vuole far corri- 
spondere una funzione della classe derivata ad una 
funzione della classe base, della quale l'omonima ap- 
partenente alla classe derivata costituisce una specia- 
lizzazione. Quando ridefiniamo una funzione nella 
classe derivata, essenzialmente basta che ci comportia- 
mo come se non esistesse un analogo metodo nella 
classe base. Scriviamo così il nostro "nuovo" metodo 
nella classe derivata: 




A questo punto, il codice di prova scritto nel paragrafo 
precedente funziona in maniera corretta, stampando il 
contenuto del campo email per (e solo per) gli oggetti di 
tipo Scheda Avanzata. Si deve, però, prestare attenzione 
ad un aspetto relativamente a questo meccanismo di ri- 
definizione: quando ridefiniamo un metodo nella clas- 
se derivata, essa maschera nella classe derivata tutte le 
funzioni ad essa omonime presenti nella classe base 
(cioè, il mascheramento avviene solo guardando il no- 
me della funzione, senza guardare le liste dei parame- 
tri: in altre parole, non è un overload!). Ad esempio, 
avendo una generica classe X con la seguente dichiara- 
zione: 

class X 

{ public: 

F(int); 

F(char); }; 

e definendo una classe derivata Y nel seguente modo: 
class Y: public X 



{ public: 

F(); }; 

si avrebbe che il metodo Y::F() maschera entrambi i 
metodi Xr.F(int) ed X::F(char), sebbene abbiano tra loro 
liste di parametri diverse. Quindi il seguente codice 
darebbe un errore: 

Y dummy; 

dummy.F(lO); //sbagliato: il metodo invocato non esiste! 

e questo perché il metodo F(int), sebbene presente nel- 
la classe base, è diventato invisibile nella classe deriva- 
ta in quanto mascherato dal metodo Y::F(), senza para- 
metri. I metodi della classe base non sono, però, per- 
duti per sempre: per accedervi basta usare l'operatore 
di scope resolution, "::". Tale operatore, incontrato già 
parlando delle definizioni delle funzioni di una classe, 
chiarisce al compilatore quale sia la classe di apparte- 
nenza di un metodo chiamato: l'uso di questo operato- 
re non è solo relegato alle definizioni delle funzioni di 
una classe! Infatti, questo operatore può essere usato 
ogni volta si renda necessario specificare una cosa del 
tipo "voglio che venga invocato il metodo M della clas- 
se C". Questo è proprio ciò che ci serve per accedere 
(da un oggetto della classe derivata) ai metodi della 
classe base una volta che essi siano stati ridefiniti nella 
classe derivata. Possiamo infatti accedere al metodo 
X::F(int) anche da un oggetto della classe Y, semplice- 
mente scrivendo: 



Y dummy; 

dummy.X::F(10); 



//giusto! 



In questo modo si è inteso dire che l'oggetto di invoca- 
zione dummy richiama il metodo F(int) della classe 
(base) X. Ovviamente, il metodo invocato tratterà 
adesso l'oggetto dummy (appartenente alla classe deri- 
vata) come fosse un oggetto della classe (base) X: que- 
sto significa che eventuali campi specifici della classe 
derivata non saranno considerati. Tornando al caso 
specifico delle classi Scheda e Scheda Avanzata, potrem- 
mo quindi scrivere: 

SchedaAvanzata XMen("Wolverine", "1235813", 

"io@wolverine.tv"); 

XMen. Scheda : :StampaFormattata(); 

ottenendo quindi una stampa a schermo come se X- 
Man fosse un oggetto della classe (base) Scheda invece 
che della classe (derivata) SchedaAvanzata: il campo 
email viene, semplicemente, ignorato dalla funzione 
invocata. 



EREDITARIETÀ MULTIPLA 

Una caratteristica molto interessante della program- 
mazione a oggetti, che il C++ implementa, è l'eredita- 
rietà multipla. Con questo nome si fa riferimento al 




Ó 



Contatta gli 
autori! 

Se hai suggeri- 
menti, critiche, 
dubbi o perplessità 
sugli argomenti trat- 
tati e vuoi proporle 
agli autori puoi scri- 
vere agli indirizzi: 

alfredo.marroccelli® 
libero.it (Alfredo') 



marcodelgobbo® 
libero.it (Marco) 

Questo contribuirà si- 
curamente a miglio- 
rare il lavoro di ste- 
sura delle prossime 
puntate. 



http: //www. itportal.it 



3 ►►► 79 




Avviso 

di chiamata 

Nell'articolo sia 
le funzioni Sche- 



Ó 



da A vanzatar.Imposta- 
ValiditàO che Scheda- 
MagneticaA vanzatar.I 
m postava Hd ita () han- 
no lo stesso compor- 
tamento, quindi la dif- 
ferenza tra il chiamare 
Cuna o l'altra potrebbe 
non essere molto evi- 
dente. Per questo ab- 
biamo inserito nel co- 
dice che trovate nel 
CD allegato, delle 
stampe a schermo che 
chiariranno l'effettivo 
percorso delle chia- 
mate effettuate. Con- 
sigliamo di dare un'oc- 
chiata! 



Scheda 




Scheda 
Avanzata 




Scheda 

Avanzatissima 







[a] 



Scheda 
Avanzata 








e 


s , 






Scheda 
Magnetica 
Avanzata 




J * 


Scheda 
Magnetica 











M 



Fig. 1: Catena di derivazione. 

meccanismo per il quale è possibile derivare una clas- 
se da più di una classe base, direttamente. Per "diretta- 
mente" si intende il fatto che la derivazione avviene 
nell'arco di un solo livello di ereditarietà, e non nel- 
l'ambito di una catena di derivazioni. Questo significa 
che le diverse classi base di una unica classe derivata 
possono anche essere completamente slegate tra loro e 
non avere niente in comune (anzi questo è proprio il 
caso più comune e utile in pratica). Per chiarire meglio 
questo concetto supponiamo di avere una classe Sche- 
daAvanzatissima derivata da Scheda Avanzata. La catena 
di derivazioni è mostrata in Fig. l.a. In questo caso 
NON si tratta di ereditarietà multipla, in quanto, come 
si può notare, tutte le classi che sono derivate di altre 
(cioè SchedaAvanzata e SchedaAvanzatissima) hanno una 
sola classe base. Il caso dell'ereditarietà multipla è 
esemplificato invece in Fig. l.b. In questo caso abbia- 
mo due classi base (SchedaAvanzata e SchedaMagnetica) 
dalla quale deriva la classe SchedaMagnetica Avanzata. 
Ma come si comporta un oggetto di una classe deriva- 
ta tramite ereditarietà multipla? Molto probabilmente 
il suo comportamento è intuibile dai concetti già ap- 
presi sull'ereditarietà. Infatti, così come una classe de- 
rivata in maniera standard racchiude ed estende le ca- 
ratteristiche della sua classe base, allo stesso modo una 
classe ottenuta mediante ereditarietà multipla, avrà i 
campi e le funzioni di tutte le sue classi base, esatta- 
mente come se ereditasse singolarmente da ciascuna di 
esse. Per fare un esempio, supponiamo che SchedaMa- 
gnetica sia definita nel seguente modo: 

class SchedaMagnetica { 

public: 

SchedaMagneticaQ; ~SchedaMagnetica(); 

void SetCodicePINQ; 

int GetCodicePINQ; 

private: 

int PIN; 

}; 

Definendo semplicemente SchedaMagneticaAvanzata 
come derivata di SchedaMagnetica e SchedaAvanzata, 
senza definire altri nuovi campi o funzioni, cioè nel se- 
guente modo: 

class SchedaMagneticaAvanzata : public 



SchedaMagnetica, SchedaAvanzata{ //... qui nulla... }; 

potremmo istanziare un oggetto che ci renda disponi- 
bili i campi delle due classi: 

SchedaMagneticaAvanzata sma; 

sma.Impostal\lome("Attarico II Babbaro"); 

//funzione di SchedaAvanzata 

sma.SetCodicePIN("0123"); //funzione di SchedaMagnetica 

in questo modo avremmo una classe che ingloba le al- 
tre due in maniera grezza, senza cioè offrire caratteri- 
stiche aggiuntive o funzionalità ulteriori rispetto a 
quelle che avremmo istanziando due oggetti diversi. 
Tuttavia, a volte, questo è utile ed è proprio quello che 
si vuole. Analogamente a quanto accade per l'eredita- 
rietà semplice, anche per quella multipla è possibile 
utilizzare la compatibilità degli oggetti, cioè a dire che 
un oggetto derivato può essere utilizzato in ogni pun- 
to in cui è richiesto un oggetto della classe base: 

void FunzioneDummyl(SchedaAvanzata s) {...} 

void FunzioneDummy2(SchedaMagnetica s) {...} 

SchedaMagneticaAvanzata sma; 

FunzioneDummyl(sma); //uso sma come SchedaAvanzata 
FunzioneDummy2(sma); //uso sma come SchedaMagnetica 

Ovviamente, come abbiamo già visto, non è possibile 
invertire il verso di questa compatibilità. 



ULTERIORI AMBIGUITÀ 

Cosa succede nel caso in cui le classi base hanno due 
funzioni con lo stesso nome? Quale delle due verrà 
"ereditata" dalla classe derivata e utilizzata quando 
viene invocata da un suo oggetto? Ci troviamo di fron- 
te a un caso di ambiguità simile a quello trattato in 
precedenza, che deve essere risolto in un qualche mo- 
do. Supponiamo, per fare un esempio, che sia Sche- 
daAvanzata che SchedaMagnetica abbiano la seguente 
funzione membro: 

void ImpostaValidita(bool valida); 

Scrivendo questo codice: 

SchedaMagneticaAvanzata sma; 

sma. Imposta Validita(true); 

quale funzione verrà chiamata? Quella di SchedaAvan- 
zata o quella di SchedaMagnetica? In realtà in questo ca- 
so non esiste alcuna discriminante valida per effettua- 
re una decisione, pertanto il compilatore segnalerà un 
errore in questo punto. Si badi bene che anche questo 
è un caso di mascheramento, per cui il compilatore se- 
gnalerebbe errore anche qualora le funzioni ImpostaVa- 
HditaO delle classi base avessero una lista di parametri 
differente: nel mascheramento conta solo il nome del 
campo. Cosa si può fare per ovviare a questa situazio- 



80 ►►► F e b b r 



http: //www. itportal.it 



ne? Esistono diverse strategie. Una prima possibilità è 
quella di utilizzare, come visto in precedenza nel caso 
dell'ereditarietà semplice, l'operatore di scope resolu- 
tion "::" e scrivere, ad esempio: 

SchedaMagneticaAvanzata sma; 

sma.SchedaAvanzata: : Imposta Validita(true); 

così facendo il compilatore avrà le idee chiare su cosa 
vogliamo intendere. Una seconda possibilità, forse più 
adatta a questo contesto, è quella di ridefinire nella 
classe SchedaMagneticaAvanzata la funzione ImpostaVa- 
UditaO in modo che faccia esattamente ciò che deside- 
riamo; ad esempio potrebbe chiamare il relativo meto- 
do di una delle sue classi base: 

void SchedaMagneticaAvanzata: :ImpostaValidita(bool v) 
{ SchedaAvanzata::ImpostaValidita(v); } 

o ancora potrebbe ridefinire completamente il com- 
portamento della funzione in questione, magari facen- 
dole impostare un nuovo campo privato di tipo boo- 
leano: 

void SchedaMagneticaAvanzata: :ImpostaValidita(bool v) { 
valida = v; //valida è dichiarato private in 

SchedaMagneticaAvanzata } 

Quest'ultima soluzione è senz'altro da preferire dal 
punto di vista semantico, in quanto il concetto di "va- 
lidità" di una scheda va al di là del fatto che si tratti di 
una scheda magnetica o quant'altro: una scheda è va- 
lida oppure non lo è, indipendentemente dalla sua na- 
tura. 



FUNZIONI VIRTUALI 

Abbiamo visto in precedenza come, per il concetto di 
compatibilità tra oggetto base e oggetto derivato, sia 
possibile usare quest'ultimo laddove è richiesto il pri- 
mo. Detta così sembra la cosa più banale del mondo, 
ma cosa succede nel seguente caso? 

void RendiValida(SchedaAvanzata& s) { 

s.ImpostaValidita(true); 

> 

SchedaMagneticaAvanzata sma; 

RendiValida(sma); 

Si utilizza in questo caso un oggetto di tipo SchedaMa- 
gneticaAvanzata al posto di uno di tipo Scheda Avanzata. 
All'interno di RendiValidaO è chiamata ImpostaValiditàO 
e, si noti bene, il parametro è passato per riferimento, 
quindi non entra in gioco alcun costruttore di copia. 
Verrà quindi chiamata la funzione ImpostaValiditàO di 
SchedaAvanzata (che è il tipo di oggetto che ci aspettia- 
mo venga passato quando scriviamo la funzione Ren- 
diValidaO) o quella di SchedaMagneticaAvanzataO (che 
maschera l'altra)? La risposta è che verrà invocata la 



funzione di SchedaAvanzata, in quanto, per le funzioni 
normali, il binding (cioè la scelta di quale funzione 
chiamare di volta in volta) viene fatto al momento di 
compilare la funzione (si parla di early binding), quan- 
do cioè non si sa di quale tipo sarà l'oggetto passato, o 
meglio, si presume ragionevolmente che esso sia del 
tipo specificato nei parametri; in questo caso, appunto, 
SchedaAvanzata. Ma come fare allora a utilizzare una 
funzione ridefinita in una classe derivata (che presu- 
mibilmente è stata ridefinita proprio perché quella ba- 
se non era adatta o sufficiente), sfruttando al tempo 
stesso la compatibilità? Bisogna introdurre un altro 
concetto: quello di funzione virtuale. Dichiarare una 
funzione come virtuale, significa dire al compilatore: 
"Quando incontri una chiamata a questa funzione non 
compilare subito il codice relativo, ma aspetta che ven- 
ga deciso a tempo di esecuzione qual'è la funzione 
giusta da agganciare qui". Il decidere a tempo di ese- 
cuzione la funzione da utilizzare si chiama, in lettera- 
tura informatica, late binding. Sfruttando il late bin- 
ding in RendiValidaO il codice: 

SchedaMagneticaAvanzata sma; 

RendiValida(sma); 

chiama effettivamente la funzione ImpostaValiditàO di 
SchedaMagneticaAvanzata, poiché di questo tipo è il pa- 
rametro passato. 

Per utilizzare il late binding è necessario che Imposta- 
ValiditàO in SchedaAvanzata sia dichiarata virtuale, tra- 
mite la parola chiave virtual: 

//nel file scheda_adv.h 

virtual void ImpostaValidita(bool valida); 

È quindi necessario in ogni caso fare uno sforzo di lun- 
gimiranza e prevedere a priori quali potranno essere le 
funzioni soggette a ridefinizione, per le quali è neces- 
saria la dichiarazione virtual. Anche in questo caso co- 
munque è bene non cadere nella sindrome del "dichia- 
ro tutto virtual" in quanto, il late binding è in ogni ca- 
so un meccanismo attuato a tempo di esecuzione, per 
cui meno ottimizzato e che potrebbe portare a delle 
inefficienze. 



CONCLUSIONI 

In questa lezione abbiamo trattato alcuni degli argo- 
menti più interessanti dell'ereditarietà in C++. Tutta- 
via non è ancora tutto in quanto questo meccanismo 
consente delle vere e proprie raffinatezze stilistiche e 
concettuali degne dei migliori programmatori. Noi ve 
le sveleremo nel prossimo appuntamento in cui parle- 
remo, tra l'altro di classi base astratte e funzioni vir- 
tuali pure. Alla prossima! 

Marco Del Gobbo & Alfredo Marroccelli 




Funzioni 
virtuali 

Dichiarare una 
funzione come 



Ó 



virtuale, significa dire 
al compilatore: 
"Quando incontri una 
chiamata a questa 
funzione non compi- 
lare subito il codice 
relativo, ma aspetta 
che venga deciso a 
tempo di esecuzione 
qual'è la funzione 
giusta da agganciare 
qui". 



http://www.itportal.it 



3 ►►► 81 




Ja\ 



Java 



MEDIA FRAMEWORK: STRUMENTI 
DI ACQUISIZIONE AUDIO E VIDEO 



Non bisogna essere degli esperti programmatori per 
realizzare applicazioni che facciano uso di dispositivi di 
acquisizione audio e video. Il pacchetto Java Media 
Framework mette a disposizione tutto quello che è 
necessario per riuscirci scrivendo soltanto qualche linea 
di codice! 



File Sul CD 

\soft\codice 
\JMFSourceCode2.zip 



Processor 



\/%\ Un Processor è un 
r^\ particolare tipo di 
Player che consente di 
ottenere come output i 
dati pre-elaborati per 
la riproduzione, natu- 
ralmente oltre a con- 
trollare e gestire la ri- 
produzione dei conte- 
nuti multimediali. Una 
volta istanziato il Pro- 
cessor, mediante il me- 
todo getDataOutput() 
è possibile avere il rife- 
rimento al DataSource 
dei dati che vengono 
prodotti in uscita. 



La semplicità di utilizzo degli strumenti presenti 
nei packages JMF è tale che per realizzare un 
multimedia player non è necessario essere 
esperti programmatori! Bastano poche istruzioni ed il 
gioco è fatto: 

• selezionare il file da riprodurre; 

• ottenere Turi corrispondente al percorso; 

• costruire un player controller per il file; 

• aggiungere alla finestra il componente di controllo 
e di riproduzione del player; 

• attivare, infine, il player! 

Per implementare i precedenti passi è possibile utiliz- 
zare come riferimento il seguente blocco di codice (trat- 
to dal metodo buildUIQ della classe Esempiol allegata). 



Player player; 

JFileChooser fileChooser = new JFileChooser("."); 

int status = fileChooser.showOpenDialog(this); 

if (status == JFileChooser.APPROVE_OPTION) 

{ File file = fileChooser.getSelectedFileQ; 

try{URL uri = file.toURLQ; 

f inai Container contentPane = getContentPaneQ; 

player = Manager.createRealizedPlayer(url); 

//A 

Component visualComponentUI = 

player.getVisualComponentQ; 

if (visualComponentUI != nuli) 

contentPane. add( visualComponentUI, 

BorderLayout.CENTER); 

Component controlPanelComponent = 

player.getControlPanelComponentQ; 

if (controlPanelComponent != nuli) 

contentPane. add( controlPanelComponent, 



BorderLayout.SOUTH); 



player.startQ; 
//A 



} 



catch(Exception e){System.out.println(e); 

System.exit(-l);} 

>//if 



La classe Manager mette a disposizione due diversi me- 
todi statici per costruire un Player e cioè Manager. crea- 
tePlayer(. . .) e Manager. createRealizedPlayer (. . .). La diffe- 
renza sostanziale sta nella modalità di controllo sulla 
costruzione del Player. Quando usiamo il metodo Ma- 
nager. createPlayer( .. .) quello che otteniamo è soltanto il 
riferimento ad un oggetto Player che in realtà può an- 
cora essere in costruzione, in quanto il metodo non è 
bloccante: nel caso in cui il Player non fosse ancora 
pronto, la successiva richiesta del componente di ripro- 
duzione video produrrà un errore javax. media. NotReali- 
zedError. In realtà questa situazione non deve conside- 
rarsi un limite. La completa realizzazione dell'oggetto 
è segnalata da un evento di tipo RealizeCompleteEvent: 
basterà quindi realizzare un Controller Adapter per que- 
sto evento e inserire all'interno del metodo realizeCom- 
plete(RealizeCompleteEvent event) la sezione delimitata 
dal commento //A (vedere esempio proposto nel prece- 
dente articolo). L'altro metodo, Manager. creai eRealized- 
Player(...) è invece bloccante: soltanto dopo la costru- 
zione dell' oggetto verrà restituito il controllo al thread 
di esecuzione dell' applicazione. 



CAPTUREDEVICE 

Limitarci a riprodurre file multimediali è però una for- 
te limitazione nell'utilizzo dei packages JFM. La realtà 



82^^ F e b b 



3 



http://www.itportal.it 



che ci circonda è una fonte inesauribile di informazio- 
ni che spesso vogliamo condividere con gli altri. Pos- 
siamo utilizzare quello che ci sta intorno come "sor- 
gente" dei contenuti audio e video delle applicazioni, 
acquisendoli mediante particolari dispositivi come te- 
lecamere digitali, webcam e microfoni. I dati ottenuti 
possono essere trattati, o direttamente memorizzati su 
disco in formato media (AVI, QUICKTIME, MP3, etc.) 
ovvero trasmessi attraverso la rete (streaming). Ciascun 
dispositivo hardware viene indicato come CaptureDe- 
vice e suddiviso in due categorie di sorgenti: di tipo pu- 
sh e di tipo pulì. La differenza è molto semplice: si par- 
la di push source quando la sorgente è di tipo continua 
(ed anche sullo stream si avrà un flusso continuo di da- 
ti), come ad esempio lo sono i microfoni. Una macchi- 
na fotografica digitale è invece una sorgente pulì in 
quanto produce dati "isolati", in singole immagini 
(scatti). Utilizzando Java Media Framework, tutti i cap- 
ture device assumono un livello di astrazione tale da 
trascurare completamente la loro natura hardware, 
consentendoci di individuarli soltanto mediante i for- 
mati dei dati prodotti. Ciascun dispositivo viene 
"mappato" su un generico CaptureDevice di cui ne co- 
nosciamo solamente le caratteristiche fondamentali a 
cui possiamo accedere usando il corrispondente Cap- 
tureDevicelnfo. Come nel caso visto in precedenza, cioè 
della riproduzione di file multimediali, anche in que- 
sto caso le istruzioni da seguire sono veramente sem- 
plici: 

• localizzare il CaptureDevice mediante apposita ri- 
chiesta al CaptureDeviceManager; 

• dal device risalire alle sue caratteristiche mediate il 
suo CaptureDevicelnfo; 

• sfruttando questo oggetto otterremo il MediaLoca- 
tor necessario per creare il DataSource da cui attin- 
gere i dati prodotti; 

• costruire il Player su questo DataSource; 

• infine, avviare il processo di acquisizione. 

Mediante chiamata al metodo statico getDeviceList( . . .) 
dXCaptureDeviceManager è possibile ottenere la lista dei 
dispositivi disponibili (o meglio dei corrispondenti 

CaptureDevicelnfo), 



java.util.Vector deviceList; 

CaptureDevicelnfo CaptureDevicelnfo; 

deviceList = CaptureDeviceManager.getDeviceList(null); 

if (deviceList.size()>0) 

CaptureDevicelnfo = (CaptureDevicelnfo) 
deviceList.fi rstElementQ; 



oppure accedere direttamente ad un particolare dispo- 
sitivo direttamente dal suo identificativo, sfruttando il 
metodo getDevice(deviceName). Il metodo getDeviceLi- 
st(...) ha come parametro di richiesta un Format, cioè 
un oggetto con il quale viene identificato, appunto, un 



particolare formato e che contiene tutte le informazio- 
ni necessarie al trattamento dei dati. Lasciando inde- 
terminato questo parametro, il CaptureDeviceManager 
restituirà la lista completa di tutti i dispositivi disponi- 
bili, altrimenti fornisce soltanto l'elenco dei CaptureDe- 
vicelnfo corrispondenti ai dispositivi che possono pro- 
durre dati nel formato richiesto. La classe Format ha 
due classi derivate principali: una per definire il gene- 
rico formato audio (AuàioFormat), l'altra per quello vi- 
deo (VideoFormat). Ciascuna di queste classi viene poi 
utilizzata per specificare ogni formato (rispettivamen- 
te audio e video) supportato dalle librerie JFM. Ad 
esempio, possiamo richiedere al CaptureDeviceManager 
soltanto i device di acquisizione video: per farlo speci- 
fichiamo un formato audio generico, senza cioè speci- 
ficare un particolare encoding type: 



AudioFormat audioFormat = new AudioFormat(null); 



ed utilizziamo l'oggetto Format come parametro al me- 
todo getDevicelisti . . .) 



deviceList=CaptureDeviceManager.getDeviceList 

(audioFormat); 

for (int index=0; index<listDevice.size(); index++) 
{devicelnfo = (CaptureDevicelnfo) 

listDevice.elementAt(index); 

System .out.println(deviceInfo.getName()); 

> 



Un'operazione analoga possiamo realizzarla per cono- 
scere i dispositivi in grado di produrre dati in formato 
video: basterà sostituire l'oggetto AudioFormat con un 
VideoFormat. Una volta individuato il device che inte- 
ressa, il passo successivo sarà quello di ottenere il suo 
MediaLocator da cui costruire il DataSource di produ- 
zione dei dati necessario al Player 



MediaLocator mediaLocator = devicelnfo.getLocatorQ; 
DataSource dataSource = Manager.createDataSource( 

mediaLocator);. 

Player player = Manager.createPlayer(dataSource); 



oppure, in maniera più compatta 



Player player = Manager.createPlayer( 
devicelnfo.getLocatorQ); 



ma questa forma non è sempre utilizzabile. Cosa suc- 
cede quando abbiamo contemporaneamente una sor- 
gente audio ed una video (magari proveniente da due 




ava 



DataSource 

\f&\ Prendiamo una 
1^1 sorgente di dati 
"digitali": il flusso pro- 
dotto viene incapsula- 
to mediante un ogget- 
to DataSource, che 
rappresenta quindi i 
vari media audio, vi- 
deo o combinazione di 
entrambi. Una sorgen- 
te può essere un file o 
uno stream via Inter- 
net: specificando la lo- 
cazione (mediante un 
semplice oggetto URL) 
oppure il protocollo 
(ad esempio file://) è 
possibile costruire il 
corrispondente Data- 
Source da passare in 
ingresso al Player. 
Quando la sorgente dei 
dati proviene da uno 
stream via Internet, è 
bene effettuare una di- 
stinzione tra due tipi di 
DataSource: 

1) PULL DATA SOURCE: Io 

si ha quando è il client 
che inizializza il trasfe- 
rimento dei dati e ne 
controlla il flusso ope- 
rando direttamente 
sulla sorgente. 
Ad esempio, i protocol- 
li HTTP e FILE sono ti- 
pici casi di questo tipo 
di DataSource. 

2) Push data source: in 
questo caso è il server 
che gestisce il flusso 
ed il client può soltan- 
to acquisire i dati sen- 
za aver un controllo di- 
retto su di essi, come 
nei sistemi di broadca- 
sting e video on de- 
mand. 



http://www.itportal.it 



3 ►►► 83 




Ja 



DataSink 



\y%\ Il DataSink è l'in- 
r^\ terfaccia di base 
utilizzata per realizza- 
re un particolare tipo 
di oggetti, in grado di 
recuperare i dati pre- 
senti su di un flusso e 
re-indirizzarli verso 
una qualche destina- 
zione. Un DataSink 
può ad esempio recu- 
perare i dati da un Da- 
taSource in uscita da 
un Processor e memo- 
rizzarli in un file multi- 
mediale (come visto 
nell'esempio propo- 
sto) 



Formati 
supportati 
da JMF 2.1.1 

\/%\ La versione 2.1.1 



versione 
J del package sup- 
porta diversi tipi di me- 
dia tra cui: 



• protocolli: FILE, 
HTTP, 

FTP, RTP 

• audio: AIFF, AU, AVI, 
GSM, MIDI, MP2, MP3, 
QT, RMF, WAV 

• video: AVI, MPEG-1, 
QT, H.261, H.263 

JMF fornisce anche il 
supporto pure a formati 
"concorrenti" come ad 
esempio Flash 2 e Hot- 
Media. 



Player 



Un Player è un particolare oggetto che rende "riprodu- 
cibile" i dati provenienti da stream di dati audio/video 
in ingresso. Questo processo di trasformazione è ne- 
cessario per problemi di compatibilità con i dispositivi 
di riproduzione. Prendiamo ad esempio un CD audio. 
Per porer essere riprodotto, il player legge in input le 
sequenze di bit dal supporto ottico e le trasforma in un 
formato media compatibile con la scheda audio. Poi- 
ché i dispositivi sia di riproduzione che di acquisizione 
vengono trattati in maniera generica, il Manager deve 
riconoscere il formato dei dati da riprodurre (distin- 
guendo tra i diversi formati audio e video) e costruire 
un Player compatibile. Il comportamento di questo 
Controller è scandito in base al particolare stato in cui 
si trova: 

1) UNREALIZED. Questo stato sta ad indicare che il 
Player è in fase di istanziazione, in quanto il Mana- 
ger deve prima identificare il formato dei dati da 
trattare. Come già detto in precedenza, se il Player 
si trova in questo stato non può ancora essere uti- 
lizzato. Bisogna aspettare la conclusione delle ope- 
razioni di preparazione. 

2) REALIZING. Dopo che il Manager ha determinato il 
formato dei dati su cui si sta costruendo il Player, 
lo stato dell'oggetto viene commutato mediante 
una chiamata al metodo realize(), che ne attiva la 
procedura di acquisizione delle risorse necessarie. 

3) REALIZED. Completata la fase di preparazione, il 
Player passa in questo stato, comunicandolo me- 
diante un evento RealizeCompleteEvent. A questo 
punto il Player è pronto, correttamente istanziato 
sul formato dei dati e con i necessari componenti 
visuali e Controls. 

4) PREFETCHING. Chiamando il metodo prefetch() il 
Player comincia a prepararsi per la riproduzione, 
precaricando i dati, ottenendo l'uso esclusivo delle 
risorse necessarie. 

5) PREFETCHED. Completato anche il precaricamento 
e l'allocazione delle risorse, il Player è finalmente 
pronto. 

6) STARTED. Dallo stato Prefetched passa in Started 
appena viene chiamato il metodo start(). 



diversi dispositivi)? In teoria si potrebbe costruire un 
Player per ciascun MediaLocator (e quindi con il corri- 
spondente DataSource) in modo da controllarne sepa- 
ratamente la riproduzione, ed in questo caso possiamo 
far uso della forma compatta: 



Player videoPlayer = Manager.createPlayer 
(videoDevice.getLocatorQ); 

Player audioPlayer = Manager.createPlayer 

(audioDevice.getLocatorQ); 

videoPlayer.addControllerListener(this); 

videoPlayer.startQ; 

audioPlayer.start(); 

Per avviare la riproduzione è necessario operare sepa- 
ratamente su i due Player invocando il metodo starti). 
In alternativa è possibile metterne uno sotto il control- 
lo dell'altro 



videoPlayer.addController(audioPlayer); 



videoPlayer.startQ; 



e quindi attivare la riproduzione sincronizzata di en- 
trambi operando soltanto su di uno. Ma se invece di 
avere due distinti DataSource si volesse operare su di 
un unico stream, è possibile chiamare il metodo create- 
MergingDataSource(DataSource[] dataSources) sul Mana- 
ger per ottenere una combinazione (nel nostro caso tra 
audio e video). Naturalmente la forma compatta non è 
più applicabile, in quanto il Player va costruito sul Da- 
taSource combinato e non più sul MediaLocator (vedere 
la classe Esempio! nell'omonimo file Java): 



DataSource[] dataSources = new DataSource[2]; 

dataSources[0] = Manager.createDataSource 
(audioDevice.getLocatorQ); 

dataSources[l] = Manager.createDataSource 
(videoDevice.getLocatorQ); 

DataSource dualDataSource = 
Manager.createMergingDataSource(dataSources); 

Player player = Manager.createPlayer(dualDataSource); 

player.startQ; 



CLONEABLEDATASOURCE 

All'interno di un'applicazione possiamo avere più 
Player operanti ognuno su di un particolare stream da- 
ti. In pratica il Player "consuma" i dati che si presenta- 
no sullo stream per poterli elaborare, ripresentandoli in 
uscita in un formato idoneo alla riproduzione. Poiché 
questi dati in input vengono man mano estratti dal 
flusso, non rimangono disponibili per eventuali elabo- 
razioni da altri Player. Un caso tipico è quando si vuol 
salvare su disco le immagini video provenienti da una 
telecamera digitale e contemporaneamente visualiz- 
zarle. La necessità di avere contemporaneamente due 
operazioni distinte (riproduzione del flusso e salvatag- 
gio), costringe l'uso di altrettanti Player che debbono 
coesistere sugli stessi dati. Ma uno dei due esclude l'al- 
tro in quanto "consuma" i dati che si presentano. 
Per coesistere, ciascun Player deve operare su di un 
proprio flusso di dati, cioè su una copia personale del 
DataSource: come creare e rendere disponibile a ciascu- 
no il proprio stream media? Mediante il metodo stati- 
co della classe Manager, una versione "clonabile" del 
DataSource originale 



dataSource=Manager.createCloneableDataSource 
(dataSource); 



il nuovo dataSource mantiene ancora la caratteristica di 
un DataSource ma acquista anche la natura di Source- 
Clonable. A questo punto possiamo ottenere da questo 
oggetto tutte le copie (cloni) che vogliamo, che saranno 



84 ►►► F e b b 



3 



http://www.itportal.it 



indipendenti l'una dall'altra ma non dallo stream ori- 
ginale 



DataSource sourcePlayerl = ((SourceCloneable) 
dataSource).createClone(); 

DataSource sourcePlayer2 = ((SourceCloneable) 
dataSource).createClone(); 

Player playerl = Manager.createRealizedPlayer 
(sourcePlayerl); 

Player player2 = Manager.createRealizedPlayer 
(sourcePlayer2); 



ai dati elaborati e convertiti nel formato; per ottenere 
un oggetto Processor in modalità Realized abbiamo la 
necessità di un Processor Model, costruito sul DataSource 
clonato, sui formati da adottare e sul FileTypeDescriptor 
del file multimediale. 



ProcessorModel processorModel = 

new ProcessorModel(dataSource, formats, outputType) 
Player processor = Manager.createRealizedProcessor 
(processorModel); 




ava 



Affinchè si abbia un flusso di dati sui cloni, è necessa- 
rio che anche l'originale sia soggetto ad un flusso. Se 
provassimo ad avviare i Player a questo stadio, non si 
avrebbe nulla in riproduzione, in quanto il DataSource 
originale è inattivo. 



SALVATAGGIO DI UN MEDIA 

A questo punto, per ritornare al caso di riproduzio- 
ne/salvataggio, ottenuti i cloni necessari si possono 
predisporre neir applicazione due moduli. Il primo 
avrà il compito di controllare e gestire la riproduzione 
del contenuto audio e video dell' acquisizione, mentre 
il secondo dovrà gestire il salvataggio dei dati in un fi- 
le media. Ciascun modulo avrà a disposizione un clo- 
ne dello stesso DataSource. Vediamo brevemente come 
è possibile salvare un flusso come un file multimedia- 
le, ad esempio QUICKTIME. 

Per prima cosa dobbiamo procurarci il formato da 
adottare nella trasformazione del flusso. L'audio dovrà 
avere un formato con encoding IMA4 mentre il video 
può essere Cinepak (che sono i formati definiti per il 
QuickTime). 



Format formats[] = new Format[2]; 

formats[0] = new AudioFormat(AudioFormat.IMA4); 
formats[l]=new VideoFormat(VideoFormat.CINEPAK); 



Poi costruire il descrittore da utilizzare nella definizio- 
ne del file e il MediaLocator da utilizzare 



FileTypeDescriptor outputType = new 

FileTypeDescriptor(FileTypeDescriptor.QUICKTIME); 
MediaLocator dest = new MediaLocator 
("file://./esempio.mov"); 



Costruito il Processor si accede al DataSource in output e 
su di esso definiremo il file-writer (in questo caso un 
DataSink). Al termine del flusso originale è necessario 
chiudere anche il file-writer per completare il salvatag- 
gio: non basta quindi bloccare il Processor ma è neces- 
sario fermare il file-writer, e quindi chiudere il file. La 
cosa però non è così immediata! Non possiamo ferma- 
re il file-writer contestualmente alla chiusura del Pro- 
cessor, in quanto possono ancora esserci dei dati sullo 
stream. Il problema è subito risolto se registriamo un 
acoltatore che resti in attesa di un evento EndOfStrea- 
mEvent: appena si raggiunge la fine dei dati presenti 
sullo stream, questo evento se catturato consentirà di 
chiudere anche il file-writer rimasto aperto. 



DataSource source = processor.getDataOutputQ; 
DataSink filewriter = Manager.createDataSink 

(source, dest); 

DataSinkListener listener = new DataSinkAdapterQ; 

filewriter.addDataSinkListener(listener); 

filewriter.openQ; 

filewriter.startQ; 

processor, sta rt(); 



Dove la classe DataSinkAdapter è: 



class DataSinkAdapter implements DataSinkListener{ 

public void dataSinkUpdate(DataSinkEvent event) 

{ 

/^Modulo di visualizzazione*/ 

if (event instanceof EndOfStreamEvent) 

{try{event.getSourceDataSink().stop(); 

event.getSourceDataSinkQ.closeQ; 

}catch(Exception e){System.out.println 
("DataSinkAdapter: "+e); System.exit(-l); 



m: 



JMFRegistry 

I L'operazione di map- 
I patura del dispositi- 
vo reale con il corrispon- 
dente CaptureDevice non 
è completamente auto- 
matica ma va controllata 
attraverso JMFRegistry, 
un'applicazione standalo- 
ne fornita con la versione 
2.1 del tool JMF scaricabi- 
le dal sito della SUN. JM- 
FRegistry consente di re- 
gistrare tutti i dispositivi 
di acquisizione audio e vi- 
deo installati sul PC: la 
condizione necessaria è 
che nel sistema siano cor- 
rettamente presenti tutti 
i driver necessari per l'i- 
dentificazione e l'accesso 
ai dispositivi. Se JMFRegi- 
stry non riesce a indivi- 
duare un dispositivo può 
essere a causa di un erro- 
re nei driver o nel proces- 
so di installazione. 



} 



event.getSourceDataSinkQ.closeQ; 



Al posto di un normale Player, utilizzeremo un Proces- 
sor: questo perché non dobbiamo riprodurre i dati ma 
convertirli in un formato compatibile con il file media 
di memorizzazione. Diversamente dal Player, il Proces- 
sor ci consente di accedere al DataSource in uscita, cioè 



big. Antonino Panella 



http://www.itportal.it 



3 ►►► 85 



< < < < < < < < < < Corsi Avanzati 

Come 

REALIZZARE UN FTP CLIENT 

In questo appuntamento descriveremo gli strumenti che 
permettono d'implementare le funzionalità di un FTP Client. 




isual 

Basic 



FTP (File Transfer Protocol) è il protocollo che defi- 
nisce le regole per il trasferimento di file tra com- 
puter. L'FTP viene usato quando si scaricano, sul 
proprio computer, file prelevati da Internet, o quando 
dal proprio computer si trasferiscono file su un altro 
computer (ad esempio sul Server di un Internet Provi- 
der). L'FTP nasce nel 1972 nel MIT (Massachussets Insti- 
tute of Technology), le specifiche deirFTP vengono de- 
scritte nella RFC 114. L'FTP unisce i comandi del 
TCP/IP e del Telnet Protocol (Protocolli sviluppati con 
ARPAnet), si basa sul codice ASCII ed in particolare ne 
usa, solo, la parte inferiore (ASCII a 7 bit). I comandi 
dell' FTP oltre a controllare il flusso dei file, da e verso 
il Server, consentono, quando si trasmettono file, di in- 
teragire con il processo in atto sul Server. Ai server FTP 
è possibile accedere anche attraverso un Web Browser, 
in questo caso l'indirizzo da specificare è del tipo 
"ftp://ftp.microsoft.com", naturalmente con questo tipo 
di richiesta le informazioni visualizzate non saranno 
delle pagine HTML ma dei nomi di directory e di file. 
In questo articolo illustreremo come implementare la 
parte centrale di una FTP Client application. In Visual 
Basic per tale fine abbiamo vari strumenti: il controllo 
Internet Transfer, le funzioni dell' API di Windows e 
l'oggetto Winsock. Nello spazio di un articolo non sarà 
possibile presentarli tutti, per questo illustreremo som- 
mariamente il controllo Internet Transfer, descriveremo 
le funzioni dell' API di Windows dedicati ad Internet e 
faremo solo qualche cenno sul WinSock Control. 

INTERNET 
TRANSFER CONTROL 

Il controllo Internet Transfer (INET) consente di attivare 
una connessione Internet e di eseguire dei comandi. Il 
tipo di comando che può essere eseguito dipende dal 
protocollo di trasmissione selezionato cioè HTTP op- 
pure FTP. I principali metodi del controllo sono: Ope- 
nilRL ed Execute. 

OpenURL - Questo metodo apre un elemento (pagina, 
directory) che si trova all'URL specificato. La sintassi è 
la seguente: 

object.OpenUrl URL [,datatype] 



URL è l'indirizzo dove si trova l'elemento che deve es- 
sere aperto. DataType è un parametro opzionale che 
specifica il tipo di dato da leggere ("0" dato stringa, "1" 
dato come byte array). 

Execute - Questo metodo permette di inviare un co- 
mando ad un Server. Naturalmente i comandi che pos- 
sono essere inviati dipendono dal protocollo seleziona- 
to. La sintassi è la seguente: 

object. Execute uri, operation, data, requestHeaders 

URL, se specificato indica l'URL da utilizzare, neW Exe- 
cute, altrimenti l'URL utilizzato sarà quello specificato 
in OpenUrl. Operation è una stringa che specifica il tipo 
di operazione da eseguire (tra poco vedremo qualche 
esempio, non elencheremo tutti i valori, se siete inte- 
ressati potete controllare la guida in linea di Visual Ba- 
sic). Data è una stringa che specifica le informazioni che 
verranno utilizzate dall'operazione. RequestHeaders è 
una stringa che specifica informazioni supplementari. 
Le proprietà principali del controllo sono: Accetype, 
Protocol, URL ecc. Per esempio AccessType è utilizzata 
per specificare il tipo di accesso alla rete Internet. Come 
è noto la connessione di un computer client ad Internet 
può avvenire direttamente o tramite Proxy (cioè attra- 
verso una Intranet collegata alla rete tramite un dispo- 
sitivo di smistamento) che eventualmente funge da fil- 
tro. Per questo i valori che la proprietà può assumere 
sono: 

icNamedProxy cioè accesso tramite proxy; 
icDirect accesso diretta ad Internet; 
IcUseDefault impostazioni di default, in generale di- 
retto. 

Le altre proprietà che utilizzeremo saranno illustrate in 
seguito. In conclusione aggiungiamo che il controllo 
INET è in grado di supportare sia la trasmissione sin- 
crona che quella asincrona. La sincrona è associata al 
metodo OpenURL, che durante la trasmissione dei file 
non permette di eseguire altro codice. L'asincrona, inve- 
ce, è associata al metodo Execute che, appunto, consen- 
te l'esecuzione di altre operazioni durante il download 
dei file. 



Client server 

I /-SI In una configura- 
la^ I zione Client/Ser- 
ver FTP, il Server è un 
sistema in cui sono ar- 
chiviati i file (oppor- 
tunamente orga- 
nizzati in Directory) 
che attraverso un FTP 
Client possono essere 
manipolati in remoto. 
Sul Server FTP sono 
definiti gli account dei 
Client. I Client dopo 
aver specificato User- 
name e Password pos- 
sono accedere, in let- 
tura/scrittura, ad una 
parte oppure a tutte 
(dipende dal tipo di 
account) le directory 
del Server. Su alcuni 
Server, di solito, è de- 
finito l'account anony- 
mous (con password 
un indirizzo di posta 
elettronica o "guest") 
che contiene le direc- 
tory pubbliche del si- 
to. 



http://www.itportal.it 



b b 



3 ►►► 87 




Visual 

Basic 



m. 



Tcp/IP 

I II protocollo TCP 
| /IP è nato nel 
mondo Unix e ormai è 
disponibile su tutti i 
sistemi operativi. 
TCP è un protocollo 
che garantisce la cor- 
retta trasmissione dei 
dati inviati e ricevuti, 
conservando la se- 
quenza di trasmissio- 
ne e ricezione. Insie- 
me all'IP protocol (In- 
ternet Protocol), che 
si occupa essenzial- 
mente dell'instrada- 
mento dei pacchetti fi- 
no al destinatario, co- 
stituiscono il base 
layer di Internet. 
Dunque il TCP/IP è un 
protocollo orientato 
alla connessione e 
concepito per la tra- 
smissione punto-pun- 
to. 




Fig. 1: La form che permette di utilizzare il 
controllo Internet Transfer. 



FTP CLIENT 

Iniziamo a descrivere il codice per l'FTP Client. 
Create un nuovo progetto Visual Basic con due form 
(formi e formi), sulla formi inserite un controllo INET 
(naturalmente dopo aver referenziato la libreria Micro- 
soft Internet Transfer Control) ed una serie di pulsanti 
che ci serviranno per abilitare alcune funzionalità del 
protocollo FTP come: connessione al Server, spostamento 
e caricamento file ecc. Inoltre sulla form posizionate un 
textbox che servirà per mostrare il contenuto dell'URL 
aperto tramite Openllrl (controllate la Fig. 1). 
Analizziamo le istruzioni che consentono di stabilire 
una connessione e successivamente di utilizzarla per 
eseguire i comandi FTP. Nel Click del pulsante Connet- 
ti settiamo i parametri del controllo INET1 necessari 
per l'impostazione di una connessione FTP. 

Private Sub Connetti_Click() 

With Inetl 

.UserName = "Anonymous" 

■ Password = "guest" 

.AccessType = icDirect 

■ RemotePort = 21 

■ Protocol = icFTP 

.URL = "ftp://pasta" 

End With 

End Sub 

In particolare effettuiamo una connessione con User- 
Name "anonimo" e Password "guest" (ospite). Questi va- 
lori consentono di accedere alla parte pubblica di uno 
spazio FTP. Successivamente specifichiamo il tipo di 
connessione impostando la proprietà AccessType su ic- 
Direct. Specifichiamo che utilizziamo la porta di con- 
nessione 21 e il protocollo FTP ed infine impostiamo 
TURL del Server cioè ftp: li 'esempio. Facciamo notare che 
il server non è remoto ma si trova sullo stesso compu- 
ter utilizzato per sviluppare il programma (questo s'in- 
tuisce dal modo in cui è specificato l'indirizzo FTP). 
Come s'intuisce dal nome del pulsante nel Click di 
"Chiudi" specifichiamo il codice per chiudere la con- 
nessione. Questo lo facciamo utilizzando il metodo 
Execute e il comando FTP "CLOSE". 



Vediamo ora il comando che ci consente di aprire un fi- 
le con nome "provaftptxt.txt" che si trova nella root del- 
lo spazio FTP pubblico (per l'organizzazione delle di- 
rectory dello spazio FTP controllate la Fig. 3). 



Private Sub 


Openurl_ 


Click() 




Textl.Text 


: = Inetl 


■openurl("esempio/provaftptxt 


txt") 


End Sub 



Nel Click del pulsante Openurl richiamiamo il metodo 
Openllrl passandogli l'indirizzo ed il nome del file da 
aprire, il risultato di questa richiesta verrà restituito nel 
textbox Textl. Per scaricare il file localmente utilizziamo 
la seguente procedura: 

Private Sub Scarica_Click() 

Inetl.Execute , "GET provaftptxt.txt c:\provadowload2.txt" 
End Sub 

In cui dopo aver invocato il metodo Execute sull'ogget- 
to Inetl gli passiamo come operazione FTP una "GET" 
(cioè preleva) che ha come parametri il file da preleva- 
re ed il percorso locale dove trasferire il file (cioè 
c:\provadowload2.txt). Come accennato la suddetta 
operazione avviene in modalità asincrona, quindi la 
stessa operazione poteva essere effettuata in modo sin- 
crono utilizzando il metodo OpenllRL. La lista dei file 
della root la richiediamo attraverso il metodo EXECU- 
TE e l'Operatore DIR. Se però volessimo la lista dei fi- 
le presenti in una sotto directory, ad Execute dovrem- 
mo passare "DIR" più il nome della sotto directory nel- 
la forma: DIR [nome], ecc. Quindi possiamo considera- 
re un'istruzione del tipo: 



Private Sub dir_ 


Click() 


Inetl.Execute 


, "DIR" 


End Sub 



Private Sub Chiud 


_Click() 


Inetl.Execute , ' 


CLOSE" 


End Sub 



Naturalmente, la creazione della connessione deve es- 
sere fatta prima dell'esecuzione delle altre operazioni 
per questo conviene inserire del codice per il controllo 
di questo aspetto (questo lo faremo quando descrive- 
remo le funzioni dell' API). Notate come in Fig. 1, la 
Formi ospita un pulsante con nome UsaAPI, questo 
serve per mostrare la formi dove abbiamo previsto il 
codice che richiama alcune funzioni dell' API. Inizia- 
mo, quindi, la descrizione della seconda parte del no- 
stro progetto che prevede l'uso delle API per realizza- 
re le operazioni che abbiamo implementato in prece- 
denza attraverso il controllo INET. 



FTP CLIENT CON LE API 

Anche sulla formi posizioniamo una serie di pulsanti 
(Fig. 2). Le funzioni API le dichiariamo in un modulo 
(Modulel.bas). In esso dichiariamo anche le seguenti 
costanti e variabili. 

Public Const INTERNET SERVICE FTP = 1 



88*-^ F e 



http: //www. itportal.it 




Fig. 2: La form che permette di utilizzare le 
funzioni dell'API. 



Public Const INTERNET_SERVICE_GOPHER = 2 

Public Const INTERNET_SERVICE_HTTP = 3 

Public sessioneinternet As Long 

Public sessioneftp As Long 

'qui vanno inserite le dichiarazioni delle funzioni API 
'che descriveremo tra poco 

Sessioneinternet e sessioneftp servono per conservare 

rhandle della sessione Internet e della sessione ftp; le 

costanti verranno utilizzate dalla funzione InternetCon- 

nect per specificare il tipo di servizio (come sarà chiaro 

tra poco). 

Nel Click del pulsante Apri Internet creiamo la sessione 

Internet. 

Private Sub ApriInternet_Click() 

sessioneinternet = InternetOpen("progettol", 0, 

vbNullString, vbNullString, 0) 

End Sub 

La sessione internet viene inizializzata richiamando la 
funzione API InternetOpen di cui vediamo brevemente 
la sintassi: 

Public Declare Function InternetOpen 

Lib "wininet.dll" Alias "InternetOpenA" ( 

ByVal sAgent As String, 

ByVal nAccessType As Long, 

ByVal sProxyName As String, 

ByVal sProxyBypass As String, 

ByVal nFlags As Long) As Long 

Dove: 

• sAgent, è il nome dell'applicazione che chiama la 
funzione API; 

• nAccessType, specifica il tipo di accesso (diretto, 
tramite proxy, ecc.); 

• sProxyName, è una stringa che contiene il nome 
dell' eventuale proxy, può essere nuli; 

• sProxyBypass, nome del proxy opzionale, può es- 
sere nuli) 

• nFlags, flag indicante diverse opzioni: connessione 
asincrona, da cache, offrine, per questo parametro 
abbiamo utilizzato il valore di default. 



La funzione restituisce rhandle della connessione che 
verrà utilizzata nella procedura Connessionelnternet. 
Notate che le API si trovano nel file Winlnet.dll. 

Private Sub ConnessioneInternet_Click() 

If sessioneinternet = Then 

MsgBox "bisogna prima creare una sessione Internet" 
Exit sub 

End If 

sessionefcp=InternetConnect(sessioneinternet, "pasta", "21" 
"anonymous", "guest", INTERNET_SERVICE_FTP, 0, 0) 

End Sub 

Nella suddetta procedura testiamo innanzitutto resi- 
stenza di una sessione Internet, se la risposta è affer- 
mativa andiamo ad "aprire" una sessione ftp richia- 
mando la funzione API InternetConnect, della quale ve- 
diamo sommariamente la sintassi. 

Public Declare Function InternetConnect 

Lib "wininet.dll" Alias "InternetConnectA" ( 

ByVal hlnternetSession As Long, 

ByVal sServerName As String, 

ByVal nServerPort As Integer, 

ByVal sUserName As String, 

ByVal sPassword As String, 

ByVal nService As Long, 

ByVal dwFlags As Long, 

ByVal dwContext As Long) As Long 

• hlnternetSession, handle sessione internet (creata 
come descritto in precedenza); 

• sServerName, stringa che indica il nome del ser- 
ver; 

• nServerPort, porta del server, per il servizio FTP 
(sarà la 21); 

• sUserName, username per la connessione; 

• sPassword, password per la connessione; 

• nService, tipo di servizio richiesto (FTP, http). 

Gli ultimi due parametri non li abbiamo utilizzati 
(l'impostiamo sul valore zero). Questa funzione resti- 
tuisce Thandle della sessione FTP (se l'operazione ha 
successo). Per chiudere la connessione utilizziamo il 
codice inserito nel pulsante Chiudi Connessione. 

Private Sub ChiudiConnessione_Click() 

Cali InternetCloseHandle(sessioneinternet) 

Cali InternetCloseHandle(sessioneftp) 

End Sub 

Con la ChiudiConnessionejClick chiudiamo sia la sessio- 
ne Internet che quella ftp, il tutto attraverso Internet- 
CloseHandle che restituisce il valore booleano true se 
l'operazione ha avuto esito positivo. La sintassi di que- 
sta funzione è semplice: 

Public Declare Function InternetCloseHandle 

Lib "wininet.dll" (ByVal hlnet As Long) As Integer 




isual 

Basic 



a; 



Web server 

I Gli esempi fatti 
| nell'articolo sono 
eseguiti utilizzando Vi- 
sual Basic e US {In- 
ternet Information 
Server) che come è 
noto permette di ge- 
stire un Server Web ed 
un Server FTP. 
Naturalmente con i si- 
stemi operativi Win- 
dows 2000 e Windows 
XP si lavora con US, 
mentre con Windows 
95/98 si lavora con 
Personal Web Server 
(PWE). 

Quest'ultimo si trova 
nella suite Visual Stu- 
dio oppure nella car- 
tella add-ons del Cd 
del sistema operativo. 
Se sul vostro computer 
non avete installato né 
US e né PWS potete 
testare gli esempi 
iscrivendovi ad una 
Community come Ly- 
cos: 
http://www.tripod.lycos.it/ 

Ultimo avvertimento il 
PWS o l'US installato 
deve essere nella stes- 
sa lingua di Visual Ba- 
sic altrimenti avrete 
delle sgradite sorpre- 
se. 



http://www.itportal.it 



b b 



3 ►►► 89 




Visual 

Basic 



Winsock 



\/%\ Winsock è il con- 
l^^l trollo che consen- 
te di utilizzare i proto- 
colli di trasmissione 
TCP/IP, UDP, FTP ecc. 
Il controllo WinSock, fa 
parte della libreria Mi- 
crosoft Winsock Con- 
trol 6.0 (in cui è pre- 
sente l'ocx MSWIN- 
SCK). Questo controllo 
è stato descritto nel- 
l'articolo: Il controllo 
per accedere ai servizi 
di rete, nel quale abbia- 
mo illustrato come im- 
plementare una Chat. 




Fig. 3: La finestra delle proprietà del controllo 
Internet Transfer 

Accetta come parametro l'handle della connessione. 
Ora vediamo come effettuare il Download di un file. 
Nel pulsante Scarica file inseriamo il seguente codice: 

Private Sub ScaricaFile_Click() 

If sessioneftp = Then 

MsgBox "bisogna prima creare una sessione ftp" 

Exit sub 

End If 

If FtpGetFile(sessioneftp, "provaftptxt.txt", 

"c:\provadowload.txt", False, 0, 1, 0) = False Then 

MsgBox "errore" 

End If 

End Sub 

Dopo aver constatato l'esistenza di una sessione ftp, la 
funzione richiama TAPI che consente di scaricare il fi- 
le e cioè la FtpGetFile, di cui descriviamo i parametri 
fondamentali: 

Public Declare Function FtpGetFile 

Lib "wininet.dll" Alias "FtpGetFileA" ( 

ByVal hFtpSession As Long, 

ByVal IpszRemoteFile As String, 

ByVal IpszNewFile As String, 

ByVal fFaillfExists As Boolean, 

ByVal dwFlagsAndAttributes As Long, 

ByVal dwFlags As Long, 

ByVal dwContext As Long) As Boolean 

• hFtpSession, handle della sessione ftp; 

• IpszRemoteFile, file da scaricare; 

• IpszNewFile, percorso e nome del file destinatario. 

Per gli altri parametri utilizziamo i valori di default. 
Notate che il file da scaricare è provaftptxt.txt e che 
verrà scaricato nella root del disco e:/ (con il nome pro- 
vadowload.txt). Vediamo come effettuare un upload 
verso il server "remoto", per tale scopo utilizziamo la 
seguente funzione. 

Public Declare Function FtpPutFile 

Lib "wininet.dll" Alias "FtpPutFileA" ( 
ByVal hFtpSession As Long, 



ByVal IpszLocalFile As String, 

ByVal IpszRemoteFile As String, 

ByVal dwFlags As Long, 

ByVal dwContext As Long) As Boolean 

• hFtpSession, handle della sessione ftp; 

• IpszLocalFile, file da scaricare sul server remoto; 

• IpszRemoteFile, percorso e nome del file sul ser- 
ver remoto; 

• dwFlags, flag indicante il tipo di trasferimento 
(ASCII o binario); 

• dwContext, impostato su zero. 

Ecco come utilizziamo questa funzione: 

Private Sub Scarica_Click() 

If sessioneftp = Then 

MsgBox "bisogna prima creare una sessione ftp" 

Exit sub 

End If 

If FtpPutFile(sessioneftp, "c:\provaput.txt", 

"\provaftp\provaput.txt", 1, 0) = False Then 

MsgBox "errore" 

End If 

End Sub 

La funzione restituisce true se l'operazione avviene 
correttamente. L'eliminazione di un file sul server può 
essere fatta attraverso la funzione FtpDeleteFileO. 

FtpDeleteFile(sessioneftp, "\provaftp\provaput.txt") 

In questo caso i parametri sono semplicemente: 
Thandle della sessione ftp ed il nome del file da can- 
cellare sul server. Dalla funzione sarà restituito il valo- 
re true o false in base all'esito dell'operazione. 



^Jnjxj 



J File Modifica Visualizza P J 



J ■*= Indietro " ^ " gj | 



J Indirizzo |(^I ftp: //pasta/ 3 ^ Vai 



provaftp provaftpTX,. 



^Jnjxj 



File Modifica Visualizza Prefei * 



■sh 



Indirizzo |Cg] ftp://pasta/provaftp/ J^J ^Vai 



d m £ 

provaftp2 provaA5P,asp ProvaHTML, 



Utent j.Jf7 Intranet locale 



^ |utente: A IH Intranet locale 



Fig. 4: Uno spazio FTP visto attraverso il Browser 
Internet Explorer Internet Transfer. 



CONCLUSIONE 

Ora che avete capito come utilizzare il protocollo FTP 
potete realizzare un FTP Client con l'interfaccia nello 
stile Explorer. Questo tipo d'interfaccia di solito preve- 
de un "albero" (treeview) che presenta la struttura del- 
le directory presenti nell'account ed una listview che 
mostra i file contenuti nella directory selezionata. 

Massimo Autiero 



90^^^ F e 



http: //www. itportal.it 



Modellazione 
tramite Surface» 



3D Studio Max 



Pietro Canini 



Vediamo come utilizzare uno tra i più versatili strumenti di modellazione, 

il Surface, costruendo una vasca. Non mancheranno gli strumenti già visti 

in precedenza, come: le operazioni booleane, le estrusioni ed alcuni 

modificatori. 



Ben ritrovati davanti ai nostri PC 
con 3dsmax (in uscita la versio- 
ne 5.0, con tante novità; prima 
tra tutte un nuovo motore di rendering 
cui è possibile applicare Radiosity e 
Global lllumination). Uno dei metodi 
migliori per modellare oggetti curvi, 
organici e non, complessi sono gli stru- 
menti di Superficie. Questi strumenti 
sono composti da due modificatori: 
Cross Section e Surface. Il Cross 
Section crea delle spline di congiunzio- 
ne tra spline esistenti. Ad esempio se 
abbiamo un cerchio sotto ed un cer- 
chio sopra e gli applichiamo il Cross 
Section, vediamo delle spline che colle- 
gano i due cerchi per formare un cilin- 
dro. Nota bene che le spline che cree- 



remo noi, dovranno essere ordinate e 
unite (se le creiamo separatamente) col 
comando Attach. Applicando poi il 
modificatore Surface al modello spline, 
avremo delle patch che ricoprono la 
struttura da noi creata. Nel caso del 
cilindro, oltre al reticolato in wireframe, 
avremo anche le patch che formano 
una struttura chiusa e visibile. Dei con- 
sigli utili per chi usa questi strumenti 
sono: l'utilizzo di figure di riferimento 
da applicare su dei piani in back- 
ground; lavorazione su metà modello, 
per poi specchiarlo (se è simmetrico); 
utilizzare lo snap3d a vertice; creare 
una copia del modello usando l'opzio- 
ne Reference ed applicandogli il modifi- 
catore Surface, in modo da vedere, 



mentre si modellano le spline, i cam- 
biamenti sull'altro oggetto; la maggior 
parte delle volte, quando dei vertici 
coincidono, Max chiederà di saldare i 
vertici, è opportuno dire di No in quan- 
to è sempre possibile unirli dopo col 
comando Weld. Con questo metodo 
dunque, è possibile creare teste 
umane, automobili, aerei, ecc.. 
Modelleremo un oggetto semplice nella 
sua creazione, ma fondamentale per 
capire subito questo metodo di model- 
lazione, la vasca. Vedremo, dopo la 
modellazione: il materiale da applicargli 
e cioè un bianco con leggere riflessioni 
sfocate tramite lo shader Raytrace; altri 
parametri quali align, array, ed alcuni 
modificatori. Iniziamo a modellare... 




1 La prima spline 



Avviamo 3DSMax ed iniziamo 
a creare le spline necessarie 
per il nostro Surface. 
Andate quindi nel pannello 
Create/ Shapes e cliccate 
su Rectangle. Nella vista 
Top create un rettangolo di 
dimensione qualsiasi, ed 
andiamo nel pannello Modify 



per definirne la grandezza. 
Nei parametri del rettangolo 
(Rullout Parameters) 
impostiamo Length = 70; 
Width = 140; Corner 
Radius = 15. Questa sarà la 
base della nostra vasca, ora 
creiamo le altre spline 
partendo da questa. 



http://www.itportal.it 



e b b 



3 >>> 91 



DBSQu 



gMSSkBmim 



f 2-3-4-5 Le altre spline 



Sempre nel pannello 
Modify aprite la tendina 
dei modificatori e dalla lista 
scegliete Edit Spline, in 
modo da trasformare il 
rettangolo in una forma 
(Spline) modificabile 
(Edit). Ora col 



modificatore applicato 
scegliete di lavorare a 
livello Spline, quindi 
selezionate il rettangolo 
che diventerà rosso. 
Nella vista Front spostate 
(Select and Move), solo 
sull'asse Y, il rettangolo in 





alto (di circa 15 unità) 
tenendo premuto Shift da 
tastiera (in modo da 
clonarlo). Ingranditelo 
(Select and Uniform 
Scale) di circa 15 unita 
(3DStudio in X, Y, Z 
segnerà quindi 115 unità 
perché parte da 100). 
Ora ancora col Select and 



Move e Shift premuto 
cloniamo sempre sull'asse 
Y l'ultima spline creata, 
spostandola in alto di circa 
45 unità. 

Stesso procedimento per 
quest'ultima spline creata, 
questa volta su di 6 unità. 
Ora ingranditela di 20 unità 
(X, Y, Z 120 u). 



Il Cross Section 6 



A questo punto disattivate 
la modalità spline 
(ricliccandoci sopra). 
Dalla tendina dei 
modificatori scegliete 
Cross Section. 
Nei suoi parametri 
spuntate Smooth in modo 
da avere le linee di 
giunzione smussate. 
Se provate ad applicargli 
anche il modificatore 



Surface, noterete che la 
forma della vasca c'è, ma 
non è chiusa alla base. 
Quindi rilevate il Surface 
che avete appena messo 
per provare, lasciando 
Cross Section come 
ultimo modificatore. 
Nella lista dei modificatori 
scegliete di nuovo Edit 
Spline. 










■ 



92 >>> F e 




http: //www. itportal.it 




Chiusura 7-8-9-10* 



Scegliete di lavorare a 
livello Segment. Mettete 
la vista prospettica in 
modo da poter vedere tutti 
i vertici che formano la 
base (la prima spline 
creata). Attivate lo 
Snap3D, cliccateci col 
tasto destro sopra e nel 



Grid and Snap Settings 

spuntate solo l'opzione 
Vertex. Nel rullout 
Geometry, cliccate su 
Create Line e disattivate 
l'opzione accanto 
PolyConnect. Nella vista 
prospettica, tracciate delle 
linee verticali tra i vertici 




T — lopì) i — adou! nvor 




r" Linear |~" Bind first 
r Closed r Bind l< 



Connect | Inserì | 

Make First | Fuse | 

Reverse | 



superiori e quelli inferiori 
(con lo snap attivo, la 
freccetta punterà 
direttamente sui vertici). 
Disattivate il Create Line 
ricliccandoci sopra. 
Ora selezionate una linea 
verticale che avete appena 
creato e sempre nel rullout 
Geometry impostate il 
valore 2 accanto a Divide, 
quindi cliccate su Divide. 



Ora al segmento verranno 
aggiunti 2 vertici; fate lo 
stesso per l'altra linea 
verticale. 

Riattivate Create Line e 
create le linee orizzontali 
come in Fig. 10 (ad ogni 
linea creata, quindi da 
vertice a vertice, cliccate 
col tasto destro del mouse 
per interrompere il 
segmento). 



M1 II Surface 




Disattivate Create 
Line e la modalità 
di lavorazione sul 
segmento, 
ricliccando su 
Segment. Dalla 
lista dei modificatori 
scegliete Surface e 
lasciate i parametri 
così come sono. 
Ecco creato 
l'interno della 
vasca. 

Se dovessero 
esserci delle parti 
bucate sulla base, 
significa che 
qualche vertice non 
è sovrapposto a 
quello sottostante; 
quindi spostatelo 
esattamente sopra 



e quando si 
chiederà di saldare, 
scegliete No. 
Abbiamo visto 
quindi che il 
modificatore 
Surface funziona 
su poligoni 
quadrati, quindi 
quando sono 
composti da quattro 
vertici. Infatti il 
procedimento fatto 
per chiudere la base 
non è altro che 
l'aggiunta di vertici 
affinché si formino 
dei poligoni 
quadrati. 

Continuiamo con la 
creazione della 
vasca. 



■ 



http://www.itportal.it 




e b b 



3 >>> 93 



DBSQu 



gMSSkBmim 



12-13-14-15-16 II materiale 



Come avrete notato, un lato della vasca 
è trasparente; quindi aprite il Material 
Editor e rimediamo a questo fatto. In 
uno Slot vuoto, nella tendina Shader 
Basic Parameters spuntate l'opzione 
2-Sided (in modo da rendere visibile la 



m 



\[T 



':. >»: ', j .. f "'-. v: i-' 



|Blinn 



"3] 



V Wire F 2-Sided 

Face Map V Faceted 



Vi'Mfr ì~' '.•:•■: rcs\ti?:-?rj 



Ànnbient: | 


Diffuse: Q 
Specular: 1 


U 
U 



e 



-Self-lllumination 

r Color fO t\ _| 



Opacitv: fTOO ^J 



Specular Highhghts 
Specular Level: [70 ^J 
Glossiness: [50 ^J 
Soften: [oX~ t\ 




WM 



jfr^ l fe l x i # i ù i °è l o) i © ifjìf «, & 


rj^ \ |MapttO _*J Noise 




r - Coordinates |- 






Source:|Object>Cir^ _^j Map Channel: fi ^J 




Offset Tiling Angle: 




X:|0,0 Zj |1.,0 t] 10,0 t] 




Y:|0,0 t] 1 1.0 ijj (0,0 t| 




z: : jao tj 1 1.0 Z] |0,0 t] 




Blur: pTo t\ Blur offset: 1 0,0 t\ 






r| - Noise Parameters 


Noise Type: (* Regular C Fractal C Turbulence 


Noise Threshold: High:) 1,0 t} Levels:|3,0 vj 


Size:|5,0 t] Low:|0,0 t] Phase:|0,0 t] 




^^^^^^ Maps 




Color 81 | None | W 




Swap | 




Color tt2 p None | [7 






[|+ Output |] 





parte trasparente); impostate il colore 
Diffuse Bianco (RGB = 255); 
Specular Level = 70; Glossiness = 






I «fa I X 1*1 A l°èlsJJ® |[ìff«iA 

\ |Maptì3 TJl 




<* Use Environnrif 



Global Locai 

W W Enable Flaytracing 

1^ R Àntialiasing 

F W SelfReflect/Refract 

W W Àtmosphere 

F F7 Reflect/Refract Material ID 

W W Object: ed objects 

V " 

W P" Color Density / Fog 



Raytracer Parameters 



<* ÀutoDetect 
C Reflection 
C Refraction 



Options... 



i •■:'• •. ". :■•;-- 



Background 

■' : : he f.nvironrneri! SeUinq: 

■ Ir 



EI 



_j."""^"'L'£_ 



Copy Àntialiasing Parameters 

ni l i si ili i s(-i l. i 

Global--> Locai | Local-->Global 
Adaptive Control 



4nfeliasìng is curranl'iv' enabbi 
I - Àdaptive Initial Rays: [4 

Threshold: fai ' t\ Man. Rays: [32~ 



Blur/ Defocus (Distance Blur) 
Blur Offset: fO0 ^J Defocusing: [02 ^] 

BlurAspect: pLO _^| Defocus Aspect: pTo t\ 



Blur Map: 
Defocus Map: 



Jr 
Jr 



E 




rtasikix i#ia iiaifijj® i[ìff.«!c 

\ Il ■ Default T[ Standard 




ULAA 



■ 
J 

— ! i-0 



Soften: fai - ^J 



:.,-r-i,ur-H ,',-ihM. ' r 



Amount 

r Ambient Color . . . 1 1 00 ^J 

r Dif fuse Color.... flOO"^J _ 

V Specular Color . .| 1 00 t] 

\~ Specular Level . 1 1 00 ^J _ 

l~~ Glossiness 1 1 00 ^J 

r Self-lllumination. 1 1 00 ^J _ 

r Opacità fl00~^J _ 

r Filter Color flOT^J _ 

W Burmp [3 t\ _ 



Map 
None 



50. Nella tendina Maps cliccate su 
None accanto a Bump per definire un 
leggerissimo rilievo; dalla lista scegliete 
Noise. Impostate, nei parametri del 
Noise, Size = 5. Tornate un livello 
indietro (Go to Parent) e mettete 
Bump Amount = 3. Ora cliccate su 
None accanto a Reflection e dalla lista 
scegliete Raytrace. In RayTrace 
Parameters cliccate su Option ed atti- 
vate l'opzione Àntialiasing in Global. 
Ora aprite il menù a tendina 
Àntialiasing e puntate l'opzione 
Override Global Settings; in 
Defocusing impostate 0,2. 
In questo modo avrete delle riflessioni 
sfocate ma con un notevole aumento di 
tempo nel rendering. Tornate un livello 
indietro e mettere Reflection Amount 
= 15. Applicate il materiale alla vasca 
se non l'avete ancora fatto. 



Creiamo, tramite le 

operazioni booleane, la 

struttura base della 

vasca. 

Andate nel pannello 

Create / Geometry / 

Extended Primitives e 

cliccate su Chamfer Box. 

Nella vista Top create la 

geometria di dimensioni 

Length = 110; 

Width = 210; 

Height = 85; 

Fillet = 2,5. 

Con il box selezionato, 



La base 17 



cliccate sul comando 
Align (si può trovare 
anche nel menù a tendina 
in alto Tools / Align; 
oppure ALT+A) e poi 
sulla vasca. 
Nei parametri di 
allineamento in Align 
Position spuntate 
l'opzione X Position e Y 
Position; quindi cliccate 
su Apply e poi su Ok. 
Ora il box risulterà 
centrato rispetto alla 
vasca. 




■aia 



U^M 



*|fc|&|«|BI|T| 

|ch a mfe,B™01 


| H0dfeLiSt 


•I 




CopHoles Tapcr 


iSH- 


Rela, 


=Hi 




" -rSrl 






■WI^IV 


E 


f- Parameters 



■ 



94 >>> F e 




http: //www. itportal.it 




1 8-1 9-20 La sottrazione 



24-25-26 Aggiustamenti 



Nel pannello Create/ 
Geometry / Standard 
Primitives cliccate su Box e 
nella vista Top create la geo- 
metria di dimensioni Length = 
87,048; Width = 169,492; 
Height = 86,629 e posiziona- 
telo come in Fig. 18. 
Selezionate il Chamfer Box 



creato prima, andate nel pan- 
nello Create / Geometry / 
Compound Objects / Boolean 
e cliccate su Pick Operand B e 

selezionate l'ultimo Box creato. 
Lasciando i parametri booleani 
così come sono, avrete una sot- 
trazione del box, l'interno della 
vasca diverrà di nuovo visibile. 



Noterete che le maioliche a de- 
stra e in basso hanno dimen- 
sioni non conformi, andiamo ad 
aggiustarle. Per far sembrare 
che sono state tagliare dalla 
mano dell'uomo, selezionate 
tutta la fila in basso, andate nel 
pannello Modify e dalla lista 
dei modificatori scegliete Slice. 




Nelle sue opzioni scegliete 
Remove Bottom. Si creerà 
così un piano di ritaglio che eli- 
mina la parte sottostante. 
Bisogna però regolare il piano 
per far si che tagli le maioliche 
quando inizia lo smussamente 
del chamfer box sottostante. 
Fate quindi click su Slice in 

modo da lavorare a 
livello sotto l'oggetto 
e quindi muovere il 
ripiano (Gizmo) sul- 
l'asse Y. Una volta 
spostato il gizmo 
ricliccate su Slice 
per disattivare la 
modalità sub- 
objects; selezionate 
la fila di maioliche a 
destra ed eseguite 
lo stesso procedi- 
mento, questa volta 
però ruotando il 
gizmo di 90 gradi. 
Ora renderizzate. 




Conclusioni 



21-22-23 Le maioliche 




Il tutorial si conclude qua, 
potete perfezionare la scena 
applicando texture agli 
oggetti creati; magari sulle 
maioliche applicando sempre 
una leggera riflessione 
sfocata. Abbiamo visto come 
il nuovo metodo di 
modellazione Surface sia 



efficiente e se usato con 
maestria, perdendoci molto 
più tempo, si possono tirare 
fuori delle superfici 
organiche realistiche. 
Il mio spazio si conclude qui, 
quindi ci ritroviamo i 
prossimi mesi con un altro 
interessante articolo. 



Creiamo un Chamfer Box di 
dimensioni Length = 30; 
Width = 30; Height = 2,5; 
Fillet = 0,5 e posizionatelo 
come in Fig. 21; ecco la nostra 



prima maiolica che moltipliche- 
remo per creare le altre, solo 
sul lato frontale (se le volete 
anche sugli altri lati, seguite di 
nuovo questo procedimento). 



p^sJP 1 
p— sjp- 

fTooTi Sj 1 100.0 






31; Array Dimension 


-J| [iOOO-U [T Scale ij 1™^ \Wn~ i\ [iOOO-^P^n. T 


ir 


spuntate l'opzione 2D; 
Count ID = 7; Count 2D 
= 3; Incrementai Row 








- 




« Copj 


* 20 [3— si p — si p — si Rra~sJ 
r 3 D n — =j fM — u p - u p - U 


^,,, J . r 


Offset Z = -31, quindi 


Reset Al Parameters 


cliccate su Ok. 


n>- 1 ™ | 


Con la maiolica selezionata sce- 


L_x 


1* ^Srr* 


gliete l'opzione Array (menù a 
tendina Tools/ Array; oppure 
l'icona nella barra degli stru- 
menti in alto). Mettete: 
Incrementai / Move / X = 


IBI. 



■ 



http://www.itportal.it 




e b b 



3 >>> 95 



4 4 < < < 4 4 < < Advanced Edition 

Simulare 

UNA RETE CON NETWORK SIMULATOR Networking 




Analizzare il comportamento di una rete, locale, 
metropolitana, cablata, wireless e di qualsiasi altra 
natura. È fondamentale per ricavare le massime 
prestazioni. 



Network Simulator, brevemente NS, è un simu- 
latore universale di reti, conosciutissimo in 
ambito accademico, ma non solo, permette di 
progettare una rete di telecomunicazioni di qualsiasi ti- 
po e ottenere informazioni di ogni genere sul suo fun- 
zionamento. NS permette di simulare praticamente 
ogni aspetto della rete, partendo dai suoi componenti 
fondamentali, cioè nodi, router, link, passando per i di- 
versi protocolli coperti, ad esempio CSMA/CD a livel- 
lo di linea, IP a livello di rete, TCP a livello di trasporto 
e così via, coprendo praticamente l'intera pila OSI. Il 
cuore di NS è scritto interamente in C++ ed in filosofia 
open source, permettendo di creare nuovi oggetti o 
modificare quelli esistenti. Infatti, col susseguirsi delle 
sue varie release, attualmente siamo giunti alla versio- 
ne 2.1b9, sono state varie le aggiunte e modifiche da 
parte dei gruppi di lavoro sparsi su tutto il pianeta. L'u- 
tente normale, il sistemista di rete, lo studente di reti di 
telecomunicazioni, ha inoltre a disposizione un lin- 
guaggio di scripting, OTcl (Object Tool Command Lan- 
guage), che in maniera semplice e veloce permette di 
descrivere una topologia di rete, il suo traffico, il movi- 
mento dei nodi mobili, e i risultati che si vogliono rica- 
vare dalla simulazione. 



PERCHE DUE LINGUAGGI? 

L'Object Tel, è un'estensione del Tcl/Tk per la pro- 
grammazione object-oriented, in pratica fornisce un'in- 
terfaccia per l'utente, che così non deve assolutamente 
mettere mano al codice C++. In pratica NS è costituito 
da una gerarchia di classi C++, detta gerarchia compi- 
lata, ed una gerarchia OTcl detta invece interpretata. Le 
due gerarchie sono strettamente legate, dal punto di vi- 
sta dell'utente c'è una relazione uno ad uno fra una 
classe C++ ed una OTcl. L'utente crea nuovi oggetti at- 
traverso l'interprete, questi oggetti vengono istanziati 
al suo interno e a questo punto vengono cercati i corri- 
spondenti oggetti nella gerarchia compilata. Sembra 
più complicato a dirsi che a farsi, ma c'è naturalmente 
un motivo che porta all'uso di due linguaggi diversi 
per un simulatore di reti. Da una parte la simulazione 



dettagliata di protocolli di rete richiede un linguaggio 
di programmazione di sistema, che sia efficiente nella 
manipolazione di byte, degli header dei pacchetti, e 
nell'esecuzione di algoritmi su grosse quantità di dati. 
Per questi compiti quello che importa maggiormente è 
la velocità di esecuzione run-time. Dall'altra parte in- 
vece simulare una rete o progettarla, richiede la possi- 
bilità di variare parametri, creare gli scenari di simula- 
zione, rimandare in esecuzione una stessa simulazione 
più volte, compiti per cui una veloce esecuzione run-ti- 
me è meno importante rispetto alla velocità di iterazio- 
ne, cioè cambiamento del modello - riesecuzione. 



COMINCIAMO 

Esistono varie distribuzioni del simulatore, per Unix e 
Windows, da compilare a partire dai vari componenti 
che lo costituiscono, o in pacchetti all-in-one che con- 
tengono tutto ciò che ci serve. Consigliamo di usare NS 
sotto linux, sul quale d'altronde è stato sviluppato, per- 
ché avremo a disposizione una marea di tool comple- 
mentari che ci faciliteranno il compito di simulazione 
ed analisi dei risultati, oltre a poter dare un'occhiata al- 
l'intero codice sorgente di NS. Il pacchetto all-in-one 
per le piattaforme Unix è pero, nell'ultima release, di 
quasi 40Mb, così chi vuole iniziare a sperimentare con 
Ns può anche procurarsi le versioni precompilate per 
Windows, sia di Ns che del tool Nam. Nam, o Network 
Animator, darà un aspetto anche grafico alle nostre si- 
mulazioni, permettendoci di seguire visivamente la lo- 
ro evoluzione, ad esempio seguendo il movimento dei 
pacchetti lungo i link, il riempirsi delle code in un rou- 
ter o anche il movimento di nodi mobili. Nei pacchetti 
all-in-one sono inoltre contenuti tutti i sorgenti sia del 
simulatore NS, che di Nam, che di tutti gli altri tools. 
Ad esempio per facilitare la creazione dei grafici dei ri- 
sultati, troviamo l'utility Xgraph, mentre per facilitare 
la creazione degli scenari delle simulazioni, e per poter 
così programmare intere campagne di simulazione in 
modo da avere risultati più reali, troviamo degli script 
e dei file eseguibili per la generazione del traffico e per 
la generazione dei movimenti dei nodi mobili. Senza 



File sul CD 

\soft\codice\NSimulator\ 



a: 



Prestazioni 

I II C++ è veloce 
| da eseguire ma 
lento da modificare, 
rendendolo ideale per 
l'implementazione 
dettagliata di un pro- 
tocollo. L'OTcl gira più 
lentamente ma può 
essere cambiato ve- 
locemente e interatti- 
vamente. 



http://www.itportal.it 



3 ►►► 97 




Networking 



Linux 

r^&l Nell'articolo ab- 
V----J\ biamo visto e di- 
mostrato come sia 
possibile con NS simu- 
lare una qualsiasi tipo- 
logia e topologia di re- 
te, sia come punto di 
partenza per il proget- 
to, sia come strumento 
per l'analisi delle pre- 
stazioni. Per chi è dav- 
vero interessato consi- 
gliamo di scaricare e 
installare la versione 
Linux di Ns e natural- 
mente la completissi- 
ma documentazione. 



contare il fatto che possiamo anche dare un'occhiata ad 
una grossa raccolta di esempi su ogni tipo di rete, cosa 
che senz'altro aiuta più di ogni manuale. Sia in Win- 
dows che in Unix si lavora in ambiente a riga di co- 
mando. L'input da dare al simulatore è costituito da un 
file di testo con estensione tei contenente non solo la 
descrizione della rete da simulare ma anche le direttive 
del simulatore, ad esempio il tempo di simulazione, i 
file di input /output, gli eventi da tracciare, o anche 
dettagli puramente grafici come il colore e la dimen- 
sione dei nodi. 



UN PRIMO ESEMPIO 

Vediamo un primo semplice esempio per cominciare a 
prendere pratica con il linguaggio OTcl e i tool che ab- 
biamo a disposizione. Supponiamo di voler simulare 
una semplice rete costituita da due nodi, connessi da 
un link full-duplex, e l'unico tipo di traffico presente 
sia di tipo costante, con pacchetti di dimensione 500 
bytes spediti da un nodo all'altro. Iniziamo a scrivere il 
nostro primo script, con un semplice editor di testo. In- 
nanzitutto si definisce un oggetto Simulator ed il nome 
del file di output per Nam: 



^JnJxJl 



| « | M |^J »» | ►► | ± II" 0.800000 | stEP=2.0i 




Fig. 1: Il risultato della nostra prima simulazione. 



set ns [new Simulator] 

set namFile [open trace. nam w] 

poi, con il seguente commando, diciamo ad Ns di trac- 
ciare tutto sul file .nam 

$ns namtrace-all $namFile 

A questo punto dobbiamo definire i due nodi ed il link 
che li congiunge, con una capacità di 1Mb e tempo di 
propagazione di 20ms: 

set NodeO [$ns node] 

set Nodel [$ns node] 

$ns duplex-link $Node0 $Nodel 1Mb 20ms DropTail 



set DuplexLinkO [$ns link $Node0 $Nodel] 

Non resta che generare il traffico, dal nodo che abbia- 
mo chiamato NodeO faremo partire dei pacchetti da 500 
byte a bit-rate costante di uno ogni 0.005 secondi, che 
verranno ricevuti da Nodel. Ecco come fare nel detta- 
glio: gli end-point di rete dove vengono generati e con- 
sumati pacchetti sono detti Agent, per prima cosa defi- 
niamo un Agent di tipo UDP, chiamandolo UDP0: 

set UDP0 [new Agent/UDP] 

e lo assegniamo al nodo che abbiamo chiamato NodeO: 

$ns attach-agent $Node0 $UDP0 

Quindi abbiamo bisogno di un Agent che riceva i pac- 
chetti, per fare ciò creiamo un Agent di tipo Nuli, e lo 
"attacchiamo" al secondo nodo: 

set NullQ [new Agent/Null] 

$ns attach-agent $Nodel $Null0 

All' Agent UDP del nodo NodeO assegniamo inoltre il 
generatore di traffico Constant Bit Rate, con i relativi pa- 
rametri: 

set CBRO [new Application/Traffic/CBR] 

$CBR0 set interval, 0.005 

$CBR0 set packetSize, 500 

$CBR0 set random_ 

$CBR0 attach-agent $UDP0 

Ora possiamo conettere i due Agent: 

$ns connect $UDP0 $Null0 

Essendo Ns un simulatore ad eventi discreti, bisogna 
decidere il tempo di durata della simulazione, che sce- 
glieremo pari a 10 secondi e gli istanti di inizio e fine 
della trasmissione dei pacchetti. Per comodità inoltre 
definiamo una semplice procedura che ci servirà a 
chiudere il file di output e lanciare l'esecuzione di 
Nam. 

proc finish {} { 

global ns 

global namFile 

$ns flush-trace 

dose $namFile 

exec nam trace.nam & 

exit } 

Il generatore di traffico CBR inizierà a trasmettere all'i- 
stante 0.5 secondi e finirà all'istante 4.5 secondi: 



$ns 


at .5 ' 


$CBR0 start" 


$ns 


at 4.5 


"$CBR0 stop" 


$ns 


at 10.0 "finish" 



98^^ F e b b 



3 



http://www.itportal.it 



Infine possiamo chiamare il metodo run del simulatore: 

$ns run 

Supponendo di aver salvato lo script come esempiol .tei 
possiamo far partire la simulazione dal prompt dei co- 
mandi con: > ns esempiol. tei. Dopo qualche secondo, 
per una simulazione così semplice, vedremo apparire 
la finestra del nam (vedi Fig. 1). Ns permette natural- 
mente di simulare situazioni molto più dinamiche, co- 
me tutti sappiamo è purtroppo possibile che un link fra 
due nodi di una rete ad un certo punto si guasti o si 
congestioni, o comunque non permetta la trasmissione 
di pacchetti su di esso. La caduta di un link è simulabi- 
le in Ns in modo molto semplice. Ad esempio se nel no- 
stro primo esempio vogliamo che il link fra i due nodi 
ad un certo punto cada, diciamo nell'intervallo di tem- 
po [2,3] secondi, basta aggiungere due righe nella se- 
guente maniera: 

$ns rtmodel-at 2.0 down $Nodel $Node2 

$ns rtmodel-at 3.0 up $Nodel $Node2 

Anche nella finestra del Nam vedremo questa situazio- 
ne, con il link che cambia colore e i pacchetti che vngo- 
no persi. 

SIMULIAMO UNA 

RETE WIRELESS MOBILE 

Cerchiamo di esplorare le capacità di NS con un esem- 
pio più complesso, ma che, con gli strumenti a disposi- 
zione, non richiede molto più di quello che abbiamo vi- 
sto. Supponiamo di voler simulare una rete wireless 
802.11 con i nodi aventi capacità di movimento, cioè ab- 
biamo a che fare con una vera e propria rete mobile. 
Inoltre vogliamo ottenere dalla simulazione risultati ri- 
guardanti ad esempio quanti dei pacchetti spediti arri- 
vano a destinazione, cioè il cosiddetto "Packet Delivery 
Ratio". La prima cosa da fare è quella di configurare i 
nodi mobili, compresa l'antenna e l'interfaccia radio. 
Usiamo un antenna omnidirezionale, e settiamo i para- 
metri in modo da averla ad un altezza di 1,5 metri e con 
guadagno unitario sia in trasmissione che in ricezione: 

Antenna/OmniAntenna set X_ 

Antenna/OmniAntenna set Y_ 

Antenna/OmniAntenna set Z_ 1.5 

Antenna/OmniAntenna set Gt_ 1.0 

Antenna/OmniAntenna set Gr_ 1.0 

Per quanto riguarda l'interfaccia radio, la configuriamo 
in modo che funzioni come una Lucent WaveLan 
914MHz., basta consultare il manuale della scheda e i 
parametri corrispondenti sono: 



« I « I ■ I » I » I ± 




Fig. 2: Un clic su un pacchetto per scoprirne tutte 
le caratteristiche. 

Phy/WirelessPhy set Rb_ 2*le6 

Phy/WirelessPhy set Pt_ 0.2818 

Phy/WirelessPhy set freq_ 914e+6 

Phy/WirelessPhy set L_ 1.0 

A questo punto configuriamo i nodi mobili, basta va- 
riare i parametri del comando node-config, descritti in 
modo esauriente nel manuale ufficiale di Ns, quelli che 
ci interessano maggiormente sono i seguenti: 

node-config -adhocRouting DSR \ #protocollo di routing ad hoc 

-IIType LL \ #tipo di link layer 

-macType Mac/802.11 \ #protocollo di livello MAC 

-ifqType Queue/DropTail/PriQueue \#accoramento 

e droppaggio dei pacchetti 

-ifqLen 50 \ lunghezza della coda 

-antType Antenna/OmniAntenna \ #tipo di antenna 

-propType Propagation/TwoRayGround \ #propagazione 

del segnale 

-phyType Phy/WirelessPhy \ #livello fisico 

-channelType $opt(chan) \ #canale fisico 

-topolnstance $wtopo \ #la topografia della rete 

-agentTrace OFF \ 

-routerTrace ON \ #tracciamo solo i pacchetti a livello 

Router 

-macTrace OFF 

Con altri parametri, qui non indicati, è anche possibile 
definire il modello energetico del nodo, ad esempio la 
potenza di trasmissione e ricezione, oltre ad altre carat- 
teristiche che qui stiamo trascurando. Ora può avveni- 
re la creazione vera e propria dei nodi, supponiamo di 
volerne 5: 



for {set i 0} {$i < 5 } {incr i} 


{ 


set node_($i) [$ns_ node] 


$node_($i) random-motion 


;# disabilita 

il movimento casuale} 



Phy/WirelessPhy 


set CPThresh_ 


10.0 




Phy/WirelessPhy 


set CSThresh_ 


1.559e- 


■11 


Phy/WirelessPhy 


set RXThresh_ 


3.652e- 


■10 



Per quanto riguarda la mobilità dei nodi, sotto Linux, è 
comodo e conveniente utilizzare l'utility setdest, che 
crea dei pattern di movimento casuali su file, diretta- 
mente richiamabili dallo script, specificando il nome 
del file da includere con il comando: 




Networking 



Sul Web 

• Sito ufficiale 

http://www.isi.edu 
/nsnam/ns/index.html 

• NS by example 

http://nile.wpi.edu/NS/ 

• Marc Grei's Tutorial 

http://www.isi.edu/nsnam 
/ns/tutorial/index.html 



http://www.itportal.it 



3 ►►► 99 




Networking 



Bibliografia 

• THE VINT PROJECT - 

"THE NS MANUAL 

(FORMERLY NS NOTES 

AND DOCUMENTA- 

TION)", 

UC Berkeley, LBL, 

USC/ISI e Xerox 

PARC. 



source miadir/file_traffico 

Altrimenti possiamo definire da codice il modello di 
movimento con delle righe come le seguenti: 

# inizialmente il nodo è nel punto (x,y,x)=(200, 100,0) 

$node_(0) set X_ 200.0 

$node_(0) set Y_ 100.0 

$node_(0) set Z_ 0.0 

# all'istante 2.0 secondi si muove verso il punto (300,200,0) 
$ns_ at 2.0 "$node_(0) setdest 300.0 200.0 0" 

Un'altra possibilità ancora, è quella di far muovere un 
nodo in modo casuale, basta abilitare il movimento 
random e usare la primitiva start: 

$nodomobile random-motion 1 

$nodomobile start 

Non resta che generare il traffico. Come visto nel pri- 
mo esempio, per creare una connessione di tipo CBR 
dal nodo 2 al nodo 3, che inizia all'istante 10.0, proce- 
diamo così: 

set udp_(0) [new Agent/UDP] 

$ns_ attach-agent $node_(2) $udp_(0) 

set null_(0) [new Agent/Null] 

$ns_ attach-agent $node_(3) $null_(0) 

set cbr_(0) [new Application/Traffic/CBR] 

$cbr_(0) set packetSize, 512 

$cbr_(0) set interval, 0.05 

$cbr_(0) set random_ 1 

$cbr_(0) set maxpkts, 10000 

$cbr_(0) attach-agent $udp_(0) 

$ns_ connect $udp_(0) $null_(0) 

$ns_ at 10 "$cbr_(0) start" 

Sempre nel pacchetto all-in-one di Ns, è contenuto uno 
script, cbrgen.tcl che, mandato in esecuzione con gli ap- 
propriati parametri, genera un file contenente la de- 
scrizione del traffico della rete. Analogamente a quan- 
to visto per i pattern di movimento possiamo include- 
re questo file nello script con il comando source. 
Lo script completo e funzionante è contenuto nel file 
esempio2.tcl. Dandolo in pasto al simulatore NS otter- 
remo due file di output. Uno con estensione .tr che con- 
tiene il tracing di ogni evento della simulazione. A que- 
sto punto basta analizzare quest'ultimo, magari con un 
tool esistente (ad esempio trgraph), oppure con qual- 
che riga di codice possiamo scriverci un parser perso- 
nalizzato. Ad esempio, la riga 



r 40.647 2 RTR 



8 cbr 512 [0 0] 

[2:0 3:0 32 0] [2] 



La r iniziale ci dice che si tratta di un evento di ricezio- 
ne, all'istante 40.647, da parte del nodo 2, di un pac- 
chetto CBR di 512 bytes. Un semplice programmino in 
Java (vedi NSParser.java) che calcoli la percentuale di 



m 

File Views 


Ànalysis |^ 






4* 


M 


■ 1 


► ►► 


<& 


© 


O 


& 


ED 


^"** 




ack 16708:2 
Sent at 49.674575 
68 bytes 

Monitor Filter Dismiss 









Fig. 3: Dettagli su un pacchetto di 
acknowledgement. 

pacchetti TCP spediti, ricevuti, e persi, e quindi ci mo- 
stri il valore percentuale del Packet Delivery Ratio, po- 
trebbe contenere un metodo come questo: 

try { BufferedReader fr=new BufferedReader(new 

FileReader(file)); 

String line=fr.readLine(); 

while(line! = null) 

{ if(line.indexOf("tcp")>0) 

{ if(line.startsWith("r")) recv++; 

else if(line.startsWith("s")) sent+ + ; 

else if(line.startsWith("D")) drop++; } 

line=fr.readLine(); } 

fr.closeQ; 

System.out.println("Pacchetti spediti = "+sent); 

System.out.println("Pacchetti ricevuti = "+recv); 

System.out.println("Pacchetti persi = "+drop); 

System. out.println("Packet Delivery Ratio = 

"+(((double)recv/(double)sent)*100)+"%"); } 

catch(FileNotFoundException fnf) 

{System .out.println(fnf.toString());> 

catch(IOException ioe) 

{ System. out.println(ioe.toString());> 




Fig. 4: Le statistiche ottenute attraverso una 
piccola applicazione Java. 

Se eseguiamo il programma passando come argomen- 
to il nome del file di trace da analizzare otteniamo il ri- 
sultato voluto (vedi Fig. 4). Comunque, leggendo la 
parte di documentazione riguardante proprio il tra- 
cing, troverete tutti i dettagli suir argomento. L'altro fi- 
le di output, con estensione .nam, ci darà la possibilità, 
come detto, di seguire l'evoluzione della rete, il movi- 
mento dei nodi, i pacchetti spediti, (sia a livello tra- 
sporto, sia a livello di routing. Ad esempio la Fig. 2, ci 
mostra come, cliccando su un pacchetto, riusciamo a 
sapere che è di tipo TCP e di dimensione 540 bytes, e 
cliccando a questo punto su Monitor possiamo seguire 
il pacchetto per tutta la sua vita. La Fig. 3 invece ci mo- 
stra un pacchetto di acknowledgement. Se ci interessano 
invece in particolare i meccanismi di routing, possiamo 
seguire la loro evoluzione seguendo la propagazione 
delle onde da router a router. 

Antonio Pelleriti 



100 ►►► F e b b 



3 



http://www.itportal.it 



A d 



Testare 

IL CODICE CON JUNIT 

Tutti sanno che testare il codice è un'operazione 
noiosissima, una cosa che nessun programmatore ha mai 
voglia di fare... E invece non è così. Non ci credete? In 
questa serie di articoli vi spiegheremo come scrivere 
codice a prova di bomba e divertirvi mentre lo fate. Tutto 
grazie ad una nuova, rivoluzionaria tecnica: i "test unitari' 




Junit 



Vi è mai capitato di passare una notte intera cur- 
vi sulla tastiera alla ricerca di un maledetto 
bug? Vi è mai successo che il vostro codice di- 
ventasse complesso come un piatto di spaghetti, tanto 
che ogni volta che correggevate un bug ne saltavano 
fuori altri due da qualche altra parte? Allora gioite, 
peccatori! Non diciamo che i tempi delle vostre soffe- 
renze siano completamente finiti, ma se seguirete que- 
sta serie di articoli possiamo garantirvi che passerete 
molte più notti dormendo sereni nel vostro lettino. In 
questa serie di tre articoli vi introdurremo al piacere 
dei Test Unitari, della Grande Barra Verde e del Test- 
First Design. Attraverso questi strumenti potrete rag- 
giungerete il Nirvana della programmazione, uno sta- 
to di grazia nel quale i programmatori tornano a casa 
dal lavoro sereni, consapevoli che il loro codice funzio- 
na e che non riserverà brutte sorprese il mattino se- 
guente. Certo, anche noi sappiamo che i test sono una 
bestia antipaticissima. Tutti i programmatori sanno che 
dovrebbero scrivere i test, così come tutti sanno che do- 
vrebbero perdere qualche chilo e magari smettere di 
fumare. Ma quante persone conoscete che testano re- 
golarmente il proprio codice? Quasi nessuno, vero? I 
test sono noiosi, fanno perdere tempo, e spesso non 
aiutano più di tanto a trovare i bug. Almeno questo va- 
le i test che abbiamo usato finora. Ma esiste un'altra ca- 
tegoria di test, diversi da quelli che conosciamo. Si 
chiamano "unit test" oppure, all'italiana, "test unitari". 
Perché sono diversi? Per cominciare sono diversi per- 
ché non testano il sistema dall'esterno, come se fosse 
una scatola nera, ma da dentro. I test unitari testano di- 
rettamente il codice, in ogni sua piccola parte. Se l'idea 
vi sembra stupida, aspettate di vedere come funziona- 
no. E poi provateli. 

ESEMPI 

DALLA VITA QUOTIDIANA 

Il modo migliore per capire come funzionano i test uni- 



tari è sbirciare da sopra la spalla di qualcuno che li usa. 
In mancanza di meglio cercheremo di spiegarveli con 
qualche esempio. Questo mese potremo fare solo i pri- 
mi passi. Speriamo che bastino, se non a convincerci, 
almeno ad incuriosirvi abbastanza da farvi leggere i 
prossimi due articoli di questa serie e a provare queste 
tecniche per conto vostro. Lo scenario: dobbiamo scri- 
vere un programma per gestire il nostro conto corren- 
te. Useremo la tecnica dei test unitari e la libreria JUnit 
(ne parliamo nelle barre laterali). La classe che voglia- 
mo scrivere è una semplice rappresentazione di un im- 
porto di denaro in ingresso o in uscita dal conto. Dob- 
biamo decidere come rappresentare l'importo. Per 
adesso useremo due numeri per indicare rispettiva- 
mente gli Euro e i centesimi, e un valore booleano per 
indicare se l'importo è positivo o negativo, cioè se si 
tratta di una somma di denaro in ingresso o in uscita. 
Useremo questa rappresentazione sia all'interno della 
classe che nel costruttore. Ecco quindi la prima versio- 
ne della nostra classe Importo: 

package serie_junit; 

public class Importo 

{ private final boolean _positivo; 



private final long _euro; 



private final long _cent; 



public Importo(boolean positivo, long euro, long cent) 



{ _positivo = positivo; 



_euro = euro + (cent / 100); 



cent = cent % 100; 



} 



Nel costruttore i centesimi oltre i 100 vengono auto- 
maticamente convertiti in Euro. I tre valori vengono 
poi conservati nei rispettivi campi privati. I campi so- 
no tutti final (cioè costanti). Quindi l'oggetto è "immu- 
tabile", cioè non può più essere modificato dopo che è 
stato creato. Ora ci serve un modo per leggere il conte- 



File sul CD 

\soft\codice 
\ExtremeProgramming\ 



I prossimi 
appuntamenti 

[/SI Questa serie sarà 
I -J\ composta da tre 
articoli. Nei prossimi 
due numeri di ioPro- 
grammo troverete il se- 
condo articolo ("Pro- 
grammare con ritmo") 
e il terzo ("Abbracciare 
il cambiamento"). 



http://www.itportal.it 



3 ►►► 101 




Junit 



Programmazi 
one estrema 

I "test unitari" 
sono diventati fa- 
grazie alla cosid- 
Extreme Pro- 



Ó 



mosi 
detta 

gramming (o XP), una 
metodologia recente e 
molto popolare per svi- 
luppare il software. 
Probabilmente in futu- 
ro parleremo ancora di 
Extreme Programming 
sulle pagine di ioPro- 
grammo. Comunque i 
test unitari non sono 
strettamente legati al- 
l'XP, quindi potete 
usarli anche se l'XP 
non vi interessa affat- 
to. 



JUnit 
Uber Alles 

Del framework 
JUnit hanno det- 



to: 

"Mai prima d'ora nella 
storia della program- 
mazione così tante 
persone hanno avuto 
un debito così grande 
nei confronti di così 
poche righe di softwa- 
re". 

Potete trovare l'ultima 
versione di JUnit (at- 
tualmente la 3.8.1) sul 
sito 

http://www.junit.org 

o sul CD allegato a 
questo numero di io- 
Programmo. Per usare 
JUnit aggiungete sem- 
plicemente il file ju- 
nit.jar al vostro clas- 
spath (oppure, se usa- 
te un IDE come JBuil- 
der, registrate il file 
come libreria nel vo- 
stro progetto). 



mito di un Importo. Scriviamo un metodo getVoloreO 
che converte la rappresentazione interna in una String: 

public String getValoreQ 

£ 

String risultato = ""; 

if(!_positivo) 

risultato += "-"; 

risultato = risultato + _euro + "." + _cent; 

return risultato; 



} 



Appena abbiamo finito di scrivere il metodo, un cam- 
panellino trilla nella nostra testa. E' la nostra coscienza, 
che ci ricorda che è arrivato il momento di scrivere un 
test unitario per verificare se il metodo getVoloreO e il 
costruttore funzionano. Ecco quindi la prima regola 
del perfetto autore di test unitari: 

Ogni volta che scrivi un frammento di codice, anche 
se piccolo e semplice, scrivi anche un test per verifi- 
care che il codice funzioni. 

Naturalmente nessun test ci garantirà mai che il nostro 
codice non contiene bug. Ma anche se non possiamo 
testare tutto, più cose testiamo meglio è. All'opera, 
dunque. 

IL PRIMO TEST 
NON SI SCORDA MAI 

Per scrivere il nostro primo test unitario con il fra- 
mework JUnit dobbiamo scrivere una classe che eredi- 
ta da junit. framework.TestCase. Ecco lo scheletro di un 
test unitario per la classe Importo: 

package serie_junit; 

import junit.framework.*; 

public class Testlmporto extends TestCase 

£ 

public static void main(String[] args) 

_£ 

junit.textui.TestRunner.run(Testlmporto.class); 



} 



Per lanciare la classe (che in realtà non contiene ancora 
nessun test) possiamo passarla al metodo statico run() 
della classe junit. textui.TestRunner. Per comodità abbia- 
mo invocato questo metodo dal maini) della stessa Te- 
stlmporto. Proviamo a lanciare questo maini) e vediamo 
cosa succede. Ecco l'output: 



Time: 

There was 1 failure: 

1) warning(junit. framework. TestSuite$l) 

junit. framework. AssertionFailedError: No tests found 



in serie_junit_l .Testlmporto 

at serie_junit_l.TestImporto.main(Testimporto.java:14) 

FAILURESM! 

Tests run: 1, Failures: 1, Errors: 

Ci basta un solo sguardo alle ultime due righe del- 
l'output per vedere che il nostro test è fallito. Il motivo 
è anche spiegato esplicitamente nel messaggio di erro- 
re: JUnit non ha trovato i test che si aspettava nella clas- 
se. Dunque dobbiamo scrivere almeno un test. 
Ciascun test è un metodo public void il cui nome inizia 
con la sequenza di caratteri ''test". Il TestRunner tro- 
verà e chiamerà "automagicamente" questi metodi. 
Dobbiamo testare il metodo Importo. getValorei), quindi 
per chiarezza chiamiamo il nostro test con il nome test- 
GetValoreQ: 



public void testGetValoreQ 


{ 


Importo il = new Importo(true, 12 


,06); 


assertEquals(il. getValoreQ, 


x 12.06 


"); 


Importo i2 = new Importo(false, 0, 


99); 


assertEquals(i2. getValoreQ, 


x -0.99' 


'); 


} 



Qui stiamo vedendo all'opera il succo della filosofia 
JUnit. Se un test restituisse lunghe sfilze di numeri, ben 
presto ci stancheremmo di farlo girare e di perdere del 
tempo per controllarne il risultato. Un test deve invece 
essere semplice, e deve avere un risultato booleano che 
possa essere verificato con un solo colpo d'occhio: o 
riesce, o fallisce. Per raggiungere questo obiettivo dob- 
biamo usare le cosiddette asserzioni, cioè dichiarare il 
risultato che ci aspettiamo di ottenere dal codice che 
stiamo testando. La classe TestCase ci mette a disposi- 
zione diverse asserzioni, e tra queste assertEqualsi) , un 
metodo che accetta due parametri e restituisce true se e 
solo se i due parametri sono uguali. La versione di as- 
sertEqualsi) che abbiamo usato noi accetta due para- 
metri di tipo long. Ad esempio: 

Importo il = new Importo(true, 12, 06); 

assertEquals(il. getValoreQ, "12.06"); 

In questo caso abbiamo costruito un importo e abbia- 
mo dichiarato: mi aspetto che il metodo getValorei) di 
questo importo restituisca la stringa "12.06". Possiamo 
usare tutte le asserzioni che vogliamo in un test. Il test 
riesce se e solo se tutte le asserzioni riescono, e fallisce 
se anche una sola asserzione fallisce. Ecco tutto questo 
discorso distillato in una seconda semplice regola: 

I test unitari devono essere semplici. Un test unitario 
può avere solo due risultati: o riesce, o fallisce. 

Notate che per testare il metodo getValorei) abbiamo 
creato due oggetti Importo con parametri "quasi a ca- 
saccio", ma non del tutto. In particolare abbiamo scel- 
to un importo positivo e uno negativo, per cercare di 



102 ►►► F e b b 



3 



http://www.itportal.it 



A d 



non avere sorprese in nessuno di questi due casi. Tor- 
neremo suir argomento tra poco. Intanto proviamo a 
lanciare il test e vediamo qual è il risultato questa vol- 
ta: 



Time: 

There was 1 failure: 

1) testGetValore(serie_junit.TestImporto) 

junit.framework.ComparisonFailure: expected:< > 

but was:<...0...> 

at serie_junit.TestImporto.testGetValore( 
Testlmporto.java : 22) 

at serie_junit.TestImporto.main(TestImporto.java:ll) 

FAILURESM! 



Tests run: 1, Failures: 1, Errors: 

Un altro errore! Questa volta non è colpa della man- 
canza di test. Il test c'è, ma è fallito. Cosa è successo? 

NON È MAI TROPPO 
SEMPLICE 

Purtroppo la versione di JUnit che stiamo usando dà 
un messaggio di errore piuttosto ambiguo quando fal- 
lisce un confronto tra stringhe, quindi non è del tutto 
facile scoprire dov'è il problema. Ma di sicuro sarebbe 
stato molto più difficile se avessimo scoperto questo 
bug solo tra qualche tempo, magari senza poter più sa- 
pere in quale parte del codice andarlo a cercare. Alme- 
no in questo caso siamo sicuri che Terrore deve essere 
nelle poche righe di codice che abbiamo appena scrit- 
to. Riuscite a vederlo? 

L'errore sta nel fatto che il nostro metodo getValoreO 
non aggiunge uno zero dopo la virgola se il numero di 
centesimi è inferiore a 10. Quindi l'output della prima 
chiamata a getValoreO non è "12.06" come ci aspettava- 
mo, bensì "12.6". 

Non è difficile correggere questo bug modificando il 
metodo getValoreO: 

public String getValoreO 

£ 

String risultato = ""; 

if(!_positivo) 

risultato += "-"; 

risultato = risultato + _euro + "."; 

if(_cent < 10) 

risultato += "0"; 

risultato += _cent; 

return risultato; 

> 

Facciamo girare di nuovo il test: 



Time: 
OK (1 test) 



Successo! Ci basta leggere l'ultima riga per vedere su- 
bito che il nostro metodo getValoreO funziona. E' una 
vera fortuna che questo problema sia saltato fuori su- 
bito, anziché tra qualche tempo. Dite la verità: magari 
non ve ne eravate accorti nemmeno voi. Eppure questo 
codice sembrava talmente semplice che probabilmente 
non vi sarebbe mai venuto in mente di testarlo. Questa 
è la dimostrazione del fatto che anche un pezzo di co- 
dice semplicissimo può contenere dei bug - anzi, pro- 
babilmente sarete d'accordo con noi se diciamo che i 
bug nel codice più semplice sono anche i più difficili 
da trovare. Certo, scrivendo anche i test scriviamo 
molto più codice, quindi abbiamo più possibilità di 
sbagliare. Cosa succede se sbagliamo qualcosa nei test? 
La stessa cosa che succede se sbagliamo qualcosa nel 
codice: l'errore salta fuori immediatamente appena il 
test fallisce. Quindi è vero che potenzialmente possia- 
mo commettere più errori, ma la gran parte di questi 
errori sono immediatamente visibili, e quindi innocui. 



CATTIVI QUANTO BASTA 

Nessun test ci darà mai la garanzia assoluta che il co- 
dice funziona al di fuori dei pochissimi casi particolari 
che testiamo direttamente. Diamo quindi un altro 
sguardo al nostro test. Siamo sicuri di non aver di- 
menticato niente? Abbiamo detto che un test scritto be- 
ne non deve semplicemente provare due o tre casi 
qualsiasi, ma deve anche cercare i casi particolarmente 
infelici: i casi limite, i casi particolari, eccetera. Insom- 
ma, un buon test deve essere un po' perfido. Chiedia- 
moci ad esempio quali sono i casi limite della classe 
Importo. Quando creiamo un Importo, quali sono i valo- 
ri massimi e minimi che possiamo passargli? Rivedia- 
mo il costruttore: 

public Importo(boolean positivo, long euro, int cent); 

Il primo parametro è booleano, quindi non presenta 
problemi. Per quanto riguarda gli altri due parametri 
poniamoci questi vincoli: 

euro >= 

cent >= 

euro <= Long.MAX_LONG (massimo valore di un 

long in Java) 

cent < 100 

I primi due vincoli per ora vengono lasciati al buon 
cuore di chi usa la classe. Se qualcuno passa dei valori 
negativi al costruttore di Importo, il codice non funzio- 
na più. Per ora supponiamo che i client della classe 
sappiano come usarla, quindi facciamo finta di niente 
(il mese prossimo risolveremo questo potenziale pro- 
blema). Il terzo vincolo è sempre automaticamente ri- 
spettato, perché il compilatore impedirà a chiunque di 
passare come secondo parametro del nostro metodo 
qualcosa che sia più grande di un long. 

II quarto vincolo è interessante. Cosa succede se qual- 




Junit 



a: 



Java è, 
se vi pare 

I Tutti gli esempi di 
I questa breve se- 
rie di articoli saranno 
in linguaggio Java, per 
tre motivi: perché la 
comunità Java è stata 
la prima a sostenere e 
adottare i test unitari; 
perché Java è un lin- 
guaggio orientato agli 
oggetti semplice e 
comprensibile; e anche 
perché useremo per i 
nostri test una libreria 
di nome JUnit, che è 
scritta in Java. Se pre- 
ferite qualche altro lin- 
guaggio object-orien- 
ted, come C# o C++, 
seguiteci pure tranquil- 
lamente. Non dovreste 
comunque avere pro- 
blemi a capire gli 
esempi, e sicuramente 
troverete in rete una 
conversione di JUnit 
per il vostro linguaggio 
preferito. Ne esistono 
per quasi tutti i lin- 
guaggi di programma- 
zione terrestri, inclusi 
quelli meno disposti a 
collaborare (come Vi- 
sual Basic e altri lin- 
guaggi non orientati 
agli oggetti). Date uno 
sguardo alla pagina 

http : //www, x program - 
minq.com/software.htm 

Se invece ancora non 
conoscete alcun lin- 
guaggio object-orien- 
ted, cosa aspettate a 
impararne uno? 



http://www.itportal.it 



3 ►►► 103 




Junit 



Troppe lingue 



r^ftl Nel codice dei no- 
\---J\ stri esempi usia- 
mo nomi per metà in 
inglese e per metà in 
italiano, come getValo- 
re(). Mescolare le due 
lingue è di solito una 
cattiva idea, e alla lun- 
ga può rendere il codi- 
ce piuttosto confuso. 
Ma in questo caso vo- 
gliamo rispettare le 
convenzioni di Java, 
come quelle sui metodi 
"get" e "set", e allo 
stesso tempo vogliamo 
facilitare la vita ai let- 
tori che non hanno 
molta pratica con l'in- 
glese. Quindi abbiate 
pazienza, e rassegna- 
tevi a vedere altri nomi 
in "lingua mista" nel 
corso di questa serie. 
Se conoscete bene l'in- 
glese, vi consigliamo di 
non usare l'italiano nel 
vostro codice se non 
nei commenti. 



cimo crea un Importo passandogli un numero di cente- 
simi maggiore o uguale a 100? Per come abbiamo scrit- 
to il codice l'operazione è legale e i centesimi in ecces- 
so vengono automaticamente convertiti in Euro. Ma i 
test che abbiamo scritto fino ad ora non verificano co- 
sa succede in questo caso particolare. Tanto per andare 
sul sicuro, aggiungiamo un paio di test. In uno provia- 
mo a passare esattamente 100 centesimi (equivalenti 
ad 1 Euro), così ne approfittiamo anche per verificare 
che l'output sia corretto nel caso in cui i centesimi del- 
l'importo sono esattamente pari a (un altro caso limi- 
te). Nel secondo test scegliamo un numero di centesi- 
mi molto alto, per verificare che tutti vengano conver- 
titi in Euro come ci aspettiamo. Notate che stiamo cer- 
cando a tutti i costi proprio i casi "sfortunati" nei qua- 
li il codice potrebbe fallire. 



public void testGetValoreQ 


< 


Importo il = new Importo(true, 12, 


06); 


assertEquals(il.getValore(), 


x 12.06' 


'); 


Importo i2 = new Importo(false, 0, 


99); 


assertEquals(i2.getvalore(), 


x -0.99" 


); 


Importo i3 = new Importo(true, 12, 


100); 


assertEquals(i3.getValore(), 


x 13.00' 


'); 


Importo i4 = new Importo(false, 12 


, 375); 


assertEquals(i4.getvalore(), 


*-15.7E 


"); 


} 



Facciamo girare di nuovo i test. 
Successo su tutta la linea! Il nostro codice si comporta 
secondo le aspettative. Ad esempio, 12 Euro e 375 cen- 
tesimi diventano 15 Euro e 75 centesimi. Possiamo dir- 
ci soddisfatti, ed enunciare la terza regola dei test uni- 
tari: 

Quando scrivi un test unitario, lascia spazio al Mister 
Hyde che è in te. 

Cerca di trovare quei casi limite o quelle situazioni 
sfortunate nelle quali il tuo codice potrebbe non fun- 



LA GRANDE BARRA VERDE 

Ora che abbiamo scritto il nostro primo test unitario 
possiamo fare un altro salto di qualità. Finora abbiamo 
usato la versione testuale del TestRunner, contenuta 
nel package junit textui. D'ora in poi useremo il Te- 
stRunner grafico del package junit swingui. 
Modifichiamo il metodo Testlmport.mainQ: 

public static void main(String[] args) 

£ 

junit.swingui .TestRunner. run(Testlmporto.class); 

} 

Ora lanciamo i test. Visto che differenza? 
La barra verde che vedete al centro della finestra indi- 
ca che tutti i test si sono conclusi con successo. Da ora 



Test class name: 



serie Junit.Testlmporto 


I-I I ■■■ I 


E Reload classes every run 


1 1 


Runs: 1/1 x Errors: 


x Failures: 



Ju 



x Failures £ Test Hierarchy 



JFinished: 0,032 seconds 



Fig. 1: La versione visuale del TestRunner. 



in avanti, questa barra verde sarà il nostro passaporto 
per il paradiso. Un programmatore abituato a scrivere 
i test unitari per il proprio codice può tenere il Te- 
stRunner aperto sullo sfondo e far girare i test in conti- 
nuazione, anche ogni volta che compila. Se appare la 
barra verde, si va avanti. Se invece un test fallisce la 
barra diventa rossa. Allora ci si ferma e si corregge il 
codice (o il test) malfunzionante. Quando vi sarete abi- 
tuati a questo modo di lavorare non accetterete com- 
promessi: solo se il vostro codice è completamente te- 
stato e se vedete una barra verde andrete avanti tran- 
quilli. La pace e la serenità che i test unitari vi daranno 
sarà una delle sensazioni più piacevoli che potrete spe- 
rimentare nella vostra attività di programmatori. 
Ora sappiamo anche perché i test devono essere boo- 
leani. Solo così potranno essere verificati da un sistema 
automatico, e daranno un risultato visibile al primo 
sguardo e non ambiguo. Di conseguenza saremo invo- 
gliati a far girare tutti i test ogni volta che facciamo una 
modifica al codice, per quanto piccola. Quello che era 
un compito gravoso diventerà un piacere, perché ba- 
sterà premere un pulsante per avere una "pacca sulla 
spalla virtuale" nella forma di una barra completa- 
mente verde, che ci rassicurerà circa il corretto funzio- 
namento del nostro sistema. 

E così siamo arrivati alla quarta e ultima regola del per- 
fetto autore di test unitari: 

Lancia i test in continuazione. 
Se vedi una barra verde, vai avanti tranquillo. 
Se vedi una barra rossa, fermati e correggi il proble- 
ma dovunque esso sia - nel codice o nei test. 

Ci state prendendo gusto? Allora arrivederci al prossi- 
mo numero di ioProgrammo, dove affronteremo un 
argomento che di solito non viene associato alla pro- 
grammazione dei computer: il ritmo. 

Paolo Perrotta 



104 ►►► F e b b 



3 



http://www.itportal.it 



F T W A 




Il Software 

sul CD-ROM di ioProgrammo 



Ecco i migliori 

software scelti 

per voi da 

ioProgrammo: 

Borland 

JBuilder 8 trial, 

XML Spy 5.0 

Professional 

Edition, 

AppMentor 3.0 

for Visual Basic. 



Installazione 
ActiveX in 
Delphi 

I Dal menu "Com- 
ponent" selezio- 
nare la voce "Import 
ActiveX Component"; 
nella schermata pre- 
sente a video è visibi- 
le una list box conte- 
nente l'elenco degli 
ActiveX installati nel 
sistema; da questi è 
possibile scegliere il 
componente e instal- 
larlo mediante il bot- 
tone Instali. Tramite 
l'uso dei bottoni "Re- 
move" e "Add" è pos- 
sibile rispettivamente 
rimuovere un compo- 
nente dalla list box o 
aggiungerne uno non 
presente in essa ma 
comunque residente 
in qualche directory 
del sistema. Dalla list 
box "Palette Page" si 
seleziona la sezione 
(Standard, Additio- 
nal, Win32, etc, etc) 
nella quale troverà 
posto l'icona del com- 
ponente. 



Borland JBuilder 
8 trial 

Borland ha da poco rilasciato la 
nuova versione di JBuilder 8.0. 
Questa nuova release è caratteriz- 
zata da una struttura completa- 
mente rinnovata e basata sul fra- 
mework open source Jakarta 
Struts. Da parte degli sviluppato- 
ri è stata data una notevole im- 
portanza alle funzioni di colla- 
borazione, testing e di debug- 
ging, ora, per esempio, l'Ide può 
eseguire lo "spot debug", solo su 
una piccola parte del codice (per 
poi modificarlo nell'immediato), 
su JSP o anche su codice non Ja- 
va. Le funzioni di collaborazione, 
per lo sviluppo in team azienda- 
li, invece, si avvalgono dei col- 
laudati tool di Rational: Clear 
Case, per la gestione e l'integra- 
zione del codice, CVS per la 
gestione delle versioni e del codi- 
ce sorgente. In aggiunta JBuilder 
8 supporta tutte le ultime versio- 
ni degli application server di Bor- 
land, Bea Systems, Oracle e Sun 
Microsystems. Sono inoltre sup- 
portati i sistemi Aix di Ibm e la 
piattaforma Hp-Ux. Per l'attiva- 
zione del prodotto si richiede la 
registrazione sul sito Borland 

(www.borland.com). 
Borland_JB\ 



AUTOFORM@asp 

Sviluppato da una software house 
italiana, AUTOFORM@asp è un 
interessante tool di sviluppo RAD 
che, poggiandosi su tecnologie 
consolidate e molto diffuse, per- 
mette di rendere più rapide molte 
fasi della progettazione di applica- 
zioni gestionali, oltre a garantire la 
coerenza estetica delle interfacce 
prodotte. Autoform consente la 
creazione di applicazioni per Inter- 
net, reti locali e stand alone garan- 
tendo la semplificazione dell'inter- 
facciamento con Microsoft SQL 
Server e Oracle, la generazione di 



applicazioni multilingua, l'interfac- 
ciamento degli OLAP Services di 
Microsoft, la gestione sicura delle 
transazioni, numerose funzioni per 
l'export dei dati. L'ambiente auto- 
form è composto da una serie di 
strumenti che si possono racchiu- 
dere in due grandi categorie: stru- 
menti lato server e strumenti lato 
client. Dalla parte server abbiamo 
un motore di database, un'applica- 
zione che fa da interfaccia tra il 
database e l'applicazione client e 
un generatore di report. Lato client 
troviamo l'applicativo che fa da 
interfaccia utente e che comunica 
con il componente server tramite 
rete locale o via Internet. È pos- 
sibile installare Autoform in tre 
modalità differenti: 

• Server: è la tipologia di installa- 
zione naturale, richiede Micro- 
soft NT o 2000, e permette la 
connessione contemporanea di 
più client in una LAN; 

• ASP: permette l'accesso al ser- 
ver via Internet utilizzando il 
protocollo http; 

• Standalone: installazione e uti- 
lizzo su una singola worksta- 
tion. 

Versione dimostrativa. 
Autoform \ 

Ariacom Business 
Reports 1.6 

Un potente ambiente per la crea- 
zione di report automatizzata. At- 
traverso la creazione dinamica di 
query SQL, anche gli utenti meno 
esperti potranno gestire e trarre 
informazioni dai più complessi da- 
tabase relazionali. Ariacom Busi- 
ness Reports può coprire vasto 
spettro di esigenze: dalla pubblica- 
zione di una directory su Internet , 
all'analisi multidimensionale di un 
data-warehouse. Le funzioni prin- 
cipali sono: generazione e ottimiz- 
zazione dinamica delle query, 
avanzate funzioni di report, limita- 



zione all'accesso dei dati attraverso 
un'attenta gestione della sicurezza, 
possibilità di generare report in di- 
versi formati (html, csv, txt) e su 
dispositivi diversi (file, stampante, 

fax, email) e molto altro. 
bfreel6.exe 

Ulead Cool 3D 
Studio 1.0 

Che dobbiate realizzare il nuovo 
logo della vostra software-house, 
un filmato introduttivo sul vostro 
nuovo prodotto, o semplicemente 
una gif animata che non sia banale, 
Ulead Cool 3D Studio è il prodotto 
che fa per voi! La creazione di gra- 
fica e testo animata raggiunge in 
questi prodotto livelli di semplcità 
ed eccellenza mai visti in preceden- 
za e, grazie alla grande compatibi- 
lità garantita in output, sarà pos- 
sibile distribuire i filmati che pro- 
durremo in molteplici formati: se- 
quenza di fermo immagini, anima- 
zione GIF e filmati Flash. Si integra 
perfettamente con gli altri prodotti 
Ulead per l'editing Video come 
MediaStudio Pro e VideoStudio. 
Versione di valutazione valida 

trenta giorni. 
Ulead_Cool3D\ 

Code Counter Pro 1.0 

Una comoda applicazione che con- 
sente a noi programmatori di 
quantificare il lavoro che abbiamo 
svolto o stiamo svolgendo. Code 
Counter si occupa di valutare il 
numero di righe, spazi bianchi, 
commenti e quant'altro sia interes- 
sante per effettuare statistiche sul 
codice. I linguaggi supportati sono 
numerosi: C/C++, Java, Delphi 
/Pascal, VB, PHP, ASP ed altri 
ancora, è possiblile effettuare anali- 
si anche su porzioni di testo che 
non siano riconducibili a codice 
sorgente. Versione di prova valida 
trenta giorni, presenta alcune limi- 
tazioni nel suo utilizzo. 
ccountp.exe 



106 ►►► F e b b r 



http://www.itportal.it 



s o 



w 



SUL 



C D 



Code Magic 4.2 

"Ma non l'avevo già risolto?" que- 
sta la tipica domanda di noi svilup- 
patori quando ci troviamo di fronte 
ad un problema che ci sembra di 
aver già affrontato, ma non ricor- 
diamo quando, ne' come. Questa 
applicazione ci viene in aiuto pro- 
prio in situazioni come queste. 
Grazie ad un parser particolarmen- 
te efficace, riesce ad archiviare tutto 
il codice che produciamo all'inter- 
no di una vista ad albero che per- 
mette un facile reperimento in fase 
di produzione del codice. Il syntax 
highlighting supporta i più noti lin- 
guaggi di programmazione. 
cm_setup.exe 

Dev-Pascal 1.9.2 

Un completo e gratuito ambiente 
di sviluppo per Pascal, dotato di 
tutte le più utili caratteristiche 
degli IDE moderni. Tra le funzioni 
disponibili segnaliamo: colorazio- 
ne del codice personalizzabile, 
wizard per la creazione di pacchet- 
ti di installazione, supporto per la 
creazione di DLL, sviluppo assisti- 
to per le interfacce, possibilità di 
impostare dei template per la pro- 
duzione rapida di codice. Nella di- 
rectory è anche presente un de- 
bugger che si integra perfettamen- 
te nell'ambiente di sviluppo. 
DevPascal\ 

Expert 
Troubleshooter 5.0 

Basato su un motore di intelligen- 
za artificiale, Export Troubleshou- 
ter consente di costruire applica- 
zioni di monitoraggio per scoprire 
immediatamente gli eventuali 
malfunzionamenti di apparecchi 
elettronici ed elettromeccanici. So- 
no disponibili diversi approcci: 
dalla verifica manuale assistita dal 
PC, alla generazione di pattern per 
l'individuazione degli ambiti criti- 
ci. Particolarmente interessante ri- 
sulta essere la generazione auto- 
matica di codice in Basic, C e Pa- 
scal per la creazione di applicazio- 
ni di test. 
ETSetup\ 

FontLab 4.52 

Un sofisticato editor di font che 



consente di importare, esportare, 
creare e modificare font nei loro 
formati nativi. Inoltre, grazie ad un 
tool di disegno vettoriale, è possibi- 
le intervenire con precisione nella 
modifica e nella creazione di font 
personalizzati. Questa nuova ver- 
sione include una potente sistema 

di macro. Versione dimostrativa. 
FL4WinDemo.exe 

Hephaestus 2.01 

Un completo kit per la realizzazio- 
ne di giochi di ruolo che permette 
di scrivere la propria avventura 
attraverso un semplice linguaggio 
di scripting e di condividere il gio- 
co con chiunque altro abbia instal- 
lato Hephaestus. Essendo scritto 
interamente in Java, Hephaestus 
gira su qualsiasi piattaforma. 

Gratuito.90 
hephaestus.zip 

IBasic Standard 
Version 1.99c 

Una occasione per chi si avvicina 
al mondo della programmazione: 
Ibasic consente di scrivere applica- 
zioni stand alone per Windows 
con estrema semplicità, adottando 
una sintassi sovrapponibile in buo- 
na parte al Basic standard. Il lin- 
guag gio è sufficientemente com- 
pleto, comprendendo oltre 180 fra 
comandi e funzioni. In questa nuo- 
va release, è stata migliorata del 
150 percento la velocità di esecuzio 
ne, sono state inserite nuove fun- 
zioni per la gestione dei file ed è 

stata migliorata l'interfaccia utente. 
ibasic.zip 

Instant Report 1.4 

Un generatore di query SQL che 
consente la costruzione completa- 
mente visuale dei report. Conce- 
pito per essere il più semplice pos- 
sibile, permette di realizzare report 
anche complessi con pochissimi 
colpi di mouse. Compatibile con 
tutti i più diffusi database sia free 

che commerciali. Gratuito. 
ireport-L4.zip 

NexJDE l.Oa 

Una comoda applicazione che va 
ad collocarsi nella categoria degli 
Universal Data Access tool: con- 



sente di effettuare query e ottenere 
risultati a partire da dati immagaz- 
zinati in un qualsiasi database: 
Oracle JDBC, SUN JDBC ODBC, 
PostgreSQL, mySQL, Sybase, e MS 
SQL Server. I risultati possono es- 
sere mostrati in una tabella HTML 
o all'interno di un'apposita inter- 
faccia utente. 
JDELight.zip 

Metamill 2.2 

Un software per la modellazione 
software UML completamente 
visuale. Metamill risulta partico- 
larmente semplice da usare, in spe- 
cial modo se paragonato ad altri 
software di modellazione UML. 
Tra le caratteristiche più interes- 
santi c'è il repository attraverso cui 
più sviluppatori possono collabo- 
rare utilizzando i medesimi ele- 
menti senza "pestarsi i piedi". Una 
volta sviluppato il modello, Me- 
tamill è in grado di produrre il 
codice relativo sia in C++ sia in 

Java. Shareware. 
Mmill221.exe 

MyTool 1.2 

Un interessante front end per 
MySQL comprensivo un editor per 
effettuare tutte le più comuni ope- 
razioni di gestione di DBMS per 
via visuale. Interessante la funzio- 
ne di monitoraggio dello stato 
delle query sul server. Versione di- 
mostrativa. 
mytool-setup.exe 

Pro-Test 1.0 

Una interessante applicazione che 
consente di velocizzare e rendere 
più efficiente una delle parti più 
noiose della creazione del softwa- 
re: il testing. Pro-Test si occupa di 
generare casi di test per analizzare 
la robustezza del codice che scri- 
viamo. Usato con attenzione, Pro- 
Test può migliorare e velocizzare 
sensibilmente la produzione di co- 
dice. Versione di prova valida die- 
ci giorni. 
Pro-Test_10Day_Trial.EXE 

ResRipper 3.8 

Davvero comodo questo tool che 
consente di analizzare velocemen- 
te le risorse immagazzinate nei 



Risorse Java 

mgm Molte delle ri- 
■» sorse Java ripor- 
tate all'interno del CD 
ROM sono munite di 
file .java, .class e di 
file html per essere 
testate. Nel caso di 
compilazione del file 
.java si dovrà utiliz- 
zare un opportuno 
strumento, come ad 
esempio il JDK di Sun. 
Per utilizzarlo si do- 
vrà operare da prom- 
pt del DOS, accedere 
alla directory bin del- 
l'ambiente stesso ed 
avviare il Java Com- 
piler digitando la 
stringa: javac "nome- 
file". 



Installazione 
componenti 

VC++/C++ 

I file C++, delle 
f librerie facenti 
parte del CD-ROM, 
possono essere diret- 
tamente inclusi all'in- 
terno dei vostri pro- 
getti. Le risorse Visual 
C++ sono invece for- 
nite del file progetto, 
quindi dall'ambiente 
di sviluppo Microsoft 
utilizzare la voce di 
menu "Open Project" 
ed automaticamente 
tutti i file afferenti al 
progetto stesso ver- 
ranno visualizzati, e 
da tale ambiente è 
possibile inoltre ese- 
guire l'applicativo 
stesso. Se invece ri- 
sorsa riportata è una 
dll, allora essa potrà 
essere direttamente 
inclusa all'interno di 
un progetto. 



http://www.itportal.it 



3 ►►► 107 



S O F T W A 



Installazione 
ActiveX in 
Visual Basic 

rèi Dal menu Proget- 
^**to selezionare la 
voce Componenti (CT 
RL + T); nella scher- 
mata presente a video 
è visibile una list box 
contenente l'elenco 
dei componenti Acti- 
veX installati nel si- 
stema; da questi è 
possibile selezionare 
uno o più componenti 
e confermare median- 
te il bottone OK; qua- 
lora il componente 
non fosse installato 
nel sistema ma fosse 
comunque presente 
nel computer è pos- 
sibile selezionare 
quest'ultimo tramite 
l'utilizzo del bottone 
"Sfoglia" mediante il 
quale si ha accesso al- 
le directory del siste- 
ma; da queste è pos- 
sibile localizzare il 
componente da instal- 
lare. 



nostri dischi e che sono normal- 
mente nascoste: migliaia di imma- 
gini (BMP, DIB, GIF, JPG) icone, 
filmati (AVI, MPG, GIF animate), 
font e suoni. Tutte risorse normal- 
mente bloccate e nascoste all'inter- 
no delle applicazioni e che, grazie 
a ResRipper, possono ora essere 
individuate, estratte e riutilizzate 
nei nostri progetti. 
Versione di prova valida trenta 

giorni. 
resripper_trial_version.exe 

Stylus Studio 4.5 

Forte dei molti premi vinti e di 
una base di installato che conta 
oltre 30.000 sviluppatori sparsi in 
tutto il mondo, Stylus Studio si 
presenta come un potente tool 
visuale per lo sviluppo e la gestio- 
ne di documenti XML e XSL. 
Rimarchevole la qualità della 
mappatura dei documenti che 
Stylus Studio offre per via grafica, 
consentendo una più facile analisi 
dei documenti. Permette di gestire 
e modificare tutti i tipi di file che 
appartengono ad un'applicazione 
XML: oltre a documenti XML, 
abbiamo il pieno supporto per gli 
XSLT stylesheets, DTD e gli XML 
schema, oltre ai file Java. Gira su 
Windows NT - 2000 -XP. Tra le 
funzioni più interessanti, segnalia- 
mo la possibilità di effettuare il 
debug e la presenza di una poten- 
te funzione di preview sulle tra- 
sformazioni realizzate. Un prodot- 
to che può risultare valido sia ai 
principianti che agli esperti e si 
presta anzi a fare da guida in un 
percorso di apprendimento delle 
tecnologie legate a XML. All'atto 
dell'installazione è richiesto un 
collegamento Internet al fine di 
riempire una breve form. Una 
chiave di attivazione verrà inviata 
alla propria casella di posta elet- 
tronica. 
StylusStudio\ 

UltraEdit-32 9.2 

UltraEdit-32 è principalmente un 
editor esadecimale con un com- 
pleto supporto per le macro e nu- 
merose funzioni avanzate come la 
conversione di file da DOS a Unix. 
In questa nuova versione sono sta- 



te aggiunte delle comode funzio- 
nalità di autocompletamento, oltre 
ad un miglioramento complessivo 
dell'interfaccia. 
Versione di valutazione valida 45 

giorni. 
uedit32.zip 

XMLEditPro 2.0 

Semplice ed intuitivo, questo edi- 
tor XML ha giusto l'essenziale per 
la creazione e l'editing di docu- 
menti XML. Proprio questo suo 
essere spartano, lungi dall'essere 
un limite, diventa un pregio se 
visto sotto l'ottica della semplicità 
dell'interfaccia e della velocita. 

Gratuito. 
xep2setup.exe 

XML Spy 5.0 
Professional 
Edition 

Il più avanzato strumento di svi- 
luppo per XML. Uno dei punti di 
forza risiede nella possibilità di 
switchare velocemente fra quattro 
differenti viste per ogni documen- 
to: Enhanced Grid per il dettaglio di 
tutti gli elementi: Schema Design; 
Text View per una programmazio- 
ne a più basso livello e una vista di 
preview che anticipa come il docu- 
mento sarà visualizzato da un 
comune browser. E' possibile svi- 
luppare sia documenti XML che 
DTD che saranno poi pubblicabili 
via FTP attraverso lo stesso XML 
Spy. 

Davvero eccezionale il supporto 
offerto ai Web Services grazie ad 
apposite interfacce per i protocolli 

SOAP,XSLeWSDL. 
XmlSpy\ 

Dev-C++ 5 Beta 7 
(4.9.7.0) 

Uno dei migliori ambienti graniti 
di sviluppo per C++. In questa 
versione, l'interfaccia raggiunge 
livelli di eccellenza: scrivere, com- 
pilare, eseguire ed effettuare il 
debug, tutto molto efficiente e con 
la possibilità di avere delle icone 
stile Gnome. Quasi una scelta 
obbligata per chi vuole sviluppare 
applicazioni per Win32 e non 
vuole affrontare la spesa di un 
Visual C++. Tra le caratteristiche 



più interessanti: completamento 
automatico del codice, manager di 
progetto, syntax highlighting per- 
sonalizzabile, creazione assistita di 
librerie statiche e DLL, supporto 
per i packages e molto altro anco- 
ra. Provatelo. 
devcpp4970-gcc32.exe 

Visual Paradigm 
for UML 
Community Edition 

Un ambiente di sviluppo integrato 
per UML che farà la gioia di tutte 
le figure coinvolte nello sviluppo 
di applicazioni di grandi dimen- 
sioni. Completamente gratuito, 
non rinuncia ad una ottima inter- 
faccia di livello professionale e 
copre tutte le maggiori esigenze di 
chi si occupa di UML. 

Da provare. 
VParamUML\ 

AppMentor 3.0 for 
Visual Basic 

Una piattaforma che consente di 
velocizzare la produzione di 
nuove applicazioni Visual Basic, 
grazie ad un approccio template- 
oriented che consente di ridurre i 
tempi di sviluppo anche dell'80 
percento. L'accesso ai database è 
realizzato attraverso una logica n- 
tier che consente di demandare 
buona parte della gestione a basso 
livello. Che siate sviluppatori 
esperti o "apprendisti stregoni", 
AppMentor può essere la soluzio- 
ne giusta per fare un passo decisi- 
vo verso lo sviluppo di applicazio- 
ni professionali. 

Versione di valutazione. 
AppMentor3\ 

ActivePerl 5.8 

La versione Windows di una com- 
pleta distribuzione Perl. Otre al 
linguaggio, potrete sperimentare il 
Perl Package Manager (PPM) che, 
attraverso una semplice interfac- 
cia e riga di comando, permette di 
installare e gestire moduli ed 
estensioni. La copiosa documenta- 
zione di cui è fornita questa distri- 
buzione varrebbe da sola a instal- 
lare il pacchetto. 
Gratuita. 

ActivePerl-5.8.0.804-MSWin32- 
x86.zip 



108 ►►► F e b b r 



http://www.itportal.it 



LE FAQ DI IOPROGRAMMO 

Le risposte alle domande più frequenti 

Ogni mese troverete riportate le domande che più spesso giungono in redazione. Capita frequentemente che, affrontando 
linguaggi in continua evoluzione, si diano per scontati alcuni concetti o alcune caratteristiche di base: queste pagine sono 
l'occasione per ribadire o spiegare meglio queste nozioni. 




Java 



Cosa accomuna 
Java e C# 

Quando fu presentato, il C# sollevò molte 
perplessità per l'eccessiva somiglianza con 
Java. Addirittura si ventilò un'accusa di pla- 
gio, poi caduta nel vuoto, soprattutto per- 
ché, come spesso accade in questi casi, mol- 
te delle caratteristiche che C# avrebbe "mu- 
tuato" da Java erano in realtà preesistenti a 
Java stesso, della serie: "chi non ha peccato 
scagli la prima pietra"! 
Ormai le polemiche sono spente e C# si è di- 
mostrato semplicemente un nuovo (e ottimo 
per la verità) linguaggio, e ci sembra interes- 
sante, a mente fredda, riassumere breve- 
mente i principali punti di contatto fra il 
gioiello di Sun e l'astro nascente di Micro- 
soft. Eccone un sommario elenco: 

• Entrambi prevedono la compilazione in 
un codice indipendente dalla piattafor- 
ma, codice che viene eseguito da una 
macchina virtuale. 

• Un meccanismo di Garbage Collection e 
la scomparsa dei puntatori (fondamen- 
tali in C++, il C# ne permette l'uso in 
particolari porzioni di codice dichiarate 
esplicitamente unsafe). 

• Potenti meccanismi per la reflection. 

• Assenza di file Header (anch'essi fonda- 
mentali in C++). 

• Tutte le classi derivano dalla classe base 
Object. 

• Supporto per i thread attraverso un 
meccanismo di lock attivato sulle por- 
zioni di codice marcate come locked 
/synchronized. 

• Supporto per le interfacce con eredita- 
rietà multipla per le interfacce stesse e 



singola per le implementazioni. 

• Disponibilità delle inner class. 

• Assenza di funzioni o costanti globali: 
tutto appartiene al dominio delle classi. 

• Uso della "notazione punto" al posto 
degli operatori "->" e "::" utilizzati in 

C++. 

• Tutti i valori sono inizializzati prima di 
poter essere usati. 

• Impossibilità si usare gli interi per valu- 
tare le condizioni di if. 

• I blocchi di Try/ Catch possono avere la 
clausola finally. 

Cosa sono 

gli obfuscator? 

Il bytecode racchiude le informazioni che 
descriviamo con il codice sorgente Java. Il 
bytecode è generato dal compilatore Java ed 
è relativamente semplice risalire al codice 
sorgente attraverso un'operazione di rever- 
se engineering: molti decompilatori, alcuni 
pubblicati anche nei CD allegati a ioPro- 
grammo, consentono infatti di passare dal 
bytecode al codice sorgente in maniera pres- 
soché automatica, e con un buon grado di 
approssimazione. La proprietà intellettuale 
legata al codice da noi prodotto è dunque re- 
sa abbastanza vulnerabile. Gli obfuscator 
(offuscatori) rendono il lavoro dei decompi- 
latori più arduo, ed il codice che si riesce a ti- 
rar fuori è meno leggibile e meno utile. Esi- 
stono essenzialmente due tipi di obfuscator: 
una prima categoria si occupa di cambiare i 
nomi di classi, campi e metodi con sequenze 
di caratteri senza senso, con l'obiettivo di di- 
sorientare e far perdere il senso complessivo 
del progetto. Ciò che rimane in chiaro è la 
struttura dell'applicazione che, con un più 
attento lavoro di reverse engineering, può 
comunque essere "riutilizzata". Una secon- 
da categoria di obfuscator, oltre ad offuscare 
i nomi, si occupa di offuscare anche il flusso 



di esecuzione dell'applicazione, attraverso 
delle leggere modifiche al bytecode che ren- 
dono oscuro il flusso di esecuzione dell'ap- 
plicazione senza (ovviamente) modificarne 
il comportamento. Tipicamente gli offusca- 
tori di questo tipo intervengono nelle strut- 
ture di selezione e nei costrutti di loop, mo- 
dificandoli in maniera tale da non consenti- 
re la ricostruzione del sorgente Java equiva- 
lente. 

Perché dichiarare un 
metodo "synchronized"? 

La sincronizzazione dei metodi in Java 
consente la realizzazione di sezioni criti- 
che nella programmazioni multithread. 
Sezioni cioè in cui è necessario garantire 
che la concorrenza fra i vari thread sia in 
qualche modo "sospesa". Un problema 
che si presenta tipicamente nell'accesso a 
risorse condivise; mettiamo il caso che 
due applicazioni vogliano scrivere sul- 
l'hard disk: per garantire la consistenza 
dell'informazione, è ovviamente necessa- 
rio che quale delle due cominci per prima 
a salvare i dati non venga interrotta dal- 
l'altra. In questi casi si adotta una sorta di 
"lucchetto" virtuale associato alla risorsa 
(in questo caso l'hard disk): se l'applica- 
zione Appi vuole scrivere sul disco, deve 
innanzitutto procurarsi il lucchetto del- 
l'hard disk. L'applicazione App2, che pu- 
re vuole scrivere, tenta di procurarsi il 
lucchetto dell'hard disk ma deve attende- 
re, poiché il lucchetto è detenuto da 
Appi. Quando Appi avrà finito le sue 
operazioni di scrittura, avrà cura di rila- 
sciare il lucchetto. Lucchetto che verrà in- 
tercettato da App2, che inizierà le sue 
operazioni di scrittura, e così via. Ecco 
spiegata, in termini poco ortodossi, l'uti- 
lità della nozione di "lucchetto" nella 
programmazione, multithread. Un meto- 
do è dichiarato synchronized secondo la 
sintassi: 

public synchronized int scriviValoreQ 

{ - 

} 



http: //www. itportal.it 



3 ►►► 109 



Grazie a questa dichiarazione, ad ogni 
istanza della classe cui il metodo appar- 
tiene sarà associato un lucchetto. Nel mo- 
mento in cui un thread invocherà il meto- 
do scriviValoreO, esso diverrà detentore 
del lucchetto associato alla classe di cui 
scriviValoreO è metodo. Il possesso di que- 
sto lucchetto durerà fino alla completa 
esecuzione del metodo scriviValoreO, ciò 
significa che, per tutto questo tempo, nes- 
sun altro thread potrà invocare un meto- 
do synchronized di quello stesso oggetto. 
Se il metodo, oltre ad essere dichiarato 
synchronized, è definito anche come sta- 
tic, il lucchetto sarà esteso all'intera classe 
e non più alle singole istanze. 

Perché dichiarare 
una classe abstract? 

La parola chiave abstract serve a indicare 
una classe o un metodo che non ha im- 
plementazione. Quando una classe è di- 
chiarata abstract, essa non può essere 
istanziata. Solo le sottoclassi di una classe 
astratta possono essere istanziate, sempre 
che non siano state dichiarate abstract a 
loro volta. Similmente, dichiarando un 
metodo come abstract, si specifica che il 
metodo non è implementato nella classe 
in cui è dichiarato, ha solo la signature: 

abstract class Risorsa { 

//■■■ 

public abstract int leggiValoreQ; 

} 

Un metodo astratto esiste solo allo scopo 
di essere sovrascritto (overridden) nelle 
sottoclassi della classe in cui è dichiarato. 
E' bene tenere presente che un metodo 
astratto può essere dichiarato solo nel- 
l'ambito di una classe astratta, mentre 
non è obbligatorio che una classe astratta 
presenti dei metodi astratti. Nel momen- 
to in cui si dichiara una sottoclasse di una 
classe astratta, la sottoclasse deve neces- 
sariamente fornire una implementazione 
dei metodi astratti della superclasse, o in 
alternativa essere dichiarata a sua volta 
come classe astratta. 

Qual è il ruolo di static 
in Java? 

Quando dichiariamo static una variabile 
di una classe, quella varibile viene istan- 
ziata una sola volta, qualsiasi sia il nume- 
ro di istanze create a partire da quella 
classe. 
In pratica, se un'istanza della classe cam- 



bia il valore di quella variabile statica, il 
cambiamento si riflette in tutte le altre 
istanze della classe. Se invece dichiaria- 
mo un metodo static, il campo di azione 
del metodo si sposta dalle istanze della 
classe alla classe stessa. Un metodo stati- 
co può fare riferimento solo a variabili e 
metodi statici e non accetta V over ride nel- 
le classi derivate dalla classe di apparte- 
nenza: un metodo static è implicitamente 
definito final. 

Cos'è un file JAR ? 

JAR è un acronimo e sta per Java ARchi- 
ve. Un file .jar è semplicemente un archi- 
vio di file compressi. In un file JAR è pos- 
sibile sistemare tutte le classi necessarie 
ad un'applicazione con il vantaggio di 
una notevole riduzione dello spazio oc- 
cupato dalla versione del software che di- 
stribuiremo. Supponiamo di voler creare 
un file .jar, chiamato archivio.jar, in cui si- 
stemeremo tutti i file presenti in una di- 
rectory. 
Ecco la sintassi: 

jar -cf archvio.jar *.* 

Lo switch -e è servito a indicare la vo- 
lontà di creare un nuovo archivio, mentre 
con -f abbiamo la possibilità di specifica- 
re il nome del file. Per avere il dettaglio 
delle operazioni compiute da Jar, possia- 
mo aggiungere lo switch -v. 

jar -cvf ajarfile.jar *.* 

In questo modo appiamo attivato V opzio- 
ne "verbose", con il risultato di avere in 
output tutte le informazioni riguardo ai 
file inseriti nell' archivio. Per estrarre il 
contenuto di un file Jar, la sintassi è la se- 
guente: 

jar -xf ajarfile.jar 

È possibile visualizzare V elenco completo 
delle opzioni disponibili avviando il co- 
mando jar, senza fornire alcun parametro. 

Cos'è la Extreme 
Programming? 

Con Extreme Programming (XP) si inten- 
de una serie di regole e principi per lo svi- 
luppo rapido di software professionale. 
Lo scopo è dunque duplice: massima ve- 
locità nella realizzazione e massima qua- 
lità possibile del prodotto finito. 
XP rappresenta una sorta di metodologia, 



anche se una delle più leggere e semplici 
da seguire, che può essere ripetuta ogni 
qual volta si debba sviluppare un'appli- 
cazione. Vediamo brevemente le dodici 
principali regole della Exreme Program- 
ming: 

1) Il punto di partenza è rappresentato 
dalla scrittura delle cosiddette "User 
Stories". In questa fase i committenti 
e gli sviluppatori collaborano per la 
definizione specifiche funzionali e del 
tempo necessario alla realizzazione 
dell'applicativo. I committenti sono 
chiamati a definire scrivere queste 
storie: ognuna rappresenta una fun- 
zionalità del sistema. Le singole storie 
saranno esaminate dagli sviluppatori 
al fine di valutare il tempo di svilup- 
po necessario. Normalmente, se una 
storia impiega più di tre settimane, si 
considera troppo grande e va spezza- 
ta in più sotto-storie, se invece richie- 
de meno di una settimana, vuol dire 
che si è scesi ad un livello di dettaglio 
eccessivo e la storia va accorpata con 
un'altra. 

2) Rilasciare nuove versioni il più pre- 
sto possibile. Rilasciare spesso al 
cliente nuove versioni, aggiungendo 
anche poche caratteristiche per volta, 
consente di avere un continuo feed- 
back sul lavoro e permette di correg- 
gere immediatamente eventuali errori 
della progettazione. 

3) Scegliere una metafora per il sistema 
che si va implementando. La metafo- 
ra consente di ricordare facilmente i 
nomi degli oggetti coinvolti nel pro- 
getto o consente di "indovinarli" se 
non li si ricorda. 

4) Usare sempre il design più semplice 
possibile. Le richieste possono cam- 
biare da un giorni all'altro e dunque è 
bene progettare con l'obiettivo di sod- 
disfare solo le richieste attualmente 
formulate. Inoltre, il fatto che l'XP sia 
un processo iterativo, consente di pro- 
seguire per affinamenti successivi. 

5) Testare continuamente. Prima di scri- 
vere una nuova funzione, il program- 
matore scrive un test per metterla alla 
prova. Il lavoro si considera fatto 
quando i test hanno esito positivo. 
Esistono due tipi di test: 



!!()►►► F e b b r 



http: //www. itportal.it 



a. Unit Test: sono test automatici 
scritti dagli sviluppatori per pro- 
vare il codice mentre lo scrivono. 
Generalmente ogni Unit Test pro- 
va una singola classe o un piccolo 
insieme di classi, inoltre per effet- 
tuare gli Unit Test si adottano tipi- 
camente dei framework specifici 
come il JUnit (descritto nelF artico- 
lo dell' ottimo Paolo Per rotta pre- 
sente in questo stesso numero di 
ioProgrammo) 

b. Acceptance Test: noti anche come 
test funzionali, sono definiti dai 
committenti allo scopo di verifica- 
re che il sistema rispetti comples- 
sivamente le specifiche. I test fun- 
zionali si occupano in genere di 
verificare Finterò sistema o larghe 
porzioni di esso. Un tipico test 
consiste in uno script equivalente 
alle azioni di un comune utente di 
fronte al sistema e nella verifica 
che il risultato sia coerente con le 
aspettative. 

6) Cancellare sempre il codice super- 
fluo. Spesso si è portati a mantenere 
delle vecchie funzioni o classi non più 
necessarie, o anche pezzi di codice 
che ormai non utilizziamo più. L'XP 
consiglia di eliminare tutto il super- 
fluo il più spesso possibile. Grazie ai 
continui test abbiamo la garanzia di 
non buttare via niente di utile e pos- 
siamo dunque procedere ad un refac- 
toring continuo. 

7) Programmazione in coppia. Tutto il 
codice è prodotto da due programma- 
tori seduti alla stessa workstation. In 
pratica, questo "trucco" consente di 
avere il codice revisionato nel mo- 
mento stesso in cui viene prodotto. 
Può apparire una misura eccessiva 
ma è stato dimostrato che il codice 
prodotto da due programmatori che 
lavorino assieme è migliore e più con- 
sistente del codice prodotto dagli stes- 
si separatamente. Tipicamente, il pro- 
grammatore che scrive "fisicamente" 
il codice bada alla correttezza sintatti- 
ca, mentre l'altro cerca di tenere uno 
sguardo di più ampio respiro, control- 
lando la correttezza semantica di 
quanto si va sviluppando. 

8) Il codice è di tutti. Nessuna persona e 



nessuna coppia può dirsi proprietaria 
di un pezzo di codice. E' riconosciuto 
a tutto il team il diritto di agire su 
qualsiasi parte del codice. Chiunque 
può aggiungere funzionalità ed effet- 
tuare debugging su qualsiasi pezzo di 
codice in qualsiasi momento. Questa 
che potrebbe apparire una libertà ec- 
cessiva è possibile e assolutamente si- 
cura grazie alla presenza dei test: 
chiunque apporti una modifica, deve 
garantire che essa superi i test previsti 
per quella porzione di codice. 

9) Integrare continuamente. Gli svilup- 
patori devono integrare le modifiche 
che apportano al più presto possibile 
e, in ogni caso, non deve passare più 
di un giorno prima che le modifiche 
vengano integrate nel sistema. Solo 
così è garantita la consistenza fra tut- 
te le unità di codice, oltre a permette- 
re a tutti gli sviluppatori di lavorare 
sempre con la versione più aggiorna- 
ta del codice. 

10) Si lavora non più di quaranta ore a 
settimana. Tutti i programmatori van- 
no via al momento giusto, solo in si- 
tuazioni critiche è contemplata una 
settimana di straordinari. Se comin- 
ciano a presentarsi più settimane con- 
secutive di straordinari, vuol dire che 
c'è qualcosa da rivedere nel processo 
di produzione. 

11) Il cliente deve essere sempre dispo- 
nibile. È necessario che ci sia un con- 
tinuo scambio di idee fra gli sviluppa- 
tori e il committente che non deve 
dunque limitarsi a presentare le User 
Stories air inizio del progetto, ma de- 
ve rappresentare un punto di riferi- 
mento costante per tutto il team. Le 
User Stories sono infatti dei canovacci 
molto approssimativi ed è necessario 
un continuo feedback del cliente per 
indirizzare correttamente lo sviluppo 
del progetto. 

12) Codice standard. Il codice deve esse- 
re scritto rispettando standard comu- 
ni accettati da tutti. In pratica, leggen- 
do diverse porzioni di codice, non do- 
vrebbe essere possibile distinguere la 
"mano" del programmatore. Questa 
coerenza formale consente una facile 
leggibilità ed un semplice accesso a 
tutti gli sviluppatori verso qualsiasi 




porzione del progetto. 



Visual Basic 



Quando usare Private 
per le dichiarazioni di 
variabili e di procedure? 

Ogni volta che ciò è possibile, è bene usare 
Private per le dichiarazioni. Dichiarando 
Private le procedure e le variabili di un mo- 
dulo, infatti, queste saranno accessibili sol- 
tanto nel modulo stesso: 

Private variabile As Integer 

Private Sub Procedura() 

Conoscere a priori se una variabile o una 
procedura debba essere dichiarata Private o 
Public non è facile, specialmente se non si è 
valutato bene il problema al momento della 
redazione del codice. Se la variabile o la pro- 
cedura è dichiarata Public quando non do- 
vrebbe esserlo, si potrebbero creare proble- 
mi di eccessi di visibilità dell'oggetto in que- 
stione. Per fortuna, molti di questi problemi 
possono essere risolti con un'analisi auto- 
matica del codice. 

Come si può ottimizzare 
la velocità di 
visualizzazione? 

La velocità di visualizzazione di un pro- 
gramma è spesso più importante della 
sua reale velocità di esecuzione. Ecco al- 
cuni suggerimenti per aumentare la velo- 
cità di visualizzazione di un'applicazio- 
ne: 

• Impostare la proprietà ClipControls 
sul valore False. 

• Usare il controllo Image invece di Pic- 
tureBox e Label invece di TextBox quan- 
do possibile. 

• Nascondere i controlli quando si im- 
postano le proprietà; ciò impedisce di 
effettuare ridisegni multipli. 

• Mantenere nascosto un form prece- 
dentemente caricato per visualizzarlo 
velocemente. Questo metodo richiede 
un dispendio cospicuo di risorse di 
memoria. 

• Usare priorità basse per i processi lun- 



http:// www. itportal.it 



3 ►►► 111 



ghi. Si possono realizzare processi a 
bassa priorità di esecuzione collocan- 
do opportunamente dei controlli DoE- 
vents. Un ottimo posto dove collocare 
i DoEvents sono i cicli interni. Bisogna 
tenere presente, però, che l'utente po- 
trebbe premere qualche tasto. Il pro- 
cesso a bassa priorità deve tener con- 
to di ciò che l'utente può o non può 
fare durante la sua esecuzione. Impo- 
stare quindi le proprietà Processing col 
valore True. 

Usare barre di avanzamento di stato. 

Pre-caricare dati che serviranno suc- 
cessivamente. Per esempio, potete ca- 
ricare i contenuti di una tabella di un 
database in un vettore. 

Usare la caratteristica Show degli eventi 
Form_Load. 

Semplificare lo startup form o usare uno 
splash screen. 



C + + 



Quando vengono 
invocati i distruttori 
per le variabili locali? 

Le variabili "non-static" vengono distrut- 
te automaticamente quando V esecuzione 
esce dal loro ambito di visibilità. Senza 
voler approfondire troppo il concetto di 
visibilità, possiamo affermare che V ambi- 
to di vita di una variabile termina subito 
dopo il simbolo "}" in cui la variabile è 
stata dichiarata. Al momento dell'uscita 
da tale ambito, le variabili vengono di- 
strutte dal compilatore chiamando il di- 
struttore appropriato nella loro classe di 
appartenenza. Se l'oggetto ha allocato 
memoria (ad esempio un array), la distru- 
zione rilascia la memoria precedentemen- 
te impegnata: 





il 

main() 

{ 

//■■■ 

{vettore v(5); // alloca la memoria 

// operazioni... 

} // fine dell'ambito di visibilità 

dell'oggetto vettore 

// l'oggetto vettore viene qui distrutto, 

e la memoria viene rilasciata 

//■■■ 

} 

Come funzionano 

le espressioni separate 

da virgola? 

Le espressioni separate da virgola deriva- 
no dal linguaggio C. Spesso queste istru- 
zioni sono impiegate all'interno di elicli 
for e while. Le regole sintattiche di queste 
istruzioni, tuttavia, sono lungi da essere 
intuitive. In primo luogo, un'espressione 
può essere composta di una o più espres- 
sioni secondarie separate da virgola. 
Consideriamo, ad esempio, la seguente 
espressione: 

if (++x, --y, cin.good()) 

L'istruzione condizionale if contiene tre 
espressioni separate da virgola. Il compi- 
latore C++ si assicura che ciascuna delle 
espressioni venga valutata e che i relativi 
effetti avvengano. In questo caso, la va- 
riabile x viene incrementata e la variabile 
y è decrementata. Tuttavia, il valore del- 
l'intera espressione separata da virgola è 
soltanto il risultato dell'espressione più a 
destra. Di conseguenza, l'istruzione if di 
sopra è vera solo se il metodo cin.goodO 
ritorna true. Consideriamo invece la se- 
guente espressione: 

int j = 10; 

int i=0; 

while( ++i, — j) 

{ //- > 

Nel ciclo while, la variabile i viene incre- 
mentata mentre la variabile j è decremen- 
tata. Il ciclo prosegue fintanto che il valo- 
re di j è maggiore di 0. 

Come richiamare una 
funzione prima dell'avvio 
di un programma? 

Alcune applicazioni richiedono di invo- 
care funzioni prima che la parte principa- 
le del programma venga eseguita. Ad 



esempio, la funzione di log deve essere ri- 
chiamata prima dell'esecuzione dell'ap- 
plicazione. Il metodo migliore per invo- 
care queste funzioni è di collocare la loro 
invocazione all'interno del costruttore di 
un oggetto globale dell'applicazione, 
questo perché gli oggetti globali sono co- 
struiti prima che l'esecuzione passi al 
programma. Pertanto, le funzioni invoca- 
te in un costruttore di un oggetto globale 
verranno invocate prima della funzione 
maini). Ad esempio: 

class Login 

{ 

public: 

LoginQ 

{ 

attiva_login(); 

> 

h 

Login log; // istanza globale 

int main() 

{ record * prec=Leggi_login(); 

//.. codice dell'applicazione 

} 

L'oggetto globale log viene costruito pri- 
ma che l'esecuzione passi alla funzione 
main(). Durante la costruzione, l'oggetto 
invoca la funzione attiva _login(). Quando 
l'esecuzione passa alla funzione main() 
dell'applicazione, è possibile quindi leg- 
gere i dati dal log file. 

Cosa sono i puntatori 
ai membri? 

Una classe può avere due categorie di 
membri: membri funzioni (metodi) e mem- 
bri dati (variabili membro). Inoltre, esisto- 
no due tipi di puntatori: puntatori a me- 
todi e puntatori a variabili membro. Gli 
ultimi sono i più diffusi poiché, general- 
mente, le classi non hanno variabili mem- 
bro pubbliche. Tuttavia, se utilizziamo 
codice C esistente che contiene dichiara- 
zioni struct o classi che hanno variabili 
membro dati pubbliche, i puntatori a 
queste variabili possono rivelarsi molto 
utili. La sintassi per i puntatori a membri 
è una delle più complicate del linguaggio 
C++. L'uso di tali puntatori, però, rappre- 
senta una caratteristica molto potente del 
linguaggio, perché permette di invocare 
una funzione membro di un oggetto sen- 
za conoscerne il nome. Analogamente, è 
possibile usare un puntatore per esami- 
nare o modificare il valore di una variabi- 
le membro senza conoscerne il nome. 



112**> F e b b 



http: //www. itportal.it 



N B O 




Box 

L'esperto risponde... 



FLASH e VB 

► ►►►►►►►►►►►►►► 

Gentile Giuliano Uboldi, sono un 
programmatore "in erba" di 14 
anni ed avrei bisogno del tuo aiuto: 
nel numero 10 di ioProgrammo (12 
102), ho trovato molto interessante 
l'articolo sull'integrazione di Flash con 
VB e provando a realizzare, per 
cominciare, il programmino sono in- 
cappato in un errore: innanzi tutto 
premetto che io utilizzo VB6 e Flash 
MX su una piattaforma WIN 2000. 
Ora, dopo aver compilato la parte 
Flash e quella VB ho provato a far 
partire il programma dal VB stesso, 
ma il debugger trova un errore nella 
Sub Aggiorna alla stringa: 

"Textl.Text = Flash l.GetVariable("areaTesto.text" 
)" (Textl è il Testo dell'articolo); 

l'errore riscontrato è: 

"Errore di runtime '-2147467259(80004005) 
Metodo 'GetVariable' dell'oggetto 
'IShockVaweFlash' non riuscito 

La ringrazio e la prego di inviarmi o 
pubblicare al più presto una sua 
risposta. Distinti saluti. 

Alberto Santini 

Risponde: Giuliano Uboldi 

Caro Alberto, devo ammettere che, 
prelevando direttamente i file del- 
l'esempio dal ed ed utilizzandoli in Win 
2000 si ottiene l'errore di runtime che hai 
riportato. Ciò è dovuto ad un errato ri- 
ferimento di VisualBasic rispetto al com- 
ponente da utilizzare per eseguire l'ap- 
plicazione in oggetto. Per correggere questo 
comportamento si deve, dal menù Progetto- 
riferimenti, controllare che il riferimento al 
controllo Shockwave Flash sia legato ad un 
file .ocx piuttosto che ad uno .oca. Se infatti 
il riferimento al componente ShockWave 
Flash è legato ad un .oca, anche se con lo 
stesso nome, il programma non funziona. 
Tutto ciò che devi fare quindi è selezionare 



dall'elenco che appare, selezionando le voci 
di menù sopra indicate, l'altro componente 
ShockWave Flash.ocx che sicuramente 
troverai. Vedrai che con questa semplice 
correzione riuscirai a far girare il tutto. Un 
caro saluto. 

MFC e WIN32 

► ►►►►►►►►►►►►►► 

Un saluto e molti complimenti 
per la rivista che leggo bramo- 
samente ogni mese. Domandina: 
che differenza c'è fra MFC e WIN32 
(visualC++)? E' una questione di 
librerie, o anche di architettura? 

Alessandro Danilo Brevi 

Per realizzare un'applicazione che giri su 
piattaforma Windows, il compilatore deve 
interfacciarsi con il sistema operativo 
attraverso delle API (Application Program- 
ming Interface) che nel caso di Windows 
prendono proprio il nome di Win32 (dove 
32 sta per 32bit). Inizialmente, le API di 
Windows vennero sviluppate come un 
insieme di procedure separate e rilasciate 
attraverso una piattaforma chiamata 
Windows API SDK (Software development 
Kit), inizialmente con Api a 16 bit. La 
realizzazione delle applicazioni sotto 
Windows era pertanto realizzata mediante 
l'uso di queste "procedure" di sistema. Un 
esempio di applicazione realizzata sono le 
prime versioni di Word per Windows. Ad 
un certo punto, visto il diffondersi della 
programmazione object oriented, un team 
venne incaricato di sviluppare un 
framework ad oggetti in cui venissero 
incapsulate le API di sistema. Questo per 
facilitare la realizzazione delle applicazioni 
e per permettere un elevato riutilizzo del 
codice. Il framework in questione è ap- 
punto MFC (Microsoft Founfation Classes). 
Visto il successo di questo framework, ad 
un certo punto si decise di riscrivere le API 
di Windows in chiave MFC. Pertanto, oltre 
a costituire un potente framework per lo 
sviluppo di applicazioni in ambiente 
Windows, le MFC rappresentano oggi le 
API stesse del sistema, e cioè il modo 



privilegiato di interfacciarsi con esso 
attraverso un'architettura ad oggetti. 

Applicazioni prive di form 

► ►►►►►►►►►►►►►► 

Cara redazione, sono abbonato a 
ioProgrammo ormai da tre anni, 
e penso che questo segno di stima 
mi possa esimere dal formularvi i 
complimenti di rito. Arrivo subito al 
dunque: vorrei realizzare un'appli- 
cazione in Visual Basic, che non 
presenti alcuna form. Vorrei cioè 
che l'applicazione avesse le 
sembianze di un semplice message 
box... so che può sembrare una 
richiesta un po' strana, ma avrei 
bisogno di una risposta in tal senso. 
Vi ringrazio e vi auguro buon 
lavoro. 

Stefano 

Per ottenere il risultato che desideri, 
apriamo un nuovo progetto Visual Basic e 
andiamo ad eliminare tutte le form incluse 
nel progetto (essendo il progetto nuovo, si 
tratterà di eliminare semplicemente formi). 
Dal menu Progetto, selezioniamo la voce 
Proprietà e, dal combobox "Oggetto di avvio", 
selezioniamo "Sub Main". A questo punto, 
aggiungiamo un nuovo modulo standard al 
progetto e, all'interno di questo, creiamo 
una procedura chiamata "Main" attraverso 
un codice simile a quello che puoi trovare 
di seguito 

Private Sub MainQ 

MsgBox("Ciao!") 

End Sub 

Ovviamente, al posto del Message Box, 
puoi aggiungere qualsiasi codice, ed il tutto 
sarà eseguito senza che venga visualizzata 
alcuna form. 

Per contattarci: 

e-mail: iopinbox@edmaster.it 

Posta: Edizioni Master, 

Via Cesare Correnti, 1 - 20123 Milano 



http://www.itportal.it 



3 ►►► 113 



I L 



Sito de 



Gamasutra 

The Art & Science of Making Games http://www.gamasutra.com/ 



Chiacchierando con amici, colleghi e cono- 
scenti interessati al mondo della pro- 
grammazione, ho avuto modo di verifica- 
re come le mie radici di informatico affondino in 
un terreno fertile e condiviso. Correva la seconda 
metà degli anni '80, ed io ero ancora un bambino 
sotto i dieci anni. Già qualche volta, entrando di 
soppiatto nelle proibitissime sale giochi, ero rima- 
sto affascinato da quegli strani "scatoloni con la 
TV" che monopolizzavano l'attenzione di molti 
ragazzi un po' più grandi di me. Ricordo ancora, 
con grande nostalgia, i diabolici piani che orga- 
nizzavo insieme agli amici d'infanzia per andare a 
giocare liberamente senza essere scoperti dai 
nostri genitori. Evidentemente, però, non siamo 
stati molto abili, giacché in famiglia qualcuno 
intese immediatamente la mia passione per i gio- 
chi elettronici. Per la prima comunione, infatti, 
ricevetti in regalo uno storico Atari 2600, che non 
avevo richiesto e di cui nemmeno sospettavo l'esi- 
stenza. Quel regalo, visto col senno di poi, mi ha 
cambiato la vita. Di lì in poi, la mia passione per i 
videogiochi è cresciuta in maniera esponenziale. 
Prima il Commodore 64, poi numerose console 
quali il Master System, il Mega Drive ed il Game 
Gear (sì, ero un partigiano della fazione Sega, ai 
tempi della lotta contro Nintendo), quindi 
l'Amiga ed infine il PC Intel. Già ai tempi del 
Commodore 64 mi domandavo quali fossero gli 
"ingredienti" di un videogioco. Chi crea i video- 
giochi? Come è possibile costruire qualcosa di 
simile? Nessuno dei miei compagni di giochi 
sapeva dare risposta a queste domande. Così co- 
me le popolazioni primitive, nella loro ignoranza, 
attribuirono il fulmine al potere degli dei, per noi 
il "creatore di videogiochi" era una figura mitolo- 
gica ed inarrivabile. Dire "da grande voglio fare il 
creatore di videogiochi" era proprio come voler 
divenire astronauta, calciatore, pilota di Formula 1 
o Presidente della Repubblica. Passavamo le sera- 
te estive a sognare il nostro videogioco ideale, 
come se di lì a poco l'avremmo realizzato. A dieci 
anni circa, sapevo qualcosa di programmazione 
applicata al Commodore 64, ma nulla di esatta- 
mente cosciente. Che un videogioco potesse esse- 
re realizzato in casa, lo scoprii poco tempo dopo. 
Il merito lo devo dare proprio ad una rivista e alla 
sua rubrica "Talent Scout", che recensiva le attra- 
zioni videoludiche sviluppate dai lettori. Scoperta 
la possibilità ed esplorati i mezzi, non so quantifi- 



care il tempo speso sulla tastiera, a digitare istru- 
zioni Basic e Pascal. Non credo di aver mai abban- 
donato il sogno di sviluppare videogiochi, benché 
la passione per la programmazione videoludica 
sia poi mutata lentamente in amore per l'informa- 
tica, in termini più generali. Chissà quanti di quei 
bambini sognatori, oggi, sono divenuti informati- 



pochi motti così ispirati. Progettare e realizzare 
videogiochi è qualcosa a metà strada tra l'arte e la 
scienza. Gamasutra è una sterminata raccolta di 
articoli che coprono tutte le fasi dello sviluppo di 
un videogioco moderno, dal design alla program- 
mazione, dalla grafica all'audio, fino a giungere 
alle questioni legali sollevate dalla pubblicazione 



G3FHà|\J6tWOrk GaineuBYelDpefBConleience (3 sin e Developer ilagazh 

T li e Art & Science o f AJ ù k i a e G ù m e s 



Ine Gamasutra. corri 



Gamasutra 



<YOU, 



news | features | cornpanies | jobs | resurnes | education | product guide | projects | sture 



December 22, 102 

Welcome! rLoqin...1 




Latest News: 

E Microsoft Releases DirectX 9 [12.21.02] 

► TDK Mediacre Lowers Guidance ri2.21.02l 

► Game Industri Gets "Failinq Grade" For Violence Aqainst Wornen [12.21.02] 

► Mac Games Support Force-Feedback [12.21.02] 

► Warthoq Acquires Zed Two [12,18,02] 

► Free Cq Plug-in For Maya Released [12.18.02] 

► Actiuision Lowers Guidance For : Shares Fall ri2.17.Q2l 

► ATI Inyestiqated By Canadian Securiti jon [12. 17. 02] 
Y GTA Franchise Helps Propel Take-Twc 32 Results fl2.17.02l 

► NCsoft Acquires ArenaNet [12,16,02] 
[More News...l 



b Design | Visual Ari | Production | Business | Education | Audio | Postmortem 



The development of Ditngeon S/e«je was about 
muchi more than the RPG you may have played 
by novi. Dtingnon S/ege. vias a Herculean effort 
by a small gnoup of people who simultaneously 
started Gas Powered Games, buìlt their first 

RPr:. anH hijHp a hit- namt». 



Programmingl G 

Latest Articles: 

► Postmortem; Dm by Bartosz Kijanka [12.18.02] 

► Action-Based Discretization for AI Search by Todd Neller [12.11.02] 

► implementinq Puzzles by Pascal Luban [12,06,02] 

► Postmortem; Bì : by Scott Grieg., et al [12.04,02] 
2002 Mobile Games Resource Guide [11.25.021 Gamasutra's latest 
resource guide offers a selection of features devoted to the design and 
creation of mobile games, Features include: 




ci, programmatori, ingegneri, amministratori di 
sistema e altro ancora. Sì, le scappatelle in sala gio- 
chi e quello strano Atari 2600 mi hanno cambiato 
la vita. Nonostante l'età avanzi senza sosta, il 
sogno nel cassetto non è mai scomparso. 
Sviluppare videogiochi, forse, non sarà mai il 
lavoro che mi darà il pane, ma sono certo che 
rimarrà sempre uno degli hobby prediletti. Oggi, 
ad ogni modo, realizzare un videogioco è tutt'al- 
tro che semplice. Il mito del programmatore soli- 
tario è rilegato al passato. Lo sviluppo di un 
videogioco, con le possibilità dei tempi nostri, 
richiede personale e mezzi che si avvicinano più 
al settore cinematografico che non a quello infor- 
matico. Nessuno, ad ogni modo, ci vieta di porta- 
re avanti i nostri amati progetti. Al mondo sono 
ancora tanti quelli che bramano il parto del video- 
gioco dei loro sogni. Che lo si faccia per professio- 
ne o per hobby, Gamasutra rimane un riferimento 
imperdibile. "The Art & Science of Making 
Games", ossia "l'Arte e la Scienza di Fare Giochi", 
recita la striscia sopra il logo del sito. Ho letto 



e dalla diffusione di un gioco. Nessuna piattafor- 
ma videoludica è estranea a Gamasutra. Troverete 
informazioni preziose per sviluppare giochi desti- 
nati, indifferentemente, ai personal computer, alle 
console e ai dispositivi portatili. Più che altro, la 
sezione rivolta agli autori di codice si concentra 
principalmente su tecniche algoritmiche di appli- 
cazione universale. Non mancano articoli di rifles- 
sione sul mondo videoludico, news sempre 
aggiornate, interviste con personalità del settore, 
calendari di eventi, bacheche per gli annunci ed 
altro ancora. In poche parole, Gamasutra è una 
fresca rivista elettronica che apre un'ampia fine- 
stra sull'affascinante universo del game program- 
ming. Una paio di note negative: per accedere al 
materiale disponibile nel sito è sempre necessario 
registrarsi, ed il layout delle pagine non è molto 
commestibile. Mali perdonabili, davanti alla 
bontà e alla ricchezza dei contenuti. Bookmark 
d'obbligo per ogni game programmer o aspirante 
tale. 

Carlo Pelliccia 



114^*> F e b b 



http: //www. itportal.it