Cette note décrit comment vous pouvez utiliser la MFCxx.DLL et MFCxxD.DLL (où x est le numéro de version MFC) partage des bibliothèques de liens dynamiques avec les applications MFC et les DLL d'extension. Pour plus d'informations sur les DLL normales, voir à l'aide de MFC dans le cadre d'une DLL.
Cette note technique couvre trois aspects de la DLL. Les deux derniers sont pour les utilisateurs plus avancés:
Si vous êtes intéressé dans la construction d'une DLL à l'aide de MFC qui peut être utilisé avec des applications non MFC (cela s'appelle une DLL régulière), veuillez vous référer aux techniques Note 11.
Vue d'ensemble du Support MFCxx.DLL : terminologie et fichiers
DLL normale: vous utilisez une DLL régulière pour créer une DLL autonome à l'aide des classes MFC. « C » interfaces sont des interfaces à travers la frontière App/DLL et l'application cliente n'a pas à être une application MFC.
Il s'agit de la version de la DLL soutien appuyé dans MFC 1.0. Il est décrit dans l'exemple MFC Advanced Concepts et de techniques Note 11 DLLTRACE.
&Notenbsp ; Comme Visual C++ version 4.0, le terme USRDLL est obsolète et a été remplacée par une DLL normale liée statiquement aux MFC. Vous peut également générer une DLL normale liée de manière dynamique aux MFC.
MFC 3.0 (et ci-dessus) prend en charge les DLL régulières avec toutes les fonctionnalités nouvelles, y compris les classes OLE et base de données.
AFXDLL: c'est aussi appelé la version partagée des bibliothèques MFC. C'est le nouveau support des DLL dans MFC 2.0. La bibliothèque MFC elle-même est dans un certain nombre de DLL (décrit ci-dessous) et une application cliente ou une DLL liée de manière dynamique les DLL qu'il exige. Les interfaces à travers la limite d'application et les DLL sont C + / interfaces de classe MFC. L'application cliente doit être une application MFC. Cela prend en charge toutes les fonctionnalités MFC 3.0 (excption : UNICODE n'est pas pris en charge pour les classes de base de données).
&Notenbsp ; Que de Visual C++ version 4.0, ce type de DLL est appelé une « Extension DLL. »
Cette note utilisera MFCxx.DLL pour désigner l'ensemble de la DLL MFC définie, qui comprend:
&Notenbsp ; Le MFCSxx [U] [D].LIB bibliothèques sont utilisées en conjointement avec le MFC partagé dll. Ces bibliothèques contiennent du code qui doit être liée de manière statique à l'application ou la DLL.
Une Liens de l'application à des bibliothèques d'importation correspondant:
Une « DLL d'Extension MFC » est une DLL sur MFCxx.DLL (ou l'autre MFC partagé dll). Ici, l'architecture de composants MFC kicks à. Si vous dérivez une classe utile d'une classe MFC, ou construire un autre ressemblant à MFC toolkit, vous pouvez le placer dans une DLL. Que DLL utilise MFCxx.DLL, comme le fait la demande du client final. Cela permet aux classes de feuilles réutilisables, des classes de base réutilisables et classes réutilisables vue/document.
&Notenbsp ; Il n'est pas nécessaire de lier avec MFCOxx [U] D, D MFCDxx [U] ou MFCNxx [U] D Debug bibliothèques à moins que votre application utilise les MFC/OLE, la base de données ou la mise en réseau des classes respectivement.
Avantages et inconvénients
Pourquoi est-ce que vous devez utiliser la version partagée des MFC?
Pourquoi ne faut pas utiliser la version partagée des MFC:
Une DLL d'Extension MFC est une DLL contenant les classes et les fonctions écrites d'embellir les fonctionnalités des classes MFC. Le support de débogage OLE et base de données dll (MFCOxxD.DLL et MFCDxxD.DLL) sont des exemples de DLL d'extension MFC qu'ils utilisent MFCxxD.DLL. Une DLL d'Extension MFC utilise la DLL MFC partagées de la même façon qu'une application utilise, avec quelques considérations supplémentaires:
Ces considérations sont décrites plus en détail ci-dessous. Vous devriez également vous référer à l'exemple MFC Advanced Concepts DLLHUSK puisqu'il illustre
L'application cliente et toutes les DLL d'extension doivent utiliser la même version de MFCxx.DLL. Vous devez suivre la convention de la DLL MFC et fournir les deux versions debug et retail (/ communiqué) version de la DLL d'extension. Cela permet aux programmes clients pour générer des versions debug et de vente au détail de leurs applications et leur lien avec le débogage approprié ou la version au détail de toutes les DLL.
&Notenbsp ; En raison de tenu des problème d'exportation et d'amputation des noms du C++, la liste d'exportation à partir d'une DLL d'extension peut être différente entre les versions debug et retail la même DLL et les DLL de plates-formes différentes. La vente au détail MFCxx.DLL a environ 2000 exporté des points d'entrée ; le débogage MFCxxD.DLL a environ 3000 exporté des points d'entrée.
Note rapide sur la gestion de la mémoire
La section intitulée « Gestion de la mémoire, « près de la fin de cette note technique décrit la mise en œuvre de la MFCxx.DLL avec la version partagée des MFC. Les informations que vous devez savoir pour mettre en œuvre qu'une DLL d'extension sont décrite ici.
MFCxx.DLL et toutes les DLL d'extension chargées dans l'espace d'adressage d'une application client utilisera l'allocateur de mémoire même, chargement de ressource et autres États « globales » MFC comme s'ils étaient dans la même application. Ceci est important car les bibliothèques DLL non - MFC et les DLL normales liées de manière statique aux MFC faire exactement le contraire et ont chaque attribution de DLL de son propre pool de mémoire.
Si une DLL d'extension alloue de la mémoire, alors que la mémoire peut librement mélangée avec tout autre objet alloué par l'application. En outre, si une application qui utilise les bibliothèques MFC partagées se bloque, la protection du système d'exploitation maintiendra l'intégrité de toute autre application MFC partage la DLL.
De même les autres États « globales » de MFC, comme le fichier exécutable actuel pour charger des ressources, sont aussi partagées entre l'application client et toutes les DLL d'extension MFC ainsi MFCxx.DLL lui-même.
Construction d'une DLL d'Extension
Vous pouvez utiliser AppWizard pour créer un projet de DLL d'extension MFC, et il génère automatiquement le compilateur approprié et les paramètres de l'éditeur de liens. Il était également générer une fonction DllMain que vous pouvez modifier.
Si vous convertissez un projet existant à une DLL d'extension MFC, commencer par les règles standards pour la construction d'une application à l'aide de la version partagée des MFC, puis effectuez les opérations suivantes:
Modification de vos fichiers d'en-tête
L'objectif d'une extension DLL est habituellement à l'exportation de certaines des fonctionnalités communes à une ou plusieurs applications qui peuvent utiliser cette fonctionnalité. Cela se résume à l'exportation des classes et fonctions globales qui sont disponibles pour vos applications de client.
Pour ce faire, vous devez s'assurer que chacune des fonctions membre est marqué comme importer ou exporter comme il convient. Pour cela, les déclarations spéciales : __declspec (dllexport) et __declspec (dllimport). Lorsque vos classes sont utilisées par les applications clientes, vous voulez être déclarés en tant que __declspec (dllimport). Lorsque l'extension DLL elle-même est construite, ils devraient être déclarés en tant que __declspec (dllexport). En outre, les fonctions doivent être effectivement exportées, afin que les programmes client se lient à eux au moment du chargement.
Pour exporter votre classe entière, utilisez AFX_EXT_CLASS dans la définition de classe. Cette macro est définie par le cadre tant que __declspec (dllexport) quand _AFXDLL et _AFXEXT est défini, mais défini comme __declspec (dllimport) lorsque _AFXEXT n'est pas défini. _AFXEXT comme décrit ci-dessus, est uniquement défini lors de la construction de votre DLL d'extension. Par exemple:
classe AFX_EXT_CLASS CExampleExport : public CObject
{... classe définition...}
N'exporte ne pas la classe entière
Parfois, vous souhaiterez exporter seulement les membres individuels nécessaires de votre classe. Par exemple, si vous exportez un CDialog-dérivée de la classe, vous devrez peut-être uniquement à l'exportation du constructeur et l'appel de DoModal . Vous pouvez exporter ces membres à l'aide de la DLL.Fichier DEF, mais vous pouvez également utiliser AFX_EXT_CLASS à peu près la même manière sur les membres individuels, que vous devez exporter.
Par exemple:
class CExampleDialog : public CDialog
{
public :
  ; AFX_EXT_CLASS CExampleDialog() ;
AFX_EXT_CLASS int DoModal() ;
/ / reste de la définition de classe
.
.
.
}
Lorsque vous faites cela, vous pouvez exécuter dans un problème supplémentaire dû au fait que vous exportez ne sont plus tous les membres de la classe. Le problème est dans la façon dont ce travail de macros MFC. Effectivement, plusieurs des macros MFC d'assistance déclarent ou définissent les données membres. Par conséquent, ces données membres devront également être exportés à partir de votre DLL.
Par exemple, la macro DECLARE_DYNAMIC est définie comme suit lors de la construction d'une DLL d'extension:
# define DECLARE_DY&NAMIC(class_name) \
protégé: \
nbsp ; statique PASCAL CRuntimeClass * _GetBaseClass() ; \
public: \
classe statique de AFX_DATA CRuntimeClass ## class_name ; \
Virtual CRuntimeClass * GetRuntimeClass() const ; \
La ligne qui commence « statique AFX_DATA» déclare un objet statique à l'intérieur de votre classe. Pour exporter cette classe correctement et accéder à l'information du moment de l'exécution d'un client.EXE, vous devez exporter cet objet statique. Parce que l'objet statique est déclarée avec le modificateur AFX_DATA, vous ne devez définir AFX_DATA comme __declspec (dllexport) lors de la construction de votre DLL et qui le définissent comme __declspec (dllimport) lors de la construction de votre exécutable client.
Comme nous l'avons vu, AFX_EXT_CLASS est déjà définie de cette manière. Si vous avez juste besoin de redéfinir les AFX_DATA à être le même que AFX_EXT_CLASS autour de votre définition de classe.
Par exemple:
nbsp ; # undef AFX_DATA
# define AFX_DATA AFX_EXT_CLASS
Class CExampleView : public CView
{
DECLARE_DY&NAMIC()
/ / définition de la classe...
};
# undef AFX_DATA
# define AFX_DATA
MFC utilise toujours le symbole de l'AFX_DATA sur les éléments de données que définit dans ses macros, donc cette technique fonctionnera pour tous les scénarios. Par exemple, il travaillera pour DECLARE_MESSAGE_MAP.
&Notenbsp ; Si vous exportez l'ensemble de la classe plutôt que certains membres de la classe, les membres de données statiques sont exportés automatiquement.
Vous pouvez utiliser la même technique pour exporter automatiquement l'opérateur d'extraction CArchive pour les classes qui utilisent les macros DECLARE_SERIAL et IMPLEMENT_SERIAL . L'opérateur de l'archive à l'exportation par la méthode des extrêmes les déclarations de classe (situé dans le.Fichier H) avec le code suivant:
# undef AFX_API
# define AFX_API AFX_EXT_CLASS
lt ; vos déclarations de classe ici >
# undef AFX_API
# define AFX_API
Limites de _AFXEXT
Vous pouvez utiliser le symbole pre-processor de laAFXEXT _ pour votre DLL d'extension tant que vous n'avez pas plusieurs couches de DLL d'extension. Si vous avez l'extension DLL qui appellent ou qui dérivent des classes dans vos propres DLL d'extension, qui dérivent ensuite des classes MFC, vous devez utiliser votre propre symbole de préprocesseur pour éviter toute ambiguïté.
Le problème est que dans Win32, vous devez explicitement déclarer les données tant que __declspec (dllexport) si c'est pour être exportés d'une DLL et __declspec (dllimport) si c'est d'être importées à partir d'une DLL. Lorsque vous définissez _AFXEXT, les en-têtes MFC Assurez-vous que AFX_EXT_CLASS est défini correctement.
Lorsque vous avez plusieurs couches, un symbole tel que AFX_EXT_CLASS n'est pas suffisant, car une DLL d'extension peut être exporter de nouvelles classes ainsi qu'importer d'autres classes de DLL d'extension une autre. Afin de régler ce problème, utilisez un symbole spécial de pre-processor qui indique que vous générez la DLL elle-même par rapport à l'aide de la DLL. Par exemple, Imaginez deux extension DLL, A.DLL et B.DLL. Chacun d'eux exporter certaines classes de l'hégire et B.H, respectivement. B.dll utilise les classes de A.DLL. Les fichiers d'en-tête serait quelque chose comme ça:
/ / HÉGIRE
# ifdef A_IMPL
  ; # define CLASS_DECL_A __declspec (dllexport)
# else
# define CLASS_DECL_A __declspec (dllimport)
# endif
la classe CLASS_DECL_A CExampleA : public CObject
{... classe définition...} ;
/ / B.H
# ifdef B_IMPL
# define CLASS_DECL_B __declspec (dllexport)
# else
# define CLASS_DECL_B __declspec (dllimport)
# endif
classe CLASS_DECL_B CExampleB : CExampleA public
{... définition de la classe..}
Lorsque A.DLL est construit, il est construit avec /D A_IMPL et lorsque B.DLL est construit, il est construit avec /D B_IMPL. En utilisant des symboles séparés pour chaque DLL, CExampleB est exporté et CExampleA est importé lors de la construction B.DLL. CExampleA est exporté lors de la construction de A.DLL et importé lors d'une utilisation par B.DLL (ou un autre client).
Ce type de marcottage ne peut être fait lors de l'utilisation de symboles intégrés AFX_EXT_CLASS et _AFXEXT pre-processor. La technique décrite ci-dessus permet de résoudre ce problème d'une manière pas contrairement qu'au mécanisme MFC elle-même utilise lors de la génération de la DLL d'extension OLE, base de données et réseau.
N'exporte ne pas la classe entière
Encore une fois, vous devrez prendre soin lorsque vous n'exportez pas une classe entière. Vous devez vous assurer que les éléments de données nécessaires créés par les macros MFC sont exportés correctement. Ceci est possible en redéfinissant les AFX_DATA à la macro de votre classe spécifique. Ceci devrait être fait à n'importe quel moment que vous n'exportez pas la classe entière.
Par exemple:
/ / HÉGIRE
# ifdef A_IMPL
nbsp ; # define CLASS_DECL_A _declspec(dllexport)
# else
# define CLASS_DECL_A _declspec(dllimport)
# endif
# undef AFX_DATA
# define AFX_DATA CLASS_DECL_A
classe CExampleA : public CObject
{
DECLARE_DY&NAMIC()
CLASS_DECL_A int SomeFunction() ;
définition de //Class.
.
.
};
# undef AFX_DATA
# define AFX_DATA
DllMain
Voici le code exact que vous devez placer dans votre fichier source principal pour votre DLL d'extension. Il faut d'après que la norme comprend. Notez que lorsque vous utilisez AppWizard pour créer des fichiers de démarrage pour une DLL d'extension, il fournit une fonction DllMain pour vous.
# include « afxdllx.h »
statique AFX_EXTE&NSION_MODULE extensionDLL ;
extern « C » int APIENTRY DllMain (HINSTANCE hInstance, DWORD dwReason, LPVOID)
{
nbsp ; Si (dwReason == DLL_PROCESS_ATTACH)
{
/ / Initialisation unique de DLL extension if (!AfxInitExtensionModule)
extensionDLL, hInstance))
return 0 ;
/ / TODO : effectuer d'autres tâches d'initialisation ici
}
else if (dwReason == DLL_PROCESS_DETACH)
{
/ / Résiliation par processus de DLL d'extension
AfxTermExtensionModule(extensionDLL) ;
/ / TODO : effectuer d'autres tâches de nettoyage ici
}
retour 1 ; / / ok
}
L'appel de AfxInitExtensionModule capture les classes runtime modules (structuresCRuntimeClass ) ainsi que ses fabriques d'objets (objetsCOleObjectFactory ) pour les utiliser plus tard lors de la création de l'objet CDynLinkLibrary . L'appel (facultatif) à AfxTermExtensionModule permet MFC pour le nettoyage de la DLL d'extension lors de chaque processus se détache (ce qui se produit lorsque la sortie du processus, ou lorsque la DLL est déchargée à la suite d'un appel de FreeLibrary ) de la DLL d'extension. Depuis la plupart extension DLL ne sont pas chargés dynamiquement (habituellement, ils sont liés par l'intermédiaire de leur bibliothèque d'importation), l'appel à AfxTermExtensionModule n'est généralement pas nécessaire.
Si votre applicatio&n charge et libère les DLL d'extension dynamique, veillez à appeler AfxTermExtensionModule comme montré above.nbsp ; Veillez aussi à utiliser AfxLoadLibrary et AfxFreeLibrary (au lieu des fonctions Win32 LoadLibrary et FreeLibrary) si votre application utilise plusieurs threads. À l'aide de AfxLoadLibrary et AfxFreeLibrary assure que le code de démarrage et d'arrêt qui s'exécute lorsque la DLL d'extension est chargé et déchargé ne corrompt pas l'état global de la MFC.
Le fichier d'en-tête AFXDLLX.H contient des définitions spéciales pour les structures utilisées dans les DLL d'extension, tels que la définition de AFX_EXTENSION_MODULE et de CDynLinkLibrary.
Global extensionDLL doit être déclarée comme illustré. Contrairement à la version 16 bits de MFC, vous pouvez allouer de la mémoire et appeler des fonctions MFC pendant ce temps, puisque la MFCxx.DLL est complètement initialisé au moment de que votre fonction DllMain est appelée.
Partage de ressources et de Classes
Les DLL d'extension MFC simples besoin seulement exporter quelques fonctions de faible bande passante à la demande du client et rien de plus. Plus : interface utilisateur intensif dll voudrez exporter les ressources et les classes C++ à l'application cliente.
Exportation des ressources se fait à travers une liste de ressources. Chaque application est une liste liée individuellement d'objets CDynLinkLibrary . Lorsque vous cherchez une ressource, la plupart des implémentations MFC standard que charge ressources examinent d'abord le module de ressources actuelles (AfxGetResourceHandle) et si marche pas trouvé la liste des objets CDynLinkLibrary essayer de charger la ressource demandée.
Création dynamique d'objets C++ donné un nom de classe C++ est similaire. Le mécanisme de désérialisation des objets MFC doit avoir tous les objets CRuntimeClass inscrits de sorte qu'il peut reconstruire en créant dynamiquement objet C++ du type requis basé sur ce qui a été stocké précédemment.
Si vous souhaitez que l'application cliente d'utiliser des classes dans la DLL d'extension qui sont DECLARE_SERIAL, alors vous devrez exporter vos classes pour être visible à l'application cliente. Cela se fait aussi en parcourant la liste CDynLinkLibrary.
Dans le cas de l'exemple MFC Advanced Concepts DLLHUSK, la liste ressemble à
tête - > ; DLLHUSK.EXE - ou - DLLHUSK.EXE
| |
TESTDLL2.DLL TESTDLL2.DLL
| |
TESTDLL1.DLL TESTDLL1.DLL
| |
MFCO42D.DLL |
| |
MFCD42D.DLL |
| |
MFC42D.DLL MFC42.DLL
La MFCxx.DLL est habituellement le dernier sur les ressources et la liste de la classe. MFCxx.DLL comprend l'ensemble des ressources MFC standards, y compris les chaînes rapides pour tous les ID de commande standard. Ce qui le place à la queue de la liste permet de DLL et l'application cliente elle-même de ne pas avoir un leur propre copie des ressources MFC standards, mais de compter sur des ressources partagées dans la MFCxx.DLL plutôt.
Fusionner les ressources et les noms de classe de toutes les dll dans l'espace de nom de l'application cliente a le désavantage que vous devrez faire attention à ce qu'ID ou vous cueillez les noms. Vous pouvez bien entendu désactiver cette fonctionnalité en exportant ne pas vos ressources ou un objet CDynLinkLibrary à l'application cliente. La exemple DLLHUSK gère l'espace de noms de ressources partagées à l'aide de plusieurs fichiers d'en-tête. Consultez Technical Note 35 pour plus de conseils sur l'utilisation de fichiers de ressources partagées.
Initialisation de la DLL
Comme mentionné ci-dessus, vous voudrez généralement créer un objet CDynLinkLibrary afin d'exporter vos classes et ressources de l'application cliente. Vous devrez fournir un point d'entrée exportés pour initialiser la DLL. Minimale, c'est une routine void qui ne prend aucun argument et ne renvoie rien, mais il peut être n'importe quoi que vous aimez.
Chaque demande de client qui souhaite utiliser votre DLL doit appeler cette routine d'initialisation, si vous utilisez cette approche. Vous peut également affecter cet objet CDynLinkLibrary dans votre fonction DllMain juste après l'appel de AfxInitExtensionModule.
La routine d'initialisation doit créer un objet CDynLinkLibrary dans le tas de l'application actuelle, branché à votre information de DLL d'extension. Cela peut se faire par ce qui suit:
extern « C » extern void WI&NAPI InitXxxDLL()
{
nbsp ; Nouvelle CDynLinkLibrary(extensionDLL) ;
}
Le nom systématique, InitXxxDLL dans cet exemple, peut être tout ce que vous voulez. Il n'a besoin d'être extern “C” , mais faisant rend tellement plus facile de maintenir la liste d'exportation.
&Notenbsp ; Si vous utilisez votre extension DLL à partir d'une DLL régulière, vous devez exporter cette fonction d'initialisation. Cette fonction doit être appelée à partir de la DLL normale avant d'utiliser les classes DLL d'extension ou de ressources.
Exportation des entrées
Le moyen simple pour exporter vos classes est d'utiliser __declspec (dllimport) et __declspec (dllexport) sur chaque classe et de la fonction globale que vous souhaitez exporter. Cela rend beaucoup plus facile, mais est moins efficace que la désignation de chaque point d'entrée (décrit ci-dessous) puisque vous avez moins de contrôle sur les fonctions get exportées et que vous ne peut pas exporter des fonctions par ordinal. Il s'agit de la méthode TESTDLL1 et TESTDLL2 utilisent pour exporter leurs entrées.
Une méthode plus efficace (et la méthode utilisée par MFCxx.DLL) sont d'exporter chaque entrée à la main en nommant chaque entrée dans le.Fichier DEF. Étant donné que nous exportons des exportations sélectives de notre DLL (c'est pas tout), nous devons décider laquelle interfaces particuliers nous souhaitons exporter. C'est difficile puisque vous devez spécifier les noms déformés à l'éditeur de liens sous la forme d'entrées dans le.Fichier DEF. N'exporter toutes les classes C++ sauf si vous avez vraiment besoin d'avoir un lien symbolique pour elle.
Si vous avez essayé l'exportation C++ classes avec un.DEF fichier avant, vous pouvez développer un outil pour générer automatiquement de cette liste. Cela peut être fait à l'aide d'un processus de liaison de deux étapes. Lier votre DLL une fois avec aucune exportation et permettre à l'éditeur de liens de générer un.Fichier de mappage. Le.Fichier de mappage peut être utilisé pour générer une liste de fonctions qui doivent être exportés, donc avec quelques munging, il peut être utilisé pour générer vos entrées d'exportation pour votre.Fichier DEF. La liste d'exportation pour MFCxx.DLL et OLE et les DLL d'extension de base de données, plusieurs milliers en nombre, a été générée avec un tel processus (bien qu'il n'est pas complètement automatique et nécessite une main réglage de temps en temps).
CWinApp vs CDynLinkLibrary
Une DLL d'Extension MFC n'a pas un CWinApp-dérivé de l'objet de son propre ; au lieu de cela, il doit travailler avec le CWinApp-dérivé de l'objet de la demande du client. Cela signifie que l'application cliente possède la pompe de messages principale, la boucle de marche au ralenti et ainsi de suite.
Si votre DLL d'Extension MFC doit maintenir des données supplémentaires pour chaque application, vous pouvez dériver une nouvelle classe de CDynLinkLibrary et créer dans le InitXxxDLL la routine décrit ci-dessus. Lors de l'exécution, la DLL peut vérifier la liste de l'application actuelle des objets CDynLinkLibrary pour trouver la personne que DLL d'extension particulier.
L'utilisation des ressources dans votre implémentation de DLL
Comme mentionné ci-dessus, la charge de ressource par défaut marcheront à la liste des objets CDynLinkLibrary chercher le premier fichier EXE ou DLL qui possède la ressource demandée. Toutes les API de MFC ainsi que tout le code interne utilise AfxFindResourceHandle pour parcourir la liste des ressources pour trouver n'importe quelle ressource, n'importe où il peut résider.
Si vous souhaitez seulement charger les ressources d'un lieu spécifique, utilisez les API AfxGetResourceHandle et AfxSetResourceHandle pour enregistrer l'ancien handle et définir le nouveau handle. N'oubliez pas de restaurer l'ancien handle de ressource avant que vous retournez à l'application cliente. L'échantillon TESTDLL2 utilise cette approche pour charger explicitement un menu.
Parcourir la liste d'a les inconvénients qu'il est légèrement plus lente et nécessite la gestion des chaînes d'ID de ressource. Il a l'avantage qu'une application cliente qui relie plusieurs DLL d'extension peut utiliser toute ressource DLL fournie sans avoir à spécifier le handle d'instance DLL. AfxFindResourceHandle est une API utilisée pour parcourir la liste des ressources pour rechercher une correspondance donnée. Elle prend le nom et le type d'une ressource et retourne le handle de ressource où on a d'abord trouvé (ou NULL).
Exigences de la demande
Une application qui utilise la version partagée des MFC doit suivre quelques règles simples:
Bâtir avec l'environnement de développement
Si vous utilisez le makefile interne avec la plus grande partie de la valeur par défaut standard, vous pouvez facilement changer le projet de construire la version de la DLL.
L'étape suivante suppose que vous avez une application MFC fonctionne correctement, liée avec NAFXCWD.LIB (pour debug) et NAFXCW.LIB (pour la vente au détail) et que vous souhaitez convertir pour utiliser la version partagée de la bibliothèque MFC. Vous utilisez l'environnement de Visual C++ et disposez d'un fichier de projet interne.
Bâtiment avec NMAKE
Si vous utilisez la fonctionnalité de makefile externe de la Visual C++ ou utilisez NMAKE directement, vous devrez modifier votre makefile à l'appui du compilateur et options de l'éditeur de liens
Indicateurs de compilateur requis:
/ D_AFXDLL/MD
/ D_AFXDLL
Les en-têtes MFC standards ont besoin de ce symbole à définir:
/MD
L'application doit utiliser la version DLL de la bibliothèque runtime c
Tous les autres indicateurs de compilateur suivent les valeurs par défaut MFC (par exemple _DEBUG pour débogage).
Modifier la liste de l'éditeur de liens des bibliothèques. Changement NAFXCWD.LIB de MFCxxD.LIB et NAFXCW du changement.LIB de MFCxx.LIB. Ajouter MFCOxx[U]D.LIB, MFCDxx[U]D.LIB et MFCNxx[U]D.LIB comme il convient (nécessaire pour utilisation des MFC/OLE, base de données ou réseau de classes). Remplacer la LIBC.LIB avec MSVCRT.LIB. Comme avec toute autre bibliothèque MFC, il est important que la MFCxxD.LIB est placé avant les bibliothèques runtime c.
Éventuellement, ajouter /D_AFXDLL à vos deux détail et déboguer les options du compilateur de ressources (celui qui compile en fait les ressources avec/r). Cela rend votre exécutable final plus petites en partageant les ressources qui sont présents dans les DLL MFC.
Une reconstruction complète est nécessaire après que ces modifications sont apportées.
Construction des échantillons
La plupart des exemples de programmes MFC peut être construite à partir de Visual C++ ou un MAKEFILE NMAKE compatible avec partage de la ligne de commande.
Pour convertir un de ces échantillons d'utiliser MFCxx.DLL, vous pouvez charger le.MAK de fichiers dans Visual C++ et définir les options du projet, tel que décrit ci-dessus. Si vous utilisez la version NMAKE, vous pouvez spécifier « AFXDLL = 1 "sur le NMAKE ligne de commande et qui construira l'échantillon en utilisant les bibliothèques MFC partagées.
L'exemple MFC Advanced Concepts DLLHUSK est construite avec la version DLL de MFC. Cet exemple illustre non seulement comment générer une application liée avec MFCxx.DLL, mais il illustre également les autres caractéristiques de l'option d'emballage de DLL MFC tels que les DLL d'Extension MFC décrit plus loin dans cette note technique.
Notes de l'emballage
La version des DLL (MFCxx [U].DLL) sont librement redistribuables. La version de débogage des DLL ne sont pas librement redistribuable et doit être utilisé uniquement pendant le développement de votre application.
Le débogage de la dll sont fournis avec les informations de débogage. En utilisant le débogueur de Visual C++, vous pouvez retracer l'exécution de votre application ainsi que la DLL. Les DLL de sortie (MFCxx [U].DLL) ne contiennent pas d'informations de débogage.
Si vous personnalisez ou reconstruisez les dll, alors vous devez appeler leur quelque chose autre que le fichier « MFCxx » la SRC MFC MFCDLL.MAK décrit les options de build et contient la logique pour renommer la DLL. Cette règle s'applique également aux MFC/OLE, base de données et réseau de DLL qui sont construits par MFCOLE.MAK, MFCDB.MAK et MFCNET.MAK, respectivement. Renommer les fichiers est nécessaire, étant donné que ces DLL est potentiellement partagées par de nombreuses applications MFC. Avoir votre version personnalisée de la DLL MFC remplacer ceux installés sur le système peut briser une autre application MFC à l'aide de la DLL MFC partagées.
Reconstruire les DLL MFC n'est pas recommandé.
La section suivante décrit comment la DLL MFC (MFCxx.DLL et MFCxxD.DLL) est mis en œuvre. Comprendre que les détails ici ne sont pas aussi importants si tous vous voulez faire sont utiliser la DLL MFC avec votre application. Les détails ici ne sont pas essentielles pour comprendre comment écrire une DLL d'extension MFC, mais comprendre cette implémentation peut vous aider à écrire vos propres DLL.
Aperçu de la mise en œuvre
La DLL MFC est vraiment un cas particulier d'une DLL d'Extension MFC, comme décrit ci-dessus. Elle a un très grand nombre d'exportations pour un grand nombre de classes. Il y a quelques choses supplémentaires que nous faisons dans la DLL MFC qui la rendent encore plus spécial qu'une DLL d'Extension régulière.
Win32 est la plupart du travail
La version 16 bits de MFC pour un certain nombre de techniques spéciales, y compris les données per-app sur le segment de pile, des segments spéciaux créés par certains code de l'assembly du 80 x 86, contextes d'exception par processus et d'autres techniques. Win32 supporte directement les données par processus dans une DLL, qui est ce que vous voulez la plupart du temps. La plupart du temps MFCxx.DLL est juste NAFXCW.LIB emballé dans une DLL. Si vous regardez le code source MFC, vous trouverez très peu # ifdef _AFXDLL, puisqu'il y a très peu de cas particuliers qui doit être apportées. Les cas particuliers qui y sont spécifiquement pour s'occuper de Win32 sur Windows 3.1 (autrement connu comme Win32s). Win32s n'est pas soutien par processus DLL données directement si la DLL MFC doivent utiliser le thread local storage (TLS) Win32 API pour obtenir des données locales de processus.
Impact sur les Sources de la bibliothèque, les fichiers supplémentaires
L'impact de la version _AFXDLL sur les sources de bibliothèque de classe MFC normales et les en-têtes est relativement mineure. Il existe un fichier de version spéciale (AFXV_DLL.H) ainsi qu'un fichier d'en-tête supplémentaire (AFXDLL_.H) inclus par le AFXWIN principal.En-tête de H. Le AFXDLL_.En-tête h comprend la classe CDynLinkLibrary et autres détails d'implémentation de _AFXDLL les applications et les DLL d'Extension MFC. Le AFXDLLX.En-tête h est prévu pour la construction de la DLL d'Extension MFC (voir ci-dessus pour plus de détails).
Les sources régulières à la bibliothèque MFC dans MFC SRC ont certains code conditionnel supplémentaire sous le # ifdef _AFXDLL . Un fichier source supplémentaire (DLLINIT.RPC) contient le code de l'initialisation de DLL supplémentaire et autre colle pour la version partagée des MFC.
Afin de construire la version partagée des MFC, les fichiers supplémentaires sont fournis. (Voir ci-dessous pour plus d'informations sur la façon de construire la DLL).
Construction de la DLL MFC
Reconstruction de la DLL MFC est volontairement difficile, si vous pensez que deux fois (ou trois fois) avant de le faire. Si vous comprenez les éventuels problèmes d'emballage et des restrictions de redistribution décrites ci-dessous et vous encore vraiment besoin reconstruire la DLL MFC, vous pouvez.
Le MFCDLL.Fichier MAK construira la DLL de débogage avec les informations CodeView:
NMAKE /f mfcdll.mak DEBUG = 1 LIBNAME = MYMFC
Le MFCDLL.Fichier MAK construira la DLL de sortie sans CodeView info:
NMAKE /f mfcdll.mak DEBUG = 0 LIBNAME = MYMFC
(de même, vous utilisez MFCOLE.MAK, MFCDB.MAK et MFCNET.MAK pour construire le MFCOxxD.DLL, MFCDxxD.DLL et MFCNxxD.DLL--les DLL qui contiennent la MFC/OLE, base de données et les classes de réseau)
Il construira une version privée de la DLL MFC dans le répertoire SRC MFC avec les noms MFCxx.DLL et MFCxxD.DLL standards. Vous devez les copier dans un endroit approprié sur votre chemin vers la DLL de nouveau. Le MFCDLL.MAK makefile sera aussi reconstruire les bibliothèques d'importation (MFCxx.LIB et MFCxxD.LIB) et les placer dans le répertoire LIB MFC standard. Ceci remplacera les bibliothèques prédéfinies de MFCxx.LIB et MFCxxD.LIB, donc veuillez être attentif.
Si vous souhaitez redistribuer une version modifiée de la bibliothèque MFC DLL, assurez-vous de changer le nom de la DLL dans le MFCDLL.MAK makefile et les deux.Fichiers DEF. Voir le makefile MFCDLL.MAK pour plus d'info.
Vous pouvez modifier la Bibliothèque et redistribuer une vente au détail (/ version) de votre bibliothèque modifiée uniquement si vous le renommez pour autre chose que MFCxx.DLL. Vous ne peut redistribuer la version debug de l'un ou le débogage bâti préconstruit ou personnalisé DLL.
Ces restrictions de redistribution sont principalement afin d'éviter une prolifération de non-standard et potentiellement virus contenant des dll. idéalement vous ne devriez pas avoir à reconstruire les dll et si vous redistribuez votre application avec la MFCxx.DLL prédéfinies fournies avec le produit Visual C++, vous éviterez beaucoup de problèmes pour vous et vos utilisateurs.
Gestion de la mémoire
Une application à l'aide de MFCxx.DLL utilise un allocateur de mémoire commun fourni par MSVCRTxx.DLL, la DLL runtime c partagée. L'application, toutes les DLL d'extension, ainsi que les DLL MFC eux-mêmes, utilisez cet allocateur de mémoire partagée. En utilisant une DLL partagée pour l'allocation de mémoire, les DLL MFC peuvent allouer de la mémoire qui est plus tard libérée par l'application ou vice versa. Parce que tant l'application et la DLL doivent utiliser l'allocateur de même, vous devez substituer pas le C++ global operator new ou operator delete. Les mêmes règles s'appliquent au reste des routines d'allocation mémoire runtime C (telles que malloc, realloc, libre, etc.).
Ordinaux et classe __declspec (dllexport) et nom de la DLL
Nous n'utilisons pas la class __declspec (dllexport) fonctionnalités du compilateur C++. Au lieu de cela, une liste des exportations est incluse avec les sources de bibliothèque de classe (MFCxx.DEF et MFCxxD.DEF). Seulement ces jeu de sélectionner des points d'entrée (fonctions et données) sont exportés. Autres symboles, tels que les fonctions de mise en œuvre des MFC ou de classes, ne sont pas exportés toutes les exportations sont réalisées par ordinal sans un nom de chaîne dans la table nom résident ou non-résident .
À l'aide de class __declspec (dllexport) peut être une alternative viable pour la construction de petites DLL, mais dans le cas d'une DLL importante comme les MFC, exporter le mécanisme par défaut a l'efficacité et la capacité limite .
Quelle est cette tous les moyens que nous pouvons emballer une grande quantité de fonctionnalités dans la version MFCxx.DLL qui est seulement environ 800 Koctets sans compromettre d'exécution ou la vitesse de chargement. MFCxx.DLL aurait été 100 K plus grande si cette technique n'avait pas été utilisé.Cela rend également possible d'ajouter des points d'accès supplémentaires à la fin de la.Fichier DEF pour permettre la gestion des versions simple sans compromettre l'efficacité de vitesse et de la taille de l'exportation par ordinal. Révisions de la version principale de la bibliothèque de classes MFC vont changer le nom de la bibliothèque. C'est MFC30.DLL est la DLL redistribuable contenant la version 3.0 de la bibliothèque de classes MFC. Une mise à niveau de cette DLL, dire, dans un hypothétique 3.1 de MFC, la DLL serait nommée MFC31.DLL à la place. Encore une fois, si vous modifiez le code source MFC pour produire une version personnalisée de la DLL MFC, veuillez utiliser un nom différent (et préférence sans « MFC ») dans le nom.
&Notes techniques par le numéro |nbsp ; Notes techniques par catégorie