BETA La rivista ipertestuale tecnica
BETA
BETA La rivista ipertestuale tecnicaBarra BETA
Barra Sito Beta.it

BETA 2299.5 - Programmazione: Costruiamo un'estensione della shell per Windows95  -  Indici | Guida

Clicca qui!

Costruiamo un'estensione della shell per Windows95

    Finalmente è giunta l’ora di mettere in atto la teoria spiegata negli articoli precedenti: costruiamoci una shell extension che ci dica, direttamente nel menu contestuale, le dimensioni ed il numero di colori di un’immagine bitmap senza bisogno di aprire il file con un programma di disegno. Diamo anche un’occhiata al formato dei file .INF, che permettono di installare programmi e DLL senza scrivere una riga di codice.

di Stefano Casini
Articolista, BETA

[Inizio articolo]Introduzione

    Abbiamo visto cos’è il namespace di Explorer [1], cosa sono i piddle, le regole basilari di COM [2], quali sono le interfacce con cui interagire per personalizzare la shell. Adesso dobbiamo scrivere il codice che sintetizzi tutto questo, testarlo e procedere all’installazione sul nostro computer dell’estensione che costruiremo. Alla fine dell’articolo viene riportato il codice sorgente della shell extension; a parte viene fornita, sotto forma di file zippato, la DLL compilata ed il file .INF necessario per installarla (FILEINFO.ZIP).

[Inizio articolo]Tre importanti funzioni

    Per costruire una DLL in Windows a 32 bit, dobbiamo implementare il suo entry point ed il suo exit point.
Contrariamente a Windows 16 bit, dove esistevano due diverse funzioni, LibMain e WEP, in Win32 viene utilizzata un’unica funzione:

int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved);
HINSTANCE hInstance
 è l’handle all’istanza della DLL, fornito dal sistema;
DWORD dwReason
è un flag per sapere il motivo per cui la funzione DllMain è stata chiamata, e può assumere i seguenti valori:
DLL_PROCESS_ATTACH, se la DLL è stata chiamata da un nuovo processo;
DLL_THREAD_ATTACH, se è stata chiamata da un thread che è generato da un processo che ha già chiamato la DLL (per un processo che genera più thread, questo flag viene utilizzato solo dal secondo thread in poi che chiama la DLL, il primo thread usa il flag precedente);
DLL_THREAD_DETACH, se un thread sta scaricando la DLL;
DLL_PROCESS_DETACH, se il thread che sta scaricando la DLL è l’ultimo rimasto del processo che ha chiamato la DLL, o se il processo che non ha generato thread sta terminando;
LPVOID lpReserved
è un valore riservato dal sistema.
La funzione ritorna TRUE se si vuole far caricare la DLL nello spazio di indirizzamento del processo chiamante, FALSE se si vuole avvisare il sistema che il caricamento è impossibile, magari a causa di qualche inizializzazione fallita; il valore di ritorno viene testato dal sistema solo se il flag dwReason ha valore DLL_PROCESS_ATTACH.
Nel nostro caso, non avendo bisogno di eseguire particolari inizializzazioni, il contenuto della funzione DllMain è molto banale: settiamo il valore della variabile globale g_hmodThisDll (l’istanza della nostra DLL).

Per sapere se la DLL è in uso o meno, OLE chiama ad intervalli di tempo prestabiliti da Windows la funzione

STDAPI DllCanUnloadNow(void);
con il valore di ritorno che può essere S_OK o S_FALSE.

Dovremo necessariamente implementarla nella nostra DLL; sarà compito della funzione, che controlla un contatore interno di riferimento mantenuto dalla DLL (g_cRefThisDll), controllare se ci sono attualmente oggetti in uso gestiti dalla DLL; qualora ve ne fossero, risponderà al sistema con il valore S_FALSE. Se non ci sono oggetti della DLL in giro (g_cRefThisDll è uguale a zero), risponderà S_OK, ed OLE potrà liberare la memoria usata dalla DLL; naturalmente occorre prestare attenzione ad incrementare il contatore ogni volta che si crea un oggetto, ed a decrementarlo ogni volta che un oggetto viene distrutto.
Ogni quanto tempo OLE chiama la funzione per vedere se è possibile scaricare la DLL? Se è presente nel registro la chiave:

HKEY_LOCAL_MACHINE\SOFTWARE\MICROSOFT\WINDOWS\CurrentVersion\Explorer\AlwaysUnloadDll
l’intervallo di tempo è circa 15 secondi; se questa chiave non è presente, l’intervallo di tempo è molto più lungo (oltre mezz’ora).
Infine, c’è una funzione che permette ad Explorer, che ci sta chiamando dopo aver letto nel registro che ad un certo tipo di file è collegata la nostra DLL, di farci creare un oggetto di quelli che noi “produciamo”, e di recuperarne l’interfaccia per comunicare con l’oggetto.
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID * ppvOut);
REFCLSID rclsid
è il GUID della classe di oggetti che Explorer ricava dal registro, e che ci chiede di creare;
REFIID riid
identifica l’interfaccia richiesta da Explorer per comunicare con l’oggetto (ricordiamo che un oggetto può esporre più di un’interfaccia;
LPVOID * ppvOut
è il puntatore all’interfaccia che la nostra DLL restituisce dopo aver creato l’oggetto.
Se tutto va bene, ovvero l’oggetto richiesto fa parte di quelli della nostra DLL, e possiede anche l’interfaccia giusta, la funzione ritorna S_OK, altrimenti ritorna un valore di errore.

Collegamento d'articolo
Parte 1 | Parte 2 | Parte 3

Parte 2

Copyright © 1999 Stefano Casini, tutti i diritti sono riservati. Questo Articolo di BETA, insieme alla Rivista, è distribuito secondo i termini e le condizioni della Licenza Pubblica Beta, come specificato nel file LPB.

BETAe-mail info@beta.it
Barra Sito Beta.it
Frontespizio Abbonamenti a BETA Redazione Liste/Forum Informazioni Mirror ufficiali Beta Home Page Beta Home Page english Beta News BETA Rivista Articoli BETA Beta Edit, pubblicazioni Beta Logo, premi Beta Lpb, Licenza Pubblica e Articoli Lpb Beta Navigatore Beta Online Beta Library Beta Info Gruppo Beta BETA La rivista ipertestuale tecnica Collegamento al sito Web