Articolo
PREMESSA
In questo articolo tratteremo il problema di incompatibilità tra il Visual Basic 6.0 (ma anche VB.NET non è immune al 100% da questo problema) e le icone a 32 bit con canale Alpha (quelle di Windows XP, per capirci). Potrebbe anche essere che il problema qui descritto non vi sia mai capito (come è accaduto a me fino a poco tempo fa) ma per la nota legge di Murphy prima o poi... Ed infatti a me è capitato!
Microsoft Windows 3.1 ci aveva abituato con le icone 32x32 a 16 colori, poi
con l'avvento di Windows 95 le icone iniziarono ad contenere due formati: 16x16
e 32x32. Oggi le cose sono molto cambiate, le icone possono contenere decine
di immagini in diversi formati, tra cui le icone a 32bit.
Poter quindi utilizzare anche le nuove icone di Windows XP a 32bit è
molto importante. Dobbiamo infatti riconoscere che le nuove icone sono veramente
belle ed occorre quindi esser pronti per offrire un prodotto sempre più
accattivamente anche dal punto di vista grafico.
IL PROBLEMA
Questo problema si riscontra ogni volta che si tenta di caricare un'icona a 32bit da Visual Basic in qualsiasi controllo grafico (Form, PictureBox, Image, ecc.). Tentando infatti questa operazione Visual Basic risponde con un bel messaggio (si fa per dire):
Immagine non valida (Errore 481)
La descrizione dell'errore dice:
È stato assegnato un formato grafico non valido alla proprietà Picture. Causa e soluzione dell'errore:
Si è cercato di assegnare un formato grafico diverso da bitmap,
icona o metafile di Windows alla proprietà Picture di un form o controllo.
Verificare che il file che si sta cercando di caricare nella proprietà
Picture sia un file grafico valido supportato da Visual Basic.
Eppure siamo sicuri: è un'icona!
Come dicevo nella premessa, anche io fino ad ora non avevo mai riscontrato questo problema, o meglio l'avevo incontrato ma pensavo che fosse dipeso da una immagine corrotta. Tra l'altro per le mie toolbar ho sempre preferito utilizzare icone con un massimo di 256 colori in quanto potevo utilizzare le stesse immagini anche per i menu!
Qualche giorno fa, Marc Emile della Axialis Software che produce programmi
grafici (Icon Workshop, AX Cursor,...) mi dice che molti suoi clienti, sviluppatori
VB) si lamentano perchè riscontrano questo problema e mi chiede se io
so come risolverlo.
Naturalmente casco dalle nuvole... Decido di fare qualche prova ed in effetti
scopro che è proprio così! Possibile che non me ne sia mai accorto?
A quanto pare... non sono l'unico! Quindi comincio a studiare il problema e
mi accorgo subito di una cosa strana: non sempre ricevevo il fantomatico errore.
Con alcune icone sì, con altre no. E mi domando: "Perchè?"
Ovviamente sapendo che un'icona può contenere diversi tipi di immagine con colori e dimensioni diverse, la prima cosa che mi viene in mente è quella di indagare in questo senso analizzando diversi files ICO (con Icon Workshop di Axialis) per scoprire quali differenze potevano esserci. Alla fine ho capito che si possono verificare i seguenti due casi:
Nel secondo caso, sembrerebbe quindi andare tutto bene. Purtroppo non è
così!
Infatti Visual Basic, quando carica una di queste icone, sceglie arbitrariamente
quale immagine visualizzare tra quelle contenute.
Morale, vi può accadere di veder visualizzata un'immagine diversa da
quella che vi aspettavate! Il risultato dipende da quali formati sono contenuti
nell'icona.
LA PROVA
Per dimostrarvi quanto appena detto vi mostro un'icona che ho volutamente modificato proprio per far comprendere inequivocabilmente il misfatto. Osserviamo l'icona modificata:
come potete vedere è composta da 9 immagini di cui le prime 3 raffigurano il punto interrogativo, mentre le altre 6 il punto esclamativo:
Figura 3
(Nell'icona originale le prime 3 immagini raffiguravano anch'esse il punto esclamativo; o le ho sostituite deliberatamente con il punto di domanda. )
Figura 4Tengo a precisare che l'icona in questione (wrong1.ico), se visualizzata in Explorer, mostra correttamente il punto interrogativo.
Qui a sinistra vedete la lista delle icone che ho allegato al progetto di esempio, tutte mostrano la stessa immagine.
Ma quando si caricano in Visual Basic l'immagine non è sempre quella desiderata.
Un esempio pratico
Supponiamo che vogliate caricare quest'icona in un PictureBox, dalla finestra
di dialogo Apri vedreste il punto interrogativo (come in figura 4). Selezioniamo
il file WRONG1.ICO, confermiamo con OK, ma una volta chiusa la finestra ci troviamo
una bella sorpresa... VB non ci mostra il punto interrogativo, ma quello esclamativo
e, per giunta, ha caricato l'immagine peggiore: l'ultima. Che tra l'altro è
monocromatica e quindi nemmeno trasparente!
Figura 5 - l'icona caricata
Non è sconcertante?
A questo punto sorge spontanea una semplice domanda: Come facciamo a caricare
sempre l'immagine che volgiamo noi (invece di quella che scieglie VB)?
Idea! Perchè non mettiamo l'icona che ci interessa in file di risorse
(RES) e la carichiamo da lì? Peccato purtroppo che anche in questo caso
VB si rifiuta di caricare icone a 32bit! (Più avanti spiegherò
anche come risolvere a questa limitazione)
SOLUZIONE DEL PROBLEMA
La sola soluzione possibile è quella di caricare le icone come risorsa, più semplice a dirsi che a farsi, però. Perchè qui non si parla di estrarre le icone nel metodo 'standard' (vi sono migliaia di progetti sulla rete che estraggono icone da EXE e DLL) ma in questo caso, scusate se lo ribadisco, si devono estrarre SOLO determinate immagini appartenenti ad un'icona, non l'icona completa!
In questo articolo non descriverò il codice sorgente perchè ci vorrebbe molto di più di un articolo! Lascio questo esercizio a chi desidera approfondire le proprie conoscenze sull'argomento. Naturalmente siete liberi di utilizzare il codice e le funzioni che trovate nel progetto a vostro piacere.
Qui mi limiterò solo a descrivere il funzionamento di questo progetto.
Dovrete scusarmi, ma avendolo preparato in inglese non ho pensato a tradurlo,
ma è talmente semplice che non credo vi siano difficoltà nel comprenderlo.
Figura 6 - Il progetto di esempio
Il progetto dimostra come caricare 'selettivamente' le immagini contenute nelle
icone contenute in file EXE o DLL, cioè solo le icone
che corrispondano ad una determinata dimensione e profondità di colore
(stabilita tramite le opzioni impostate nei gruppi Size e Color
depth).
Una volta acquisite le immagini richieste, le carica in un controllo ImageList
che a sua volta viene poi collegato ad una ToolBar ed ad un ImageCombo (in basso
a sinistra) per poter visualizzare le immagini.
La ToolBar visualizza solo alcune delle immagini caricate, mentre nell'ImageCombo
potrete vederle tutte, e per ognuna ne viene indicato il numero, lo spazio occupato
in bytes e le dimensioni.
Nell'esempio in figura 6 possiamo notare che la toolbar ha
caricato solo le icone a 32bit formato 48x48 contenute nel file Explorer.exe,
in base a quanto indicato appunto dai pulsanti di opzione nei due gruppi Size
e Color depth.
Nella barra di stato vediamo indicato che il numero delle immagini corrispondenti
a quanto richiesto è 9 (Explorer.exe ne contiene invece 113 in totale).
Selezionando la casella All Size and Formats, quando premete
il pulsante Load Icons verranno caricate tutte le risorse icone
contenute nel file selezionato dalla lista. Ecco allora che la listbox Other
formats (if any) tornerà utile perchè nel file, logicamente,
vi possono essere anche altre immagini di formato diverso (parliamo sempre di
icone).
Osserviamo la figura 7:
Figura 7 - Tutte le icone di Explorer.exe
In questo caso abbiamo caricato tutte le icone di Explorer.exe (113 immagini) e vedete che a destra la ListBox elenca 3 icone che non rientrano in nessuno dei formati diciamo così 'predefiniti'. Infatti sono icone monocromatiche, di cui la prima la potete vedere nell'ImageCombo a sinistra.
Noterete che alcune icone visualizzate sulla ToolBar risultano distorte; questo perchè, come ben sapete, la ToolBar e l'ImageList possono visualizzare immagini in un solo formato quindi tutte le altre vengono 'adattate'.
COME CREARE LIBRERIE DI ICONE A 32BIT
Ora che abbiamo visto come estrarre le immagini dalle icone dei files EXE/DLL e visualizzare nei nostri controlli, non resta che trovare il modo di creare le nostre librerie.
Anche se la cosa è fattibile, nel progetto non ho intenzionalmente affrontato la questione di caricare le icone da files ICO per due motivi:
Infatti sarebbe assai più comodo riunire tutte le icone che volgiamo
utilizzare in una libreria, e caricarle a run-time. La creazione di una libreria
(DLL) di icone tramite il Visual Basic è normalmente un'operazione alquanto
banale.
Purtroppo, come ho già detto, questo non vale per le icone a 32bit (con
canale Alpha) che il Resource Editor rifiuta categoricamente, al pari degli
altri controlli grafici.
Come fare, allora?
Come ben sanno i programmatori di lunga data, esiste un programma che si chiama Resource Compiler (RC.EXE) che viene tutt'ora distribuito con il Visual Basic. Per quelli che hanno il Visual Studio lo possono trovare nella cartella:
C:\Programmi\Microsoft Visual Studio\VB98\Wizards\
oppure
C:\Programmi\Microsoft Visual Studio\Common\MSDev98\Bin
Nota storica: il Resource Compiler, ai tempi del VB3 era l'unico programma con cui i programmatori VB potevano creare i files di risorse (RES) anche se poi da lì a creare una libreria DLL la cosa non era così semplice per loro.
Per creare la nostra libreria procediamo in questo modo:
Ecco fatto, avete creato la vostra libreria di icone!
Nel progetto di esempio ho allegato anche 4 librerie di icone create proprio in questo modo, che contengono esclusivamente icone a 32bit con canale Alpha:
Come vedete le prime tre contengono solo immagini della stessa dimensione,
mentre l'ultima contiene formati misti. Voi potete creare librerie con le immagini
in base alle vostre esigenze: se ad esempio volete fornire all'utente di poter
cambiare la dimensione dei pulsanti della toolbar (come avviene in Esplora risorse)
da 16 a 24, potete includere nella libreria entrambi i formati e poi caricare
a run-time quello richiesto dall'utente.
Tra l'altro, il fatto di includere solo le immagini che utilizzate vi permette
di risparmiare spazio inutile (e memoria): perchè caricare 12 formati
quando ne uso solamente 2?
Nel progetto di esempio potete fare questa prova: selezionate il file XP_icons_16.dll dalla lista, e poi impostate Size a 16 e Color Depth a 16. Premete Load Icons e vedrete che non viene caricata alcuna icona. Perchè? Perchè le librerie contengono SOLO immagini a 32bit. Se impostate Size su 16 e Color Depth su Win XP le immagini verranno caricate regolarmente.
Suggerimento sul Resource Compiler
Se qualcuno si trova in difficoltà nella compilazione con RC.EXE (perchè non sa come aprire una sessione DOS, o perchè digitare da DOS tutti i percorsi completi potrebbe essere noioso) io uso questo sistema:
Copio i due files RC.EXE e RCDLL.DLL nella cartella che contiene le icone ed il file MYICONS.RC, poi direttamente da Esplora risorse trascino il file MYICONS.RC sul file RC.EXE.
In un attimo ottengo il file RES.
Per chiudere, una nota interessante
Nel progetto ho utilizzato i controlli Windows Common Controls 6.0 (SP6) ma potete utilizzare tranquillamente anche quelli della versione 5.0 (SP2) che ad esempio visualizza la toolbar nello stile di XP. Inoltre il codice di questo progetto utilizzato con la versione 5.0, vi permette di visualizzare correttamente nella toolbar anche le icone a 256 colori, che invece risultano veramente brutte.
CONCLUSIONE
Sicuramente gli amanti della grafica apprezzeranno molto il codice sorgente utilizzato in questo progetto.
Spero anche che questo articolo possa contribuire ad aiutarvi nella creazione di interfaccie grafiche sempre più accattivanti. Anche perchè (non bisogna mai dimenticarlo) anche l'occhio vuole la sua parte!
Naturalmente il progetto è stato realizzato a scopo puramente didattico,
lungi dall'essere perfetto.
Se qualcuno apporterà dei miglioramenti sarei felice di esserne informato.
Giorgio Brausi