Partager via


Comment partager les données contenues dans ma DLL avec une application ou d'autres DLL ?

Mise à jour : novembre 2007

Les DLL Win32 sont mappées à l'espace d'adressage du processus appelant. Par défaut, chaque processus utilisant une DLL possède sa propre instance des variables globales et statiques de toutes les DLL. Si votre DLL doit partager des données avec d'autres instances d'elle-même chargées par d'autres applications, vous pouvez adopter l'une des approches suivantes :

  • Créez des sections de données nommées à l'aide du pragma data_seg.

  • Utilisez des fichiers mappés en mémoire. Consultez la documentation « Managing Memory-Mapped Files in Win32 » dans MSDN Lib.

Voici un exemple d'utilisation du pragma data_seg :

#pragma data_seg (".myseg")
   int i = 0; 
   char a[32]n = "hello world";
#pragma data_seg()

data_seg permet de créer une nouvelle section nommée (.myseg dans cet exemple). L'application la plus classique consiste à appeler le segment de données .shared par souci de clarté. Vous devez ensuite spécifier les attributs de partage appropriés pour cette nouvelle section de données nommée dans le fichier .def ou utiliser l'option /SECTION:.MYSEC,RWS de l'éditeur de liens.

Certaines restrictions sont à prendre en compte avant toute utilisation d'un segment de données partagées :

  • Les variables contenues, le cas échéant, dans un segment de données partagées doivent être initialisées de manière statique. Dans l'exemple ci-dessous, i est initialisée en utilisant la valeur 0 et a (qui compte 32 caractères) est initialisée en "hello world".

  • Toutes les variables partagées sont placées dans la DLL compilée dans le segment de données spécifié. De très grands tableaux peuvent produire des DLL très volumineuses. Ceci est vrai pour toutes les variables globales initialisées.

  • N'enregistrez jamais des informations spécifiques d'un processus dans un segment de données partagées. La plupart des valeurs ou des structures de données Win32 (HANDLE, par exemple) sont réellement valides seulement dans le contexte d'un processus unique.

  • Chaque processus obtient son propre espace d'adressage. Il est très important de ne jamais enregistrer les pointeurs dans une variable contenue dans un segment de données partagées. Un pointeur peut parfaitement être valide dans une application et pas dans une autre.

  • Il est possible que la DLL elle-même puisse être chargée à une adresse différente dans les espaces d'adressage virtuels de chaque processus. Il est déconseillé d'avoir des pointeurs qui désignent des fonctions dans la DLL ou d'autres variables partagées.

Notez que les trois derniers points s'appliquent aux fichiers mappés en mémoire et aux segments de données partagées.

Les fichiers mappés en mémoire offrent un avantage par rapport aux sections de données partagées car le début du fichier mappé en mémoire est connu. Les développeurs peuvent implémenter un comportement de type pointeur en utilisant un « offset à partir du début de la section de mémoire partagée » dans toutes les données contenues dans la mémoire partagée. Les pointeurs __based sont vivement recommandés pour effectuer cette opération de manière rapide et simple. Cependant, il est important de se souvenir que la base (ou le début du fichier mappé en mémoire) peut être différente dans chaque processus ; la variable contenant la base pour les pointeurs __based ne peut donc pas se trouver elle-même dans la mémoire partagée.

Ces restrictions ont d'importantes implications pour les classes C++.

  • Les classes pourvues de fonctions virtuelles contiennent toujours des pointeurs de fonction. Les classes pourvues de fonctions virtuelles ne doivent jamais être stockées dans des segments de données partagées et des fichiers mappés en mémoire. Ce point est particulièrement important pour les classes MFC ou les classes qui héritent des MFC.

  • Les données membres statiques sont implémentées en tant qu'équivalents des variables globales. Cela signifie que chaque processus aurait sa propre copie des données membres statiques de cette classe. Les classes pourvues de données membres statiques ne doivent pas être partagées.

  • La nécessité d'initialiser un segment de données partagées pose un problème particulier pour les classes C++. Si, par exemple, CTest Counter(0); se trouve dans un segment de données partagées, l'objet Counter est initialisé dans chaque processus lors du chargement de la DLL, mettant potentiellement à zéro les données de l'objet à chaque fois. Ceci est très différent des types de données intrinsèques qui sont initialisés par l'éditeur de liens qui crée la DLL.

Compte tenu de ces restrictions, Microsoft ne recommande pas le partage d'objets C++ entre les processus. En règle générale, si vous souhaitez utiliser C++ pour partager les données entre les processus, écrivez une classe qui utilise en interne un fichier mappé en mémoire pour partager les données, mais ne partagez pas les instances de la classe. Cela peut demander une attention particulière lors du développement d'une telle classe, mais permet aux développeurs d'applications de contrôler pleinement les effets secondaires du partage des données.

Pour plus d'informations sur la création de sections de données nommées, consultez les articles ci-dessous dans la Base de connaissances à l'adresse https://www.microsoft.com/france/support :

  • « Comment partager des données entre différents mappages d'une DLL » (Q125677 en anglais).

  • « Comment spécifier des données partagées et non partagées d'une DLL dans Visual C++ » (Q100634 en anglais).

  • « Comment partager toutes les données d'une DLL » (Q109619 en anglais).

  • « La mémoire figurant dans les sections de code partagé n'est pas partagée dans les sessions Terminal Server » (F251045 en français).

Voir aussi

Concepts

Forum Aux Questions à propos des DLL