Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Punto di ingresso facoltativo in una libreria a collegamento dinamico (DLL). Quando il sistema avvia o termina un processo o un thread, chiama la funzione del punto di ingresso per ogni DLL caricata usando il primo thread del processo. Il sistema chiama anche la funzione del punto di ingresso per una DLL quando viene caricata o scaricata usando le funzioni LoadLibrary e FreeLibrary .
Avvertimento
Esistono limiti significativi sulle operazioni che è possibile eseguire in modo sicuro in un punto di ingresso della DLL. Vedere Procedure consigliate generali per API di Windows specifiche che non sono sicure da chiamare in DllMain. Se è necessario un'inizializzazione qualsiasi ma la più semplice, eseguire questa operazione in una funzione di inizializzazione per la DLL. È possibile richiedere alle applicazioni di chiamare la funzione di inizializzazione dopo l'esecuzione di DllMain e prima di chiamare qualsiasi altra funzione nella DLL.
Esempio
BOOL WINAPI DllMain(
HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpvReserved ) // reserved
{
// Perform actions based on the reason for calling.
switch( fdwReason )
{
case DLL_PROCESS_ATTACH:
// Initialize once for each new process.
// Return FALSE to fail DLL load.
break;
case DLL_THREAD_ATTACH:
// Do thread-specific initialization.
break;
case DLL_THREAD_DETACH:
// Do thread-specific cleanup.
break;
case DLL_PROCESS_DETACH:
if (lpvReserved != nullptr)
{
break; // do not do cleanup if process termination scenario
}
// Perform any necessary cleanup.
break;
}
return TRUE; // Successful DLL_PROCESS_ATTACH.
}
Questo è un esempio della funzione Entry-Point libreria diDynamic-Link.
Syntax
BOOL WINAPI DllMain(
_In_ HINSTANCE hinstDLL,
_In_ DWORD fdwReason,
_In_ LPVOID lpvReserved
);
Parameters
-
hinstDLL [in]
-
Handle per il modulo DLL. Il valore è l'indirizzo di base della DLL. L'HINSTANCE di una DLL è uguale a HMODULE della DLL, quindi hinstDLL può essere usato nelle chiamate a funzioni che richiedono un handle di modulo.
-
fdwReason [in]
-
Codice motivo che indica il motivo per cui viene chiamata la funzione punto di ingresso della DLL. Questo parametro può essere uno dei valori seguenti.
Value Meaning - DLL_PROCESS_ATTACH
- 1
La DLL viene caricata nello spazio degli indirizzi virtuali del processo corrente in seguito all'avvio del processo o a seguito di una chiamata a LoadLibrary. Le DLL possono usare questa opportunità per inizializzare tutti i dati dell'istanza o per usare la funzione TlsAlloc per allocare un indice tls (Thread Local Storage).
Il parametro lpvReserved indica se la DLL viene caricata in modo statico o dinamico.- DLL_PROCESS_DETACH
- 0
La DLL viene scaricata dallo spazio indirizzi virtuale del processo chiamante perché è stata caricata in modo non riuscito o il conteggio dei riferimenti ha raggiunto zero (i processi hanno terminato o chiamato FreeLibrary una volta per ogni volta che ha chiamato LoadLibrary).
Il parametro lpvReserved indica se la DLL viene scaricata in seguito a una chiamata FreeLibrary , a un errore di caricamento o alla terminazione del processo.
La DLL può usare questa opportunità per chiamare la funzione TlsFree per liberare tutti gli indici TLS allocati usando TlsAlloc e liberare tutti i dati locali del thread.
Si noti che il thread che riceve la notifica di DLL_PROCESS_DETACH non è necessariamente lo stesso thread che ha ricevuto la notifica di DLL_PROCESS_ATTACH .- DLL_THREAD_ATTACH
- 2
Il processo corrente sta creando un nuovo thread. In questo caso, il sistema chiama la funzione del punto di ingresso di tutte le DLL attualmente collegate al processo. La chiamata viene effettuata nel contesto del nuovo thread. Le DLL possono usare questa opportunità per inizializzare uno slot TLS per il thread. Un thread che chiama la funzione punto di ingresso dll con DLL_PROCESS_ATTACH non chiama la funzione del punto di ingresso DLL con DLL_THREAD_ATTACH.
Si noti che la funzione del punto di ingresso di una DLL viene chiamata con questo valore solo dai thread creati dopo che la DLL viene caricata dal processo. Quando una DLL viene caricata tramite LoadLibrary, i thread esistenti non chiamano la funzione del punto di ingresso della DLL appena caricata.- DLL_THREAD_DETACH
- 3
Un thread viene chiuso in modo pulito. Se la DLL ha archiviato un puntatore alla memoria allocata in uno slot TLS, dovrebbe usare questa opportunità per liberare la memoria. Il sistema chiama la funzione del punto di ingresso di tutte le DLL attualmente caricate con questo valore. La chiamata viene effettuata nel contesto del thread di uscita. -
lpvReserved [in]
-
Se fdwReason è DLL_PROCESS_ATTACH, lpvReserved è NULL per i caricamenti dinamici e non NULL per i caricamenti statici.
Se fdwReason è DLL_PROCESS_DETACH, lpvReserved è NULL se FreeLibrary è stato chiamato o il caricamento della DLL non è riuscito e non NULL se il processo termina.
Valore restituito
Quando il sistema chiama la funzione DllMain con il valore DLL_PROCESS_ATTACH , la funzione restituisce TRUE se ha esito positivo o FALSE se l'inizializzazione non riesce. Se il valore restituito è FALSE quando Viene chiamato DllMain perché il processo usa la funzione LoadLibrary, LoadLibrary restituisce NULL. Il sistema chiama immediatamente la funzione del punto di ingresso con DLL_PROCESS_DETACH e scarica la DLL. Se il valore restituito è FALSE quando DllMain viene chiamato durante l'inizializzazione del processo, il processo termina con un errore. Per ottenere informazioni estese sull'errore, chiamare GetLastError.
Quando il sistema chiama la funzione DllMain con qualsiasi valore diverso da DLL_PROCESS_ATTACH, il valore restituito viene ignorato.
Remarks
DllMain è un segnaposto per il nome della funzione definito dalla libreria. È necessario specificare il nome effettivo usato durante la compilazione della DLL. Per altre informazioni, vedere la documentazione inclusa negli strumenti di sviluppo.
Durante l'avvio iniziale del processo o dopo una chiamata a LoadLibrary, il sistema analizza l'elenco di DLL caricate per il processo. Per ogni DLL che non è già stata chiamata con il valore DLL_PROCESS_ATTACH , il sistema chiama la funzione punto di ingresso della DLL. Questa chiamata viene effettuata nel contesto del thread che ha causato la modifica dello spazio degli indirizzi del processo, ad esempio il thread primario del processo o il thread che ha chiamato LoadLibrary. L'accesso al punto di ingresso viene serializzato dal sistema a livello di processo. I thread in DllMain mantengono il blocco del caricatore in modo che nessuna DLL aggiuntiva possa essere caricata o inizializzata dinamicamente.
Se la funzione del punto di ingresso della DLL restituisce FALSE dopo una notifica di DLL_PROCESS_ATTACH , riceve una notifica di DLL_PROCESS_DETACH e la DLL viene scaricata immediatamente. Tuttavia, se il codice DLL_PROCESS_ATTACH genera un'eccezione, la funzione del punto di ingresso non riceverà la notifica DLL_PROCESS_DETACH .
Esistono casi in cui viene chiamata la funzione del punto di ingresso per un thread di terminazione anche se la funzione del punto di ingresso non è mai stata chiamata con DLL_THREAD_ATTACH per il thread:
- Il thread era il thread iniziale nel processo, quindi il sistema ha chiamato la funzione del punto di ingresso con il valore DLL_PROCESS_ATTACH .
- Il thread era già in esecuzione quando è stata effettuata una chiamata alla funzione LoadLibrary , quindi il sistema non ha mai chiamato la funzione del punto di ingresso per essa.
Quando una DLL viene scaricata da un processo in seguito a un caricamento non riuscito della DLL, alla chiusura del processo o a una chiamata a FreeLibrary, il sistema non chiama la funzione del punto di ingresso della DLL con il valore DLL_THREAD_DETACH per i singoli thread del processo. La DLL viene inviata solo una notifica di DLL_PROCESS_DETACH . Le DLL possono sfruttare questa opportunità per pulire tutte le risorse per tutti i thread noti alla DLL.
Quando si gestisce DLL_PROCESS_DETACH, una DLL deve liberare risorse come la memoria heap solo se la DLL viene scaricata dinamicamente (il parametro lpvReserved è NULL). Se il processo termina (il parametro lpvReserved è diverso da NULL), tutti i thread del processo, ad eccezione del thread corrente sono già usciti o sono stati terminati in modo esplicito da una chiamata alla funzione ExitProcess , che potrebbe lasciare alcune risorse di processo, ad esempio gli heap in uno stato incoerente. In questo caso, non è sicuro che la DLL pulisca le risorse. La DLL dovrebbe invece consentire al sistema operativo di recuperare la memoria.
Se si termina un processo chiamando TerminateProcess o TerminateJobObject, le DLL di tale processo non ricevono notifiche DLL_PROCESS_DETACH . Se si termina un thread chiamando TerminateThread, le DLL di tale thread non ricevono notifiche DLL_THREAD_DETACH .
La funzione del punto di ingresso deve eseguire solo semplici attività di inizializzazione o terminazione. Non deve chiamare la funzione LoadLibrary o LoadLibraryEx (o una funzione che chiama queste funzioni), perché ciò può creare cicli di dipendenza nell'ordine di caricamento dll. Ciò può comportare l'uso di una DLL prima che il sistema abbia eseguito il codice di inizializzazione. Analogamente, la funzione del punto di ingresso non deve chiamare la funzione FreeLibrary (o una funzione che chiama FreeLibrary) durante la terminazione del processo, perché ciò può comportare l'uso di una DLL dopo che il sistema ha eseguito il codice di terminazione.
Poiché Kernel32.dll è garantito che venga caricato nello spazio indirizzi del processo quando viene chiamata la funzione del punto di ingresso, la chiamata di funzioni in Kernel32.dll non comporta l'uso della DLL prima dell'esecuzione del codice di inizializzazione. Pertanto, la funzione del punto di ingresso può chiamare funzioni in Kernel32.dll che non caricano altre DLL. Ad esempio, DllMain può creare oggetti di sincronizzazione come sezioni critiche e mutex e usare TLS. Sfortunatamente, non esiste un elenco completo di funzioni sicure in Kernel32.dll.
Le funzioni di chiamata che richiedono DLL diverse da Kernel32.dll possono causare problemi difficili da diagnosticare. Ad esempio, la chiamata a funzioni Utente, Shell e COM può causare errori di violazione di accesso, perché alcune funzioni caricano altri componenti di sistema. Viceversa, la chiamata di funzioni come queste durante la terminazione può causare errori di violazione di accesso perché il componente corrispondente potrebbe essere già stato scaricato o non inizializzato.
Poiché le notifiche DLL sono serializzate, le funzioni del punto di ingresso non devono tentare di comunicare con altri thread o processi. I deadlock possono verificarsi di conseguenza.
Per informazioni sulle procedure consigliate per la scrittura di una DLL, vedere Procedure consigliate per la libreria a collegamento dinamico.
Se la DLL è collegata alla libreria di runtime C (CRT), il punto di ingresso fornito da CRT chiama i costruttori e i distruttori per gli oggetti C++ globali e statici. Pertanto, queste restrizioni per DllMain si applicano anche a costruttori e distruttori e a qualsiasi codice chiamato da essi.
Valutare la possibilità di chiamare DisableThreadLibraryCalls durante la ricezione di DLL_PROCESS_ATTACH, a meno che la DLL non sia collegata con la libreria di runtime C statica (CRT).
Requisiti
| Requisito | Value |
|---|---|
| Client minimo supportato |
Windows XP [solo app desktop] |
| Server minimo supportato |
Windows Server 2003 [solo app desktop] |
| Intestazione |
|