Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Questo articolo descrive che cos'è una libreria di collegamento dinamico (DLL) e quali sono
i problemi che possono verificarsi quando si utilizzano le DLL. Descrive anche alcuni
problemi più complessi da tenere in considerazione quando si sviluppano le DLL.
Si applica a: Windows 10 - tutte le edizioni
Numero originale della Knowledge Base: 815065
Riepilogo
Ulteriori informazioni
Una DLL è una libreria che contiene codice e dati utilizzabili da più di un programma
contemporaneamente. Ad esempio, nei sistemi operativi Windows, la DLL Comdlg32
esegue funzioni comuni correlate alle finestre di dialogo. Ogni programma può utilizzare le
funzionalità contenute in questa DLL per implementare una finestra di dialogo Apri.
Questo favorisce il riutilizzo del codice e l'utilizzo efficiente della memoria.
Utilizzando una DLL, un programma può essere modularizzato in componenti distinti. Un
programma di contabilità può ad esempio essere venduto in diversi moduli. Ogni modulo
può essere caricato nel programma principale in fase di esecuzione, se il modulo è
installato. Poiché i moduli sono separati, il tempo di caricamento del programma è più
veloce. E un modulo viene caricato solo quando tale funzionalità viene richiesta.
Gli aggiornamenti possono inoltre essere applicati in modo più semplice a ogni modulo
senza influire sulle altre parti del programma. Ad esempio, si potrebbe avere un
programma per le retribuzioni in cui le aliquote fiscali cambiano ogni anno. Quando queste
modifiche vengono isolate in una DLL, è possibile applicare un aggiornamento senza che
sia necessario compilare o installare di nuovo l'intero programma.
Nell'elenco seguente sono descritti alcuni dei file implementati come DLL nei sistemi
operativi Windows:
•File di controlli ActiveX (con estensione ocx)
Un esempio di controllo ActiveX è un controllo calendario che consente di
selezionare una data dal calendario.
•File del Pannello di controllo (con estensione cpl)
Un esempio di file con estensione cpl è un elemento disponibile nel Pannello di
controllo. Ogni elemento è una DLL specializzata.
•File di driver di dispositivo (con estensione drv)
Un esempio di driver di dispositivo è un driver di stampante che controlla la stampa
su una stampante.
Nell'elenco seguente sono descritti alcuni dei vantaggi offerti dall'utilizzo di una DLL in un
programma:
•Riduzione dell'utilizzo delle risorse
Quando più programmi utilizzano la stessa libreria di funzioni, una DLL può ridurre la
duplicazione del codice caricato sul disco e nella memoria fisica. Questo può influire
notevolmente sulle prestazioni non solo del programma eseguito in primo piano, ma
anche di altri programmi in esecuzione nel sistema operativo Windows.
•Promozione dell'architettura modulare
Una DLL promuove lo sviluppo di programmi modulari. In questo modo, è possibile
creare programmi di grandi dimensioni che richiedono versioni in più lingue oppure
un programma che richiede un'architettura modulare. Un esempio di programma
modulare è un programma di contabilità che dispone di molti moduli che possono
essere caricati in modo dinamico in fase di esecuzione.
•Semplicità di distribuzione e installazione
Quando una funzione all'interno di una DLL richiede un aggiornamento o una
correzione, per la distribuzione e l'installazione della DLL non è necessario ricollegare
il programma alla DLL. Inoltre, se più programmi utilizzano la stessa DLL, tutti i
programmi trarranno vantaggio dall'aggiornamento o dalla correzione. Questo
problema può verificarsi più di frequente quando si utilizza una DLL di terze parti che
viene aggiornata o corretta regolarmente.
Quando un programma o una DLL utilizza una funzione DLL in un'altra DLL, viene creata
una dipendenza. Di conseguenza, il programma non è più indipendente e potrebbero
verificarsi problemi se la dipendenza si interrompe. Potrebbe ad esempio risultare
impossibile eseguire il programma in seguito a una delle azioni seguenti:
•Una DLL dipendente viene aggiornata a una nuova versione.
•Una DLL dipendente viene corretta.
•Una DLL dipendente viene sovrascritta con una versione precedente.
•Una DLL dipendente viene rimossa dal computer.
Queste azioni sono in genere definite conflitti di DLL. Se non si garantisce la compatibilità
con le versioni precedenti, il programma potrebbe non essere eseguito correttamente.
Di seguito sono elencate le modifiche che sono state introdotte in Windows 2000 e nelle
versioni successive dei sistemi operativi Windows per ridurre al minimo i problemi di
dipendenza:
•Protezione file Windows
Con Protezione file Windows, il sistema operativo impedisce che le DLL di sistema
vengano aggiornate o eliminate da un agente non autorizzato. Quando l'installazione
di un programma tenta di rimuovere o aggiornare una DLL definita come DLL di
sistema, Protezione file Windows richiederà una firma digitale valida.
•DLL private
Le DLL private consentono di isolare un programma dalle modifiche apportate alle
DLL condivise. Le DLL private utilizzano informazioni specifiche della versione o un
file con estensione .local vuoto per applicare la versione della DLL che viene
utilizzata dal programma. Per utilizzare DLL private, individuare le DLL nella cartella
radice del programma. Per i nuovi programmi, aggiungere informazioni specifiche
della versione alla DLL. Per i vecchi programmi, utilizzare un file con
estensione .local vuoto. Ognuno di questi metodi indica al sistema operativo di
utilizzare le DLL private disponibili nella cartella radice del programma.
Dependency Walker
Lo strumento Dependency Walker analizza in modo ricorsivo tutte le DLL dipendenti che
sono utilizzate da un programma. Quando si apre un programma in Dependency Walker,
questo effettua i controlli seguenti:
•Controlla le DLL mancanti.
•Controlla i file di programma o le DLL non validi.
•Controlla la corrispondenza tra le funzioni di importazione ed esportazione.
•Controlla gli errori di dipendenza circolare.
•Controlla i moduli non validi perché destinati a un diverso sistema operativo.
Utilizzando Dependency Walker, è possibile documentare tutte le DLL utilizzate da un
programma. Ciò consente di prevenire e correggere i problemi delle DLL che possono
verificarsi in futuro. Dopo avere installato Microsoft Visual Studio 6.0, Dependency Walker è
disponibile nella seguente directory:
drive\Program Files\Microsoft Visual Studio\Common\Tools
Lo strumento DLL Universal Problem Solver (DUPS) viene utilizzato per controllare,
confrontare, documentare e visualizzare le informazioni sulle DLL. Di seguito sono elencate
le utilità che costituiscono lo strumento DUPS:
•Dlister.exe
Questa utilità enumera tutte le DLL nel computer e registra le informazioni in un file
di testo o in un file di database.
•Dcomp.exe
Questa utilità confronta le DLL elencate in due file di testo e produce un terzo file di
testo che contiene le differenze.
•Dtxt2DB.exe
Questa utilità carica i file di testo creati tramite le utilità Dlister.exe e Dcomp.exe nel
database dllHell.
•DlgDtxt2DB.exe
Questa utilità fornisce una versione con interfaccia grafica dell'utilità Dtxt2DB.exe.
Il database DLL Help consente di individuare le versioni specifiche delle DLL installate dai
prodotti software Microsoft.
Sviluppo di DLL
Tipi di DLL
Quando si crea una DLL, è possibile specificare una funzione del punto di ingresso. La
funzione del punto di ingresso viene chiamata quando processi o thread si collegano alla
DLL o si scollegano dalla DLL. È possibile utilizzare la funzione del punto di ingresso per
inizializzare strutture di dati o eliminare definitivamente strutture di dati come richiesto
dalla DLL. Inoltre, se l'applicazione è multithread, è possibile utilizzare l'archiviazione locale
dei thread per allocare memoria privata a ciascun thread nella funzione del punto di
ingresso. Il codice riportato di seguito è un esempio di funzione del punto di ingresso DLL.
C++Copia
BOOL APIENTRY DllMain(
HANDLE hModule,// Handle to DLL module
DWORD ul_reason_for_call,// Reason for calling function
LPVOID lpReserved ) // Reserved
{
switch ( ul_reason_for_call )
{
case DLL_PROCESS_ATTACHED: // A process is loading the DLL.
break;
case DLL_THREAD_ATTACHED: // A process is creating a new thread.
break;
case DLL_THREAD_DETACH: // A thread exits normally.
break;
case DLL_PROCESS_DETACH: // A process unloads the DLL.
break;
}
return TRUE;
}
Quando la funzione del punto di ingresso restituisce il valore FALSE, se si utilizza il
collegamento dinamico in fase di caricamento, l'applicazione non verrà avviata. Se si
utilizza il collegamento dinamico in fase di esecuzione, non verrà caricata solo la singola
DLL.
La funzione del punto di ingresso deve eseguire solo semplici attività di inizializzazione e
non deve chiamare altre funzioni di caricamento o di terminazione di DLL. Nella funzione
del punto di ingresso, ad esempio, non è possibile chiamare direttamente o indirettamente
la funzione LoadLibrary o la funzione LoadLibraryEx. Inoltre, non è necessario chiamare la
funzione FreeLibrary quando il processo è terminato.
Nota
Nelle applicazioni multithread assicurarsi che l'accesso ai dati globali della DLL sia
sincronizzato (thread-safe) per evitare il possibile danneggiamento dei dati. A tale scopo,
utilizzare l'archiviazione locale dei thread per fornire dati univoci per ciascun thread.
Per esportare le funzioni DLL, è possibile aggiungere una parola chiave function alle
funzioni DLL esportate o creare un file di definizione di modulo (con estensione def) in cui
sono elencate le funzioni DLL esportate.
Per utilizzare una parola chiave function, è necessario dichiarare ogni funzione che si
desidera esportare con la parola chiave seguente:
__declspec(dllexport)
Per usare le funzioni DLL esportate nell'applicazione, è necessario dichiarare ogni funzione
da importare con la parola chiave seguente: __declspec(dllimport)
In genere si utilizza un file di intestazione con un'istruzione define e un'istruzione ifdef per
separare l'istruzione export e l'istruzione import.
È anche possibile utilizzare un file di definizione di modulo per dichiarare le funzioni DLL
esportate. Quando si utilizza un file di definizione di modulo, non è necessario aggiungere
la parola chiave function alle funzioni DLL esportate. Nel file di definizione del modulo
vengono dichiarate l'istruzione LIBRARY e l'istruzione EXPORTS per la DLL. Il codice riportato
di seguito è un esempio di file di definizione.
C++Copia
// SampleDLL.def
//
LIBRARY "sampleDLL"
EXPORTS HelloWorld
In Microsoft Visual C++ 6.0 è possibile creare una DLL selezionando il tipo di
progetto Win32 Dynamic-Link Library o il tipo di progetto MFC AppWizard (dll).
Il codice riportato di seguito è un esempio di DLL creata in Visual C++ utilizzando il tipo di
progetto Win32 Dynamic-Link Library.
C++Copia
// SampleDLL.cpp
//
#include "stdafx.h"
#define EXPORTING_DLL
#include "sampleDLL.h"
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved
)
{
return TRUE;
}
void HelloWorld()
{
MessageBox( NULL, TEXT("Hello World"), TEXT("In a DLL"), MB_OK);
}
// File: SampleDLL.h
//
#ifndef INDLL_H
#define INDLL_H
#ifdef EXPORTING_DLL
extern __declspec(dllexport) void HelloWorld();
#else
extern __declspec(dllimport) void HelloWorld();
#endif
#endif
Il codice riportato di seguito è un esempio di progetto Win32 Application che chiama la
funzione DLL esportata nella DLL SampleDLL.
C++Copia
// SampleApp.cpp
//
#include "stdafx.h"
#include "sampleDLL.h"
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int
nCmdShow)
{
HelloWorld();
return 0;
}
Nota
Nel collegamento dinamico in fase di caricamento è necessario collegare la libreria di
importazione SampleDLL.lib che viene creata quando si compila il progetto SampleDLL.
Nel collegamento dinamico in fase di esecuzione utilizzare codice simile al seguente per
chiamare la funzione DLL esportata SampleDLL.dll.
C++Copia
...
typedef VOID (*DLLPROC) (LPTSTR);
...
HINSTANCE hinstDLL;
DLLPROC HelloWorld;
BOOL fFreeDLL;
hinstDLL = LoadLibrary("sampleDLL.dll");
if (hinstDLL != NULL)
{
HelloWorld = (DLLPROC) GetProcAddress(hinstDLL, "HelloWorld");
if (HelloWorld != NULL)
(HelloWorld);
fFreeDLL = FreeLibrary(hinstDLL);
}
...
Quando si compila e si collega l'applicazione SampleDLL, il sistema operativo Windows
cerca la DLL SampleDLL nei percorsi seguenti nell'ordine indicato:
1.La cartella dell'applicazione
2.La cartella corrente
3.La cartella di sistema di Windows
Nota
La funzione GetSystemDirectory restituisce il percorso della cartella di sistema di
Windows.
4.La cartella di Windows
Nota
La funzione GetWindowsDirectory restituisce il percorso della cartella di Windows.
Assembly di .NET Framework
Con l'introduzione di Microsoft .NET e .NET Framework, la maggior parte dei problemi
associati alle DLL è stata eliminata utilizzando gli assembly. Un assembly è un'unità logica
di funzionalità che viene eseguita sotto il controllo di .NET Common Language Runtime
(CLR). Un assembly si presenta fisicamente come un file con estensione dll o exe. Tuttavia,
internamente un assembly è diverso da una DLL Microsoft Win32.
Un file di assembly contiene un manifesto dell'assembly, metadati di tipo, codice Microsoft
Intermediate Language (MSIL) e altre risorse. Il manifesto dell'assembly contiene i metadati
dell'assembly che forniscono tutte le informazioni necessarie perché un assembly sia
autodescrittivo. Le informazioni seguenti sono incluse nel manifesto dell'assembly:
•Nome dell'assembly
•Informazioni sulla versione
•Informazioni sulle impostazioni cultura
•Informazioni sul nome sicuro
•Elenco dei file dell'assembly
•Informazioni sul tipo di riferimento
•Informazioni sugli assembly a cui viene fatto riferimento e dipendenti
Il codice MSIL contenuto nell'assembly non può essere eseguito direttamente. L'esecuzione
del codice MSIL viene invece gestita tramite CLR. Per impostazione predefinita, quando si
crea un assembly, l'assembly è privato per l'applicazione. Per creare un assembly condiviso,
è necessario assegnare un nome sicuro all'assembly e quindi pubblicare l'assembly nella
Global Assembly Cache.
Di seguito sono descritte alcune delle caratteristiche degli assembly, confrontandole con
quelle delle DLL Win32:
•Natura autodescrittiva
Quando si crea un assembly, tutte le informazioni necessarie a CLR per eseguire
l'assembly sono contenute nel manifesto dell'assembly. Il manifesto dell'assembly
contiene un elenco degli assembly dipendenti. CLR può pertanto gestire un set
coerente degli assembly utilizzati nell'applicazione. Nelle DLL Win32 non è possibile
mantenere la coerenza tra un set di DLL che vengono utilizzate in un'applicazione
quando si utilizzano DLL condivise.
•Controllo delle versioni
Nel manifesto di un assembly le informazioni sulla versione vengono registrate e
applicate da CLR. I criteri di versione, inoltre, consentono di imporre l'utilizzo di
specifiche versioni. Nelle DLL Win32 il controllo delle versioni non può essere
applicato dal sistema operativo. È necessario assicurarsi che le DLL siano compatibili
con le versioni precedenti.
•Distribuzione side-by-side
Gli assembly supportano la distribuzione side-by-side. Un'applicazione può utilizzare
una versione di un assembly, mentre un'altra applicazione può utilizzare una versione
diversa di un assembly. A partire da Windows 2000, la distribuzione side-by-side è
supportata individuando le DLL nella cartella dell'applicazione. Protezione file
Windows, inoltre, impedisce che le DLL di sistema vengano sovrascritte o sostituite da
un agente non autorizzato.
•Indipendenza e isolamento
Un'applicazione sviluppata tramite un assembly può essere indipendente e isolata
dalle altre applicazioni in esecuzione nel computer Questa funzionalità consente di
creare installazioni a impatto zero.
•Esecuzione
Un assembly viene eseguito con le autorizzazioni di sicurezza che vengono fornite nel
manifesto dell'assembly e che sono controllate da CLR.
•Indipendenza dal linguaggio
Un assembly può essere sviluppato utilizzando uno qualsiasi dei linguaggi .NET
supportati. È ad esempio possibile sviluppare un assembly in Microsoft Visual C# e
quindi utilizzare l'assembly in un progetto Visual Basic .NET