Ecco la funzione di terminazione che abbiamo, nel capitolo scorso, proposto al lettore come esercizio:
Se pSC
è diverso da zero, era stato acquisito, e quindi
deve ora, in terminazione, venire rilasciato (lo azzeriamo
poi, come da buona prassi, ad evitare futuri equivoci!).
Infine, CoUninitialize
deve venire chiamata, visto che
alla inizializzazione avevamo chiamato CoInitialize
.
Più interessante il problema di assegnare la funzione
(IndiEs_Espr
) e valutarla (IndiEs_Valuta
). Lo script
control offre un metodo Eval
, che valuta una espressione e ne
ritorna il risultato, e la cosa più semplice è sicuramente quella
di usarlo per la IndiEs_Valuta
; non è, tuttavia, nè
il metodo più efficiente, nè il più potente dal punto di
vista del nostro utente.
Dal punto di vista dell'efficienza: con Eval
, obblighiamo
l'interprete che usiamo a ripetere ogni volta il parsing
dell'espressione; a seconda dell'interprete in gioco,
questo potrebbe essere un carico notevole, rispetto
ad una alternativa come usare AddCode
per definire
una funzione avente come corpo la nostra espressione
(il che permette all'interprete di fare il parsing una
sola volta, nella AddCode
, e "compilarsi" una forma
interna di più rapida valutazione), poi Run
per
la "esecuzione" della funzione così definita.
Dal punto di vista dell'utente, essere limitato a scrivere una singola espressione può essere una grossa sottrazione della potenza effettivamente messa a sua disposizione dal linguaggio interprete usato; ad esempio, a seconda del linguaggio in questione, in una "espressione" potrebbe non essere in grado di usare condizionali (IF), cicli (WHILE), eccetera.
In questo senso, sarebbe sicuramente meglio mettere a
disposizione un edit multi-linea per la "espressione",
con la convenzione, ad esempio, che essa deve così
definire una funzione F
che prende un solo argomento;
di questa intera funzione possiamo fare AddCode
, e
così soddisfare anche le esigenze di prestazioni.
Non si può, inoltre, non rilevare che l'utente apprezzerebbe certo anche la possibilità di "caricare" il codice da un generico file di testo -- ma non abbiamo ancora visto cosa le API mettono a nostra disposizione per questo compito, e l'utente potrà comunque fare copia-e-incolla da un notepad (o altro programma editor di testi) al controllo edit multi-line di cui sopra, con meno comodità ma egual funzionalità.
Tuttavia -- non esploreremo ulteriormente questa strada, pur così
più interessante, preferendo, invece, scegliere la semplicità
d'uso di Eval
. Il lettore è, come sempre, calorosamente
invitato ad esplorare in proprio le ricche possibilità (cui noi ci
limitiamo ad accennare, poichè questo è solo un tutorial,
cioè una introduzione!); l'unica difficoltà reale nell'uso di
AddCode
e Run
potrebbe stare nell'argomento
Parameters
di quest'ultima, che, e questo lo anticipiamo
volentieri!, può essere gestito così...:
Qui, in nome dell'ottimizzazione, abbiamo usato parecchie
variabili con storage-class static
,
per non dover ripetere ogni volta l'inizializzazione
(in C, a rigor di standard, non si può inizializzare uno static
con un'espressione run-time, a differenza che in C++; in C,
bisognerà dunque usare un esplicito "first-time switch", un
idioma d'altronde ben noto nel linguaggio in questione!).
Ma torniamo al discorso più semplice...! La Eval
accetta
come espressione da valutare una BSTR
(abbiamo già visto
al capitolo precedente
come crearla da una stringa "normale"), e ritorna il risultato
(se ha successo) in una VARIANT
. Windows offre varie API
per manipolare le VARIANT
; in particolare, due che qui ci
interessano sono:
VARIANT
a "vuota" (si può sostituire,
un po' volgarmente ma efficientemente, con l'assegnazione
di VT_EMPTY
al campo vt
del VARIANT
, che è il "tag" che
ne determina il tipo); e, più importante (nel senso di,
meno facilmente rimpiazzabile!-):
pVarDest
e pVarSrc
possono puntare allo stesso
VARIANT
, e le wFlags
sono normalmente 0
;
in vt
, si pone il tipo che si vuole fare assumere a
*pVarSrc
, VT_R8
nel nostro caso, e
VariantChangeType
(se l'HRESULT
che torna soddisfa la
SUCCEEDED
, naturalmente) provvede ad eseguire la trasformazione
richiesta; dopo di che, possiamo ottenere il risultato double
che
ci interessa, direttamente dal campo dblVal
del
VARIANT
.
Dal punto di vista della struttura del codice, vogliamo sicuramente evitare,
almeno!, di "pagare" ad ogni chiamata ad IndiEs_Valuta
anche per la trasformazione da char*
a BSTR
;
questa trasformazione, dunque, vorremo farla "una volta per tutte" nella
IndiEs_Espr
-- e, visto che la BSTR
serve poi nella
IndiEs_Valuta
, dovremo farne (nella impostazione di tipo
procedurale che abbiamo dato al pacchetto IndiEs
) un'altra
variabile static del sorgente IndiEs.c (dovrà, naturalmente, essere
liberata in IndiEs_Finis
).
Abbiamo dunque tutti gli elementi che ci servono per trasformare questo progetto in codice... e, come al solito, lasciamo il completamento di questo lavoro come esercizio al lettore, promettendo, pure come al solito, "il seguito alla prossima puntata". Ma il lettore dovrebbe davvero provare a realizzare l'IndiEs.c, imperniata sul VBScript, la cui traccia abbiamo sinora fornito, senza crogiolarsi nella pigrizia per la probabilità (certezze, nella vita, non ce ne sono!-) che il nostro prossimo capitolo presenti la soluzione già fatta... non si impara veramente un argomento di programmazione, senza provare un poco, in prima persona, a scrivere il codice in gioco...!
Capitolo 37: COM: alcune API, e le BSTR
Capitolo 39: Indies: l'implementazione
Elenco dei capitoli