Come utilizzare le icone a 32bit di Windows XP
a cura di Giorgio Brausi (requisiti: normale conoscenza di VB e delle procedure di compilazione)

Premessa
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ù accattivante anche dal punto di vista grafico.
Purtroppo per noi programmatori VB accade che ci troviamo con un problema di incompatibilità tra il Visual Basic 6 (e pure VB.Net, vedi articolo 316652 della KB) e le icone a 32 bit con canale Alpha (quelle di Windows XP, per capirci, vedi nota).
In questo articolo mi propongo di proporre una soluzione.

Il problema
Ogni volta che si tenta di caricare un'icona a 32bit da Visual Basic in qualsiasi controllo grafico (Form, PictureBox, Image, ecc.), Visual Basic risponde con un bel messaggio (si fa per dire), e se si consulta l'help si trova questa descrizione:

Immagine non valida (Errore 481)

È 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!

L'antefatto
Fino a qualche giorno fa, pur avendo incontrato questo problema, non credevo fosse un problema di incompatibilità, ma ritenevo che questo errore fosse provocato da un'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... A quanto pare... non sono l'unico!
Decido di fare qualche prova ed in effetti scopro che è proprio così! Possibile che non me ne sia mai accorto?

L'analisi
Quindi comincio a studiare il problema e mi accorgo subito di una cosa strana: non sempre ricevo il fatidico 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:

  1. l'icona contiene solo immagini a 32bit (canale Alpha - XP): si incorre nell'errore 481
  2. l'icona contiene immagini in vari formati (oltre a quelle a 32bit): non si incorre nell'errore 481

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, può accadere di veder visualizzata un'immagine diversa da quella che ci si aspetta! Il risultato dipende da quali formati sono contenuti nell'icona.

La prova
Per dimostrarvi quanto appena detto vi presento un'icona che ho deliberatamente modificato proprio per far comprendere inequivocabilmente il misfatto. Osserviamo l'icona modificata:

come potete vedere è composta da nove immagini di cui le prime tre raffigurano il punto interrogativo, mentre le altre la i minuscola (come originalmente accadeva per le prime tre). Le immagini hanno non solo diverse dimensioni, ma anche diverse profondità di colore:

  • le prime 3 sono a 32bit (Win XP con canale Alpha)
  • le successive 3 sono a 16bit (256 colori)
  • le successive 2 sono a 4bit (16 colori)
  • l'ultima è monocromatica

Tengo a precisare che l'icona in questione (wrong1.ico), se visualizzata in Explorer, mostra correttamente il punto interrogativo.
Qui a destra 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 di voler caricare quest'icona in una PictureBox, dalla finestra di dialogo Apri si vedrebbe il punto interrogativo (come in Explorer, appunto). Si seleziona il file wrong1.ico e si conferma con OK, ma una volta chiusa la finestra ci troviamo una bella sorpresa:
VB non ci mostra il punto interrogativo, ma la i minuscola e, per giunta, ha caricato l'immagine peggiore: l'ultima.
Che tra l'altro è monocromatica e quindi nemmeno trasparente!
Non è sconcertante?

A questo punto sorge spontanea una semplice domanda: Come facciamo a caricare sempre l'immagine che vogliamo noi (invece di quella che sceglie VB)?

Idea!
Perchè non mettere l'icona che ci interessa in file di risorse (.res) e la carichiamo da lì? Peccato purtroppo che, anche in questo caso, VB si rifiuti di caricare icone a 32bit! (Nel seguito spiegherò anche come ovviare a questa limitazione)

Soluzione del problema
La sola soluzione possibile sembra quella di caricare le icone come risorsa, più semplice a dirsi che a farsi, però. Perchè qui non si tratta di estrarre le icone seguendo il metodo 'standard' (vi sono migliaia di progetti sulla rete che estraggono icone da .exe e .dll), bensì, scusate se lo ribadisco, di 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. D'altra parte è talmente semplice che non credo vi siano difficoltà nel comprenderlo.

Il progetto di esempio


Il progetto dimostra come caricare 'selettivamente' le immagini contenute nelle icone presenti 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 una 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.
Nella figura precedente 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).
Spuntando 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).
Come nella figura seguente:

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 potete vedere la prima nell'ImageCombo a sinistra.
Noterete che alcune icone visualizzate sulla ToolBar si presentano distorte; questo perché, come ben sapete, la ToolBar e l'ImageList possono visualizzare immagini in un solo formato e 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 visualizzarle 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, sia perché mi sembra abbastanza banale, sia perché non è assolutamente pratica: infatti sarebbe assai più comodo riunire in una libreria tutte le icone che vogliamo utilizzare, 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 tuttora distribuito con il Visual Basic. Per chi ha Visual Studio si trova nella cartella

C:\Programmi\Microsoft Visual Studio\VB98\Wizards\
oppure nella cartella
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 crearsi i files di risorse (.res) anche se poi non era proprio semplice riuscire da lì a creare una libreria dll.

Per creare la nostra libreria procediamo in questo modo:

  1. Create un file di script (con il Blocco Note o altro Text Editor) in cui elencate le risorse icona, in questo modo:
    ///////////////////////////////////////////////
    //
    // Icons
    //
    ///////////////////////////////////////////////
    101 ICON MOVEABLE PURE "cd rom drive.ico"
    102 ICON MOVEABLE PURE "control panel.ico"
    103 ICON MOVEABLE PURE "default document.ico"
    104 ICON MOVEABLE PURE "entire system.ico"
    105 ICON MOVEABLE PURE "favorites.ico"
    106 ICON MOVEABLE PURE "floppy drive.ico"
    ecc.
  2. Salvate il file con estensione .rc (ad esempio myicons.rc)
    (naturalmente il file .rc va creato nella stessa cartella in cui risiedono le icone!)
  3. Quindi compilatelo con il Resource Compiler, tramite il comando al Prompt del DOS:

    rc myicons.rc

    (più avanti vi sarà un suggerimento su questa operazione)
    e otterrete così il file di risorse myicon.res.
  4. Ora avviate Visual Basic e create un nuovo progetto ActiveX/DLL
    Vi troverete un progetto con una sola classe (Class1)
  5. Aggiungete al progetto il vostro file di risorse myicon.res
    Consiglio di non modificarlo o aprirlo con il Resource Editor!
  6. Date un nome al progetto (ad esempio MyIcons)
  7. E compilatelo (File>Crea MyIcons.dll...)

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:

  1. XP_icons_16.dll (icone 16x16 a 32bit)
  2. XP_icons_24.dll (icone 24x24 a 32bit)
  3. XP_icons_48.dll (icone 48x48 a 32bit)
  4. XP_icons_all.dll (icone 16x16, 32x32, 48x48 a 32bit)

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 la possibilità di cambiare la dimensione dei pulsanti della barra strumenti (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), suggerisco il mio sistema:

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, anche se risultano davvero brutte.

Canale Alpha
Per chi ancora non lo sapesse, Il canale Alpha è quello che regola il livello di trasparenza nelle icone di Windows XP, famose proprio per questa caratteristica.
Per chiarire ulteriormente il concetto sul canale Alpha (semmai ce ne fosse ulteriore necessità) questo funziona come il colore 'trasparente' nelle normali icone, solo che quest'ultimo non è modificabile: il pixel può essere o colorato o trasparente (quindi si vede lo sfondo sotto l'icona). Invece nel canale Alpha è possibile regolare sino a 256 livelli di trasparenza.

Per creare icone con il canale Alpha occorrono appositi editor come ad esempio MicroAngelo Studio (www.microangelo.us) e Axialis IconWorkshop (www.axialis.com).

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 interfacce grafiche sempre più accattivanti. Anche perché (non bisogna mai dimenticarlo) anche l'occhio vuole la sua parte!
Naturalmente il progetto, scaricabile dall'Area Download, è stato realizzato a scopo puramente didattico, lungi dall'essere perfetto.
Se qualcuno apporterà dei miglioramenti sarei felice di esserne informato.

In merito a questo articolo, potete scrivere all'autore, del quale potete anche consultare una breve presentazione.