Sei sulla pagina 1di 10

Che cos'è una DLL

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

Durante la descrizione delle DLL, vengono illustrati i metodi di collegamento dinamico, le


dipendenze delle DLL, i punti di ingresso delle DLL, le funzioni DLL di esportazione e gli
strumenti per la risoluzione dei problemi delle DLL.
L'articolo si conclude con un confronto di carattere generale tra le DLL e gli assembly di
Microsoft .NET Framework.
Per Windows, gran parte delle funzionalità del sistema operativo è fornita dalla DLL.
Inoltre, quando si esegue un programma in uno di questi sistemi operativi Windows, molte
delle funzionalità del programma possono essere fornite tramite DLL.
Alcuni programmi possono ad esempio contenere numerosi moduli diversi e ogni modulo
del programma è contenuto e distribuito in DLL.
L'utilizzo delle DLL favorisce la modularizzazione del codice, il riutilizzo del codice, l'utilizzo
efficiente della memoria e la riduzione dello spazio su disco. Quindi, il sistema operativo e i
programmi vengono caricati ed eseguiti più velocemente e richiedono meno spazio su
disco nel computer.
Quando un programma utilizza una DLL, un problema denominato dipendenza può
impedire l'esecuzione del programma. Quando un programma utilizza una DLL, viene
creata una dipendenza. Se un altro programma sovrascrive e interrompe questa
dipendenza, potrebbe risultare impossibile eseguire il programma originale.
Con l'introduzione di Microsoft .NET Framework, la maggior parte dei problemi di
dipendenza sono stati eliminati grazie all'utilizzo degli assembly.

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.

Vantaggi delle DLL

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.

Dipendenze delle DLL

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.

Strumenti di risoluzione dei problemi delle DLL


Sono disponibili diversi strumenti per la risoluzione dei problemi delle DLL. Alcuni di questi
strumenti sono descritti di seguito.

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

DLL Universal Problem Solver

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.

Database DLL Help

Il database DLL Help consente di individuare le versioni specifiche delle DLL installate dai
prodotti software Microsoft.

Sviluppo di DLL

In questa sezione vengono descritti i problemi e i requisiti da tenere presente durante lo


sviluppo di DLL.

Tipi di DLL

Quando si carica una DLL in un'applicazione, due metodi di collegamento consentono di


chiamare le funzioni DLL esportate. I due metodi di collegamento sono il collegamento
dinamico in fase di caricamento e il collegamento dinamico in fase di esecuzione.

Collegamento dinamico in fase di caricamento


Nel collegamento dinamico in fase di caricamento, un'applicazione effettua chiamate
esplicite alle funzioni DLL esportate come funzioni locali. Per utilizzare il collegamento
dinamico in fase di caricamento, fornire un file di intestazione (con estensione h) e un file
di libreria di importazione (con estensione lib) durante la compilazione e il collegamento
dell'applicazione. Quando si esegue questa operazione, il linker fornirà al sistema le
informazioni necessarie per caricare la DLL e risolvere i percorsi delle funzioni DLL
esportate in fase di caricamento.

Collegamento dinamico in fase di esecuzione


Nel collegamento dinamico in fase di esecuzione, un'applicazione chiama la
funzione LoadLibrary o la funzione LoadLibraryEx per caricare la DLL in fase di esecuzione.
Dopo avere caricato la DLL, utilizzare la funzione GetProcAddress per ottenere l'indirizzo
della funzione DLL esportata che si desidera chiamare. Quando si utilizza il collegamento
dinamico in fase di esecuzione, non è necessario un file di libreria di importazione.
Di seguito sono elencati i criteri relativi alle applicazioni per determinare quando utilizzare
il collegamento dinamico in fase di caricamento e quando utilizzare il collegamento
dinamico in fase di esecuzione:
•Prestazioni di avvio
Se le prestazioni di avvio iniziale dell'applicazione sono importanti, è necessario
utilizzare il collegamento dinamico in fase di esecuzione.
•Facilità di utilizzo
Nel collegamento dinamico in fase di caricamento, le funzioni DLL esportate sono
come funzioni locali. Questo semplifica la chiamata di tali funzioni.
•Logica dell'applicazione
Nel collegamento dinamico in fase di esecuzione, un'applicazione può caricare
differenti moduli in base alle esigenze. È un aspetto importante quando si sviluppano
versioni multilingue.

Punto di ingresso della 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.

Esportare le funzioni DLL

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

DLL e applicazioni di esempio

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

Potrebbero piacerti anche