Remarque
L’accès à cette page requiert une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page requiert une autorisation. Vous pouvez essayer de modifier des répertoires.
Point d’entrée facultatif dans une bibliothèque de liens dynamiques (DLL). Lorsque le système démarre ou termine un processus ou un thread, il appelle la fonction de point d’entrée pour chaque DLL chargée à l’aide du premier thread du processus. Le système appelle également la fonction de point d’entrée pour une DLL lorsqu’elle est chargée ou déchargée à l’aide des fonctions LoadLibrary et FreeLibrary .
Avertissement
Il existe des limites significatives sur ce que vous pouvez faire en toute sécurité dans un point d’entrée DLL. Consultez les meilleures pratiques générales pour obtenir des API Windows spécifiques qui ne sont pas sécurisées pour appeler dans DllMain. Si vous avez besoin de quelque chose, mais que l’initialisation la plus simple, effectuez cela dans une fonction d’initialisation pour la DLL. Vous pouvez demander aux applications d’appeler la fonction d’initialisation après l’exécution de DllMain et avant d’appeler d’autres fonctions dans la DLL.
Exemple
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.
}
Il s’agit d’un exemple de la fonction Entry-Point bibliothèqueDynamic-Link.
Syntax
BOOL WINAPI DllMain(
_In_ HINSTANCE hinstDLL,
_In_ DWORD fdwReason,
_In_ LPVOID lpvReserved
);
Parameters
-
hinstDLL [in]
-
Handle du module DLL. La valeur est l’adresse de base de la DLL. L’HINSTANCE d’une DLL est identique à HMODULE de la DLL. Ainsi, hinstDLL peut être utilisé dans les appels aux fonctions qui nécessitent un handle de module.
-
fdwReason [in]
-
Code de raison qui indique pourquoi la fonction de point d’entrée DLL est appelée. Ce paramètre peut être l’une des valeurs suivantes.
Valeur Sens - DLL_PROCESS_ATTACH
- 1
La DLL est chargée dans l’espace d’adressage virtuel du processus actuel en raison du démarrage du processus ou d’un appel à LoadLibrary. Les DLL peuvent utiliser cette possibilité d’initialiser des données d’instance ou d’utiliser la fonction TlsAlloc pour allouer un index tls local storage (TLS).
Le paramètre lpvReserved indique si la DLL est chargée statiquement ou dynamiquement.- DLL_PROCESS_DETACH
- 0
La DLL est déchargée à partir de l’espace d’adressage virtuel du processus appelant, car elle a été chargée sans succès ou le nombre de références a atteint zéro (les processus ont été arrêtés ou appelés FreeLibrary une fois pour chaque fois qu’il a appelé LoadLibrary).
Le paramètre lpvReserved indique si la DLL est déchargée en raison d’un appel FreeLibrary , d’un échec de chargement ou d’arrêt du processus.
La DLL peut utiliser cette opportunité pour appeler la fonction TlsFree pour libérer tous les index TLS alloués à l’aide de TlsAlloc et libérer toutes les données locales de thread.
Notez que le thread qui reçoit la notification DLL_PROCESS_DETACH n’est pas nécessairement le même thread que celui qui a reçu la notification DLL_PROCESS_ATTACH .- DLL_THREAD_ATTACH
- 2
Le processus actuel crée un thread. Quand cela se produit, le système appelle la fonction de point d’entrée de toutes les DLL actuellement attachées au processus. L’appel est effectué dans le contexte du nouveau thread. Les DLL peuvent utiliser cette opportunité pour initialiser un emplacement TLS pour le thread. Un thread appelant la fonction de point d’entrée DLL avec DLL_PROCESS_ATTACH n’appelle pas la fonction de point d’entrée DLL avec DLL_THREAD_ATTACH.
Notez que la fonction de point d’entrée d’une DLL est appelée avec cette valeur uniquement par les threads créés après le chargement de la DLL par le processus. Lorsqu’une DLL est chargée à l’aide de LoadLibrary, les threads existants n’appellent pas la fonction de point d’entrée de la DLL nouvellement chargée.- DLL_THREAD_DETACH
- 3
Un thread sort proprement. Si la DLL a stocké un pointeur vers la mémoire allouée dans un emplacement TLS, elle doit utiliser cette possibilité pour libérer la mémoire. Le système appelle la fonction de point d’entrée de toutes les DLL actuellement chargées avec cette valeur. L’appel est effectué dans le contexte du thread de sortie. -
lpvReserved [in]
-
Si fdwReason est DLL_PROCESS_ATTACH, lpvReserved a la valeur NULL pour les charges dynamiques et non NULL pour les charges statiques.
Si fdwReason est DLL_PROCESS_DETACH, lpvReserved a la valeur NULL si FreeLibrary a été appelé ou si la charge DLL a échoué et non NULL si le processus se termine.
Valeur renvoyée
Lorsque le système appelle la fonction DllMain avec la valeur DLL_PROCESS_ATTACH , la fonction retourne TRUE si elle réussit ou FALSE si l’initialisation échoue. Si la valeur de retour est FALSE quand DllMain est appelée, car le processus utilise la fonction LoadLibrary , LoadLibrary retourne NULL. (Le système appelle immédiatement votre fonction de point d’entrée avec DLL_PROCESS_DETACH et décharge la DLL.) Si la valeur de retour est FALSE lorsque DllMain est appelé pendant l’initialisation du processus, le processus se termine par une erreur. Pour obtenir des informations d’erreur étendues, appelez GetLastError.
Lorsque le système appelle la fonction DllMain avec n’importe quelle valeur autre que DLL_PROCESS_ATTACH, la valeur de retour est ignorée.
Remarks
DllMain est un espace réservé pour le nom de la fonction définie par la bibliothèque. Vous devez spécifier le nom réel que vous utilisez lorsque vous générez votre DLL. Pour plus d’informations, consultez la documentation fournie avec vos outils de développement.
Pendant le démarrage initial du processus ou après un appel à LoadLibrary, le système analyse la liste des DLL chargées pour le processus. Pour chaque DLL qui n’a pas déjà été appelée avec la valeur DLL_PROCESS_ATTACH , le système appelle la fonction de point d’entrée de la DLL. Cet appel est effectué dans le contexte du thread qui a provoqué la modification de l’espace d’adressage du processus, tel que le thread principal du processus ou le thread appelé LoadLibrary. L’accès au point d’entrée est sérialisé par le système à l’échelle du processus. Les threads dans DllMain contiennent le verrou du chargeur afin qu’aucune DLL supplémentaire ne puisse être chargée ou initialisée dynamiquement.
Si la fonction de point d’entrée de la DLL retourne FALSE après une notification DLL_PROCESS_ATTACH , elle reçoit une notification DLL_PROCESS_DETACH et la DLL est déchargée immédiatement. Toutefois, si le code DLL_PROCESS_ATTACH lève une exception, la fonction de point d’entrée ne reçoit pas la notification DLL_PROCESS_DETACH .
Il existe des cas dans lesquels la fonction de point d’entrée est appelée pour un thread de fin, même si la fonction de point d’entrée n’a jamais été appelée avec DLL_THREAD_ATTACH pour le thread :
- Le thread était le thread initial dans le processus, donc le système a appelé la fonction de point d’entrée avec la valeur DLL_PROCESS_ATTACH .
- Le thread était déjà en cours d’exécution lorsqu’un appel à la fonction LoadLibrary a été effectué, de sorte que le système n’a jamais appelé la fonction de point d’entrée pour celle-ci.
Lorsqu’une DLL est déchargée à partir d’un processus en raison d’une charge infructueuse de la DLL, de l’arrêt du processus ou d’un appel à FreeLibrary, le système n’appelle pas la fonction de point d’entrée de la DLL avec la valeur DLL_THREAD_DETACH pour les threads individuels du processus. La DLL n’est envoyée qu’à une notification DLL_PROCESS_DETACH. Les DLL peuvent profiter de cette occasion pour nettoyer toutes les ressources de tous les threads connus de la DLL.
Lorsque vous gérez DLL_PROCESS_DETACH, une DLL doit libérer des ressources telles que la mémoire du tas uniquement si la DLL est déchargée dynamiquement (le paramètre lpvReserved est NULL). Si le processus se termine (le paramètre lpvReserved n’est pas NULL), tous les threads du processus, à l’exception du thread actuel, ont déjà quitté ou ont été explicitement arrêtés par un appel à la fonction ExitProcess , ce qui peut laisser certaines ressources de processus telles que les tas dans un état incohérent. Dans ce cas, il n’est pas sûr que la DLL nettoie les ressources. Au lieu de cela, la DLL doit autoriser le système d’exploitation à récupérer la mémoire.
Si vous arrêtez un processus en appelant TerminateProcess ou TerminateJobObject, les DLL de ce processus ne reçoivent pas de notifications DLL_PROCESS_DETACH . Si vous arrêtez un thread en appelant TerminateThread, les DLL de ce thread ne reçoivent pas de notifications DLL_THREAD_DETACH .
La fonction de point d’entrée doit effectuer uniquement des tâches d’initialisation ou d’arrêt simples. Il ne doit pas appeler la fonction LoadLibrary ou LoadLibraryEx (ou une fonction qui appelle ces fonctions), car cela peut créer des boucles de dépendance dans l’ordre de chargement dll. Cela peut entraîner l’utilisation d’une DLL avant que le système n’ait exécuté son code d’initialisation. De même, la fonction de point d’entrée ne doit pas appeler la fonction FreeLibrary (ou une fonction qui appelle FreeLibrary) pendant l’arrêt du processus, car cela peut entraîner l’utilisation d’une DLL après l’exécution de son code de terminaison par le système.
Étant donné que Kernel32.dll est garanti être chargé dans l’espace d’adressage du processus lorsque la fonction de point d’entrée est appelée, l’appel de fonctions dans Kernel32.dll n’entraîne pas l’utilisation de la DLL avant l’exécution de son code d’initialisation. Par conséquent, la fonction de point d’entrée peut appeler des fonctions dans Kernel32.dll qui ne chargent pas d’autres DLL. Par exemple, DllMain peut créer des objets de synchronisation tels que des sections critiques et des mutex, et utiliser TLS. Malheureusement, il n’existe pas de liste complète de fonctions sécurisées dans Kernel32.dll.
L’appel de fonctions qui nécessitent des DLL autres que Kernel32.dll peut entraîner des problèmes difficiles à diagnostiquer. Par exemple, l’appel des fonctions Utilisateur, Shell et COM peut entraîner des erreurs de violation d’accès, car certaines fonctions chargent d’autres composants système. À l’inverse, l’appel de fonctions telles que celles-ci pendant l’arrêt peut entraîner des erreurs de violation d’accès, car le composant correspondant peut déjà avoir été déchargé ou non initialisé.
Étant donné que les notifications DLL sont sérialisées, les fonctions de point d’entrée ne doivent pas tenter de communiquer avec d’autres threads ou processus. Des interblocages peuvent se produire en conséquence.
Pour plus d’informations sur les bonnes pratiques lors de l’écriture d’une DLL, consultez les meilleures pratiques de bibliothèque de liens dynamiques.
Si votre DLL est liée à la bibliothèque runtime C (CRT), le point d’entrée fourni par le CRT appelle les constructeurs et les destructeurs pour les objets C++ globaux et statiques. Par conséquent, ces restrictions pour DllMain s’appliquent également aux constructeurs et aux destructeurs et à tout code qui est appelé à partir de ces derniers.
Envisagez d’appeler DisableThreadLibraryCalls lors de la réception de DLL_PROCESS_ATTACH, sauf si votre DLL est liée à la bibliothèque d’exécution C statique (CRT).
Exigences
| Requirement | Valeur |
|---|---|
| Client minimum requis |
Windows XP [applications de bureau uniquement] |
| Serveur minimum pris en charge |
Windows Server 2003 [applications de bureau uniquement] |
| Header |
|