TN033: DLL-Version von MFC

Diese Applikationsschrift beschreibt, wie können Sie die MFCxx.DLL und MFCxxD.DLL (wobei x für die MFC-Versionsnummer steht) freigegebene dynamic Link Librarys mit MFC-Anwendungen und Erweiterungs-DLLs. Weitere Informationen über reguläre DLLs finden Sie unter Using MFC as Part of a DLL.

Diese technische Hinweis umfasst drei Aspekte von DLLs. Die letzten beiden sind für fortgeschrittene Benutzer:

Wenn Sie erstellen eine DLL mit MFC, die mit MFC fremden Anwendungen verwendet werden kann (Dies ist eine reguläre DLL genannt) interessiert sind, finden Sie in technischer Hinweis 11.

Übersicht über MFCxx.DLL Unterstützung: Terminologie und Dateien

Reguläre DLL: Verwenden Sie eine reguläre DLL um eine eigenständige DLL mit der MFC-Klassen erstellen. Schnittstellen über die App/DLL-Grenze sind "C" Schnittstellen, und die Client-Anwendung muss nicht zu einer MFC-Anwendung.

Dies ist die Version der DLL-Unterstützung in MFC 1.0 unterstützt. Es ist beschrieben in technischer Hinweis 11 und das MFC Advanced Concepts-Beispiel DLLTRACE.

Hinweis&Nbsp;  Visual C++ Version 4.0, der Begriff USRDLL ist veraltet und wurde ersetzt durch eine reguläre DLL, die statisch mit MFC verknüpft. Sie können auch eine reguläre DLL erstellen, die dynamisch mit MFC verknüpft.

MFC 3.0 (und höher) unterstützt reguläre DLLs mit der neuen Funktionalität einschließlich der OLE und Datenbank-Klasse.

AFXDLL: Dies wird auch als die gemeinsam genutzte Version der MFC-Bibliotheken bezeichnet. Dies ist die neue DLL-Unterstützung in MFC 2.0 hinzugefügt. Die MFC-Bibliothek selbst ist in einer Reihe von DLLs (siehe unten) und eine Client-Anwendung oder DLL dynamisch verknüpft die DLLs, die sie benötigt. Schnittstellen über die Anwendung/DLL-Grenze sind C + / MFC Klassenschnittstellen. Die Clientanwendung muss eine MFC-Anwendung sein. Dies unterstützt alle MFC 3.0-Funktionalität (Excption: UNICODE ist für die Datenbankklassen nicht unterstützt).

Hinweis&Nbsp;  Als von Visual C++, Version 4.0 wird dieser DLL-Typ als "Erweiterungs-DLL." bezeichnet

Dieser Hinweis wird MFCxx.DLL verwenden, um zu den gesamten, die MFC-DLL festgelegt, umfasst:

Hinweis&Nbsp;  Die MFCSxx [U] [D].LIB-Bibliotheken werden verwendet Verbindung mit der MFC freigegebene DLLs. Diese Bibliotheken enthalten Code, der auf die Anwendung oder DLL statisch verknüpft werden muss.

Eine Anwendung eine Verbindung zu den entsprechenden Importbibliotheken:

Einer "MFC-Erweiterungs-DLL" ist eine DLL auf MFCxx.DLL gebaut (bzw. gemeinsam genutzte die anderen MFC-DLLs). Hier greift die MFC-Komponentenarchitektur. Wenn Sie eine nützliche Klasse aus einer MFC-Klasse ableiten, oder eine andere MFC-wie Toolkit erstellen, können Sie es in einer DLL platzieren. Die DLL MFCxx.DLL, verwendet wie die ultimative Client-Anwendung. Dies ermöglicht, wiederverwendbare Blatt Klassen, wiederverwendbare Basisklassen und wiederverwendbare Ansicht und Dokumentenklassen.

Hinweis&Nbsp;  Es ist nicht notwendig, mit den MFCOxx [U] D, D MFCDxx [U] oder MFCNxx [U] D Debuggen Bibliotheken verknüpfen, es sei denn, die Anwendung, die MFC/OLE, Datenbank oder Netzwerkklassen verwendet.

Vor- und Nachteile

Warum sollten Sie verwenden die gemeinsam genutzte MFC-version?

Warum sollten Sie nicht verwenden die gemeinsam genutzte MFC-version:

Wie Sie eine MFC-Erweiterungs-DLL schreiben

Eine MFC-Erweiterungs-DLL ist eine DLL, die mit Klassen und Funktionen geschrieben, die Funktionen der MFC-Klassen zu verschönern. OLE und Datenbank Debuggen unterstützt DLLs (MFCOxxD.DLL und MFCDxxD.DLL) sind Beispiele für MFC-Erweiterungs-DLLs, insofern sie MFCxxD.DLL verwenden. Eine MFC-Erweiterungs-DLL verwendet die gemeinsam genutzte MFC-DLLs auf die gleiche Weise, die eine Anwendung, mit einigen zusätzlichen Überlegungen verwendet:

Diese Überlegungen werden im folgenden ausführlicher beschrieben. Sie sollten auch beziehen sich auf die MFC Advanced Concepts-Beispiel DLLHUSK da es illustriert

Die Client-Anwendung und alle Erweiterungs-DLLs müssen die gleiche Version von MFCxx.DLL verwenden. Sollten Sie der Konvention der MFC-DLL und sowohl Debug- und Einzelhandel (/ Version) die Erweiterungs-DLL-Version. Dies ermöglicht Clientprogrammen Debug und Retail Versionen ihrer Anwendungen erstellen und verknüpfen Sie sie mit dem entsprechenden Debug oder Einzelhandel Fassung über alle DLLs.

Hinweis&Nbsp;  Aufgrund von C++ Namensfrage-mangeln und Export kann die Liste exportieren aus einer Erweiterungs-DLL unterscheiden zwischen den Debug und Retail Versionen der gleichen DLL und DLLs für verschiedene Plattformen. Der Einzelhandel MFCxx.DLL hat etwa 2000 Einstiegspunkte exportiert; das Debug MFCxxD.DLL hat etwa 3000 Einstiegspunkte exportiert.

Kurzer Hinweis auf Speichermanagement

Der Abschnitt mit dem Titel "Memory Management" am Ende von diesem technischen Hinweis beschreibt die Implementierung der MFCxx.DLL mit gemeinsam genutzte MFC-Version. Die Informationen, die Sie, dass um nur eine Erweiterungs-DLL zu implementieren wissen müssen ist hier beschrieben.

MFCxx.DLL und alle Erweiterungs-DLLs, die in den Adressbereich einer Clientanwendung geladen werden dieselbe Speicherreservierungsfunktion, Ressourcenauslastung und andere "globale" MFC-Zustände verwenden, als wären sie in der gleichen Anwendung. Dies ist bedeutsam, weil die MFC - fremde DLL-Bibliotheken und reguläre DLLs, die statisch mit MFC verknüpfen das genaue Gegenteil tun und haben jede DLL Zuweisung von einen eigenen Speicherpool.

Wenn eine Erweiterungs-DLL Speicher reserviert, kann dann der Speicher frei mit jeder anderen Anwendung zugeordnete Objekt kombiniert werden. Außerdem stürzt eine Anwendung, die MFC-Laufzeitbibliotheken verwendet, wird der Schutz des Betriebssystems die Integrität jeder andere MFC Application-sharing-DLL beibehalten.

Ebenso werden andere "globale" MFC-Zustände, wie die aktuelle ausführbare Datei zum Laden von Ressourcen aus, auch zwischen der Clientanwendung und alle MFC-Erweiterungs-DLLs sowie MFCxx.DLL selbst geteilt.

Erstellen einer Erweiterungs-DLL

Anwendungs-Assistenten können Sie ein MFC-Erweiterungs-DLL-Projekt erstellen, und es generiert automatisch die geeigneten Linkereinstellungen für Compiler und. Es war auch eine DllMain -Funktion generiert, die Sie ändern können.

Wenn Sie ein vorhandenes Projekt in einer MFC-Erweiterungs-DLL konvertieren, beginnen Sie mit den Standardregeln für das Erstellen einer Anwendungs mithilfe der gemeinsam genutzten MFC-Version, dann gehen Sie wie folgt:

Ändern Ihren Header-Dateien

Das Ziel der Erweiterung DLL ist in der Regel einige allgemeine Funktionen in eine oder mehrere Anwendungen zu exportieren, die diese Funktion verwenden können. Dies läuft darauf hinaus, Exportieren von Klassen und globalen Funktionen, die für Ihre Clientanwendungen verfügbar sind.

Um dies zu tun müssen Sie sicherstellen, dass jeder Memberfunktionen als importieren oder Exportieren von entsprechend markiert ist. Dies erfordert spezielle Deklarationen: __declspec(dllexport) und __declspec(dllimport). Wenn Sie Klassen von der Client-Anwendungen verwendet werden, sollen Sie als __declspec(dllimport)deklariert werden. Wenn die Erweiterungs-DLL selbst gebaut wird, sollten sie als __declspec(dllexport)deklariert werden. Darüber hinaus müssen die Funktionen tatsächlich exportiert werden, so dass die Clientprogramme Sie zur Ladezeit binden,.

Verwenden Sie die gesamte Klasse exportieren, in der Klassendefinition AFX_EXT_CLASS . Dieses Makro wird vom Framework als __declspec(dllexport) definiert, wenn _AFXDLL und _AFXEXT definiert, aber als __declspec(dllimport) definiert _AFXEXT nicht definiert ist. _AFXEXT wird wie oben beschrieben nur definiert, wenn die Erweiterungs-DLL erstellen. Zum Beispiel:

klasse AFX_EXT_CLASS CExampleExport: public CObject
{... class Definition...}

Nicht exportieren die gesamte Klasse

Manchmal können Sie nur die einzelnen erforderlichen Member einer Klasse exportieren möchten. Zum Beispiel, wenn Sie exportieren ein CDialog-abgeleitete Klasse, müssen Sie möglicherweise nur den Konstruktor und den DoModal -Aufruf zu exportieren. Sie können diese Member mithilfe der DLL exportieren.DEF-Datei, aber Sie AFX_EXT_CLASS können auch in viel die gleiche Weise auf die einzelnen Mitglieder, die Sie exportieren müssen.

Zum Beispiel:

 cExampleDialog-Klasse: public CDialog
{
Öffentliche:
 &Nbsp; AFX_EXT_CLASS CExampleDialog();
   AFX_EXT_CLASS Int DoModal();
   / / rest der Klassendefinition
   .
   .
   .
}

Wenn Sie dies tun, können Sie ein zusätzliches Problem stoßen, aufgrund der Tatsache, dass Sie nicht mehr alle Member der Klasse exportieren. Das Problem ist in der Weise, dass MFC Makros die Arbeit. Einige der MFC Hilfsprogramm Makros tatsächlich deklarieren oder definieren Sie Datenmember. Daher müssen diese Datenmember auch aus der DLL exportiert werden.

Beispielsweise ist das DECLARE_DYNAMIC -Makro wie folgt definiert, wenn eine Erweiterungs-DLL:

# define DECLARE_DY&NAMIC(class_name) \
geschützt: \
 Nbsp; statische CRuntimeClass * PASCAL _GetBaseClass(); \
   Öffentliche: \
   statischen AFX_DATA CRuntimeClass-Klasse ## Class_name; \
   virtuelle CRuntimeClass * GetRuntimeClass() const; \

Die Zeile, die "static AFX_DATA" beginnt, wird ein statisches Objekt innerhalb der Klasse deklariert. Diese Klasse korrekt zu exportieren und auf die Common Language Runtime Informationen von einem Client zugreifen.EXE, müssen Sie dieses statische Objekt exportieren. Da das statische Objekt mit dem AFX_DATA-Modifizierer deklariert wird, müssen Sie nur AFX_DATA __declspec(dllexport) werden beim Erstellen der DLL und beim Erstellen des ausführbaren Clients als __declspec(dllimport) definieren.

Wie oben beschrieben, ist AFX_EXT_CLASS bereits auf diese Weise definiert. Sie müssen also nur AFX_DATA die gleiche wie AFX_EXT_CLASS Ihrer Klassendefinition sein neu.

Zum Beispiel:

&Nbsp;  # undef AFX_DATA
   # define AFX_DATA AFX_EXT_CLASS
   Klasse CExampleView: öffentliche CView
   {
     DECLARE_DYNAMIC()
     / /... class Definition...
   };
   # undef AFX_DATA
   # define AFX_DATA

MFC verwendet immer das AFX_DATA -Symbol auf Datenelemente, die es innerhalb seiner Makros definiert, so dass diese Technik für solche Szenarien funktioniert. Zum Beispiel funktioniert es für DECLARE_MESSAGE_MAP.

Hinweis&Nbsp;  Wenn Sie anstelle von ausgewählten Membern der Klasse die gesamte Klasse exportieren, werden statische Datenmember automatisch exportiert.

Das gleiche Verfahren können Sie automatisch den CArchive -Extraktion-Operator für Klassen exportieren, die die DECLARE_SERIAL und IMPLEMENT_SERIAL Makros verwenden. Exportieren der Archiv-Betreiber von Klassendeklarationen Belichtungsreihe (befindet sich in der.H-Datei) mit dem folgenden Code:

# undef AFX_API
# define AFX_API AFX_EXT_CLASS

Lt; Ihre Klassendeklarationen hier >

# undef AFX_API
# define AFX_API

Einschränkungen von _AFXEXT

_AFXEXT Präprozessor Symbol können für Erweiterungs-DLLs Sie, solange Sie nicht mehrere Sicherheitsebenen Erweiterungs-DLLs verfügen. Wenn Sie Erweiterungs-DLLs, die aufrufen oder abgeleitet von Klassen in Ihren eigenen Erweiterungs-DLLs, die dann von der MFC-Klassen abgeleitet werden verfügen, müssen Sie Ihr eigenes Präprozessorsymbol verwenden, um Mehrdeutigkeiten zu vermeiden.

Das Problem ist, dass in Win32 Sie explizit Daten als __declspec(dllexport) deklarieren müssen, wenn es ist aus einer DLL und __declspec(dllimport) exportiert werden, wenn sie aus einer DLL importiert werden soll. Wenn Sie _AFXEXTdefinieren, stellen die MFC-Header sichergestellt, dass AFX_EXT_CLASS korrekt definiert ist.

Wenn Sie über mehrere Schichten verfügen, ist ein Symbol wie AFX_EXT_CLASS nicht ausreichend, da eine Erweiterungs-DLL kann werden neue Klassen exportieren als auch andere Klassen von einer anderen Erweiterungs-DLL importieren. Um dieses Problem zu umgehen, verwenden Sie ein spezielles Präprozessor Symbol gibt an, dass Sie die DLL selbst gegenüber der Verwendung der DLL erstellen. Genommen Sie an, zwei Erweiterungs-DLLs A.DLL und B.DLL. Beide exportieren einige Klassen im AH und B.H, beziehungsweise. B.dll verwendet die Klassen von A.DLL. Die Headerdateien würden wie folgt aussehen:

/ / AH
# ifdef A_IMPL
 &Nbsp; # define CLASS_DECL_A __declspec(dllexport)
# else
   # define CLASS_DECL_A von __declspec(dllimport)
# endif

Klasse CLASS_DECL_A CExampleA: public CObject
{... class Definition...};

/ / B.H
# ifdef d B_IMPL erstellt
   # define CLASS_DECL_B __declspec(dllexport)
# else
   # define CLASS_DECL_B von __declspec(dllimport)
# endif

Klasse CLASS_DECL_B CExampleB: öffentliche CExampleA
{... Klassendefinition..}

Wenn A.DLL erstellt wird, wird es mit/d A_IMPL erstellt und wenn B.DLL erstellt wird, es wird mit / d B_IMPL erstelltgebaut. Separate Symbole für jede DLL verwenden, wird CExampleB exportiert und CExampleA wird beim Erstellen von B.DLL importiert. CExampleA wird beim Erstellen von A.DLL exportiert und importiert, wenn von B.DLL (oder einige andere Client) verwendet.

Diese Art der Schichtung kann nicht erfolgen, wenn die integrierten AFX_EXT_CLASS und _AFXEXT Präprozessor Symbole verwenden. Die oben beschriebene Technik löst dieses Problem in einer Weise nicht im Gegensatz zu die der Mechanismus MFC selbst verwendet, wenn seine OLE, Datenbank und Netzwerk Erweiterungs-DLLs erstellen.

Nicht exportieren die gesamte Klasse

Wieder müssen Sie besonders darauf achten, wenn Sie keine gesamte Klasse exportieren. Sie müssen sicherstellen, dass die erforderlichen Datenelemente erstellt von MFC-Makros korrekt exportiert werden. Dies kann AFX_DATA an Ihre spezifische Klasse Makro ändern. Dies sollte jederzeit durchgeführt werden Sie nicht die gesamte Klasse exportieren.

Zum Beispiel:

/ / AH
# 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

CExampleA-Klasse: public CObject
{
   DECLARE_DYNAMIC()
   CLASS_DECL_A Int SomeFunction();
   //class Definition.
   .
   .
};

# undef AFX_DATA
# define AFX_DATA

DllMain

Im folgenden finden den genauen Code, den Sie für die Erweiterungs-DLL in Ihre wichtigsten Quelldatei platzieren sollte. Es sollte kommen, nachdem die Standard-includes. Beachten Sie, dass wenn Sie AppWizard Startdateien für eine Erweiterungs-DLL erstellen, es eine DllMain für Sie liefert.

# include "afxdllx.h"

statische AFX_EXTE&NSION_MODULE ExtensionDLL;

Extern "C" Int APIENTRY DllMain (HINSTANCE hInstance, DWORD DwReason, LPVOID kombiniert werden)
{
 Nbsp; Wenn (DwReason == DLL_PROCESS_ATTACH)
   {
      / / Extension DLL einmalige Initialisierung If (!AfxInitExtensionModule)
             ExtensionDLL, hInstance))
         return 0;

/ / TODO: hier Weitere Initialisierungsaufgaben ausführen
   }
   elseif (DwReason == DLL_PROCESS_DETACH)
   {
      / / Erweiterungs-DLL pro Prozess Beendigung
      AfxTermExtensionModule(extensionDLL);

/ / TODO: hier andere Cleanuptasks ausführen
   }
   1 zurück;   / / ok
}

Der Aufruf von AfxInitExtensionModule erfasst die Module-Laufzeitklassen (CRuntimeClass -Strukturen) sowie seine Object Factories (COleObjectFactory -Objekte) für die spätere Verwendung, wenn das CDynLinkLibrary -Objekt erstellt wird. Der (optionale) Aufruf von AfxTermExtensionModule kann MFC zur Reinigung die Erweiterungs-DLL jeden Prozess getrennt wird (das geschieht, wenn der Prozess beendet wird oder wenn die DLL aufgrund eines einen Aufruf der FreeLibrary wird) von der Erweiterungs-DLL. Seit die meisten Erweiterungs-DLLs werden nicht dynamisch geladen (in der Regel, wenn sie verbunden über ihre Importbibliotheken), der Aufruf von AfxTermExtensionModule ist normalerweise nicht erforderlich.

We&nn die Anwendung lädt und Erweiterungs-DLLs dynamisch freigibt, müssen Sie AfxTermExtensionModule wie gezeigt above.nbsp aufrufen; Außerdem müssen Sie AfxLoadLibrary und AfxFreeLibrary (anstelle der Win32-Funktionen LoadLibrary und FreeLibrary) verwenden, wenn Ihre Anwendung mehrere Threads verwendet. Verwendung von AfxLoadLibrary und AfxFreeLibrary stellt sicher, dass der starten und Herunterfahren Code, der ausgeführt wird, wenn die Erweiterungs-DLL geladen und entladen wird den globalen MFC-Zustand nicht beschädigt wird.

Die Header-Datei AFXDLLX.H enthält spezielle Definitionen für Strukturen, die in Erweiterungs-DLLs, z. B. die Definitionen für AFX_EXTENSION_MODULE und CDynLinkLibrary verwendet.

Die globale ExtensionDLL muss deklariert werden, wie gezeigt. Im Gegensatz zu den 16-Bit-Version von MFC können Sie Speicher zuweisen und MFC-Funktionen aufrufen, während dieser Zeit, da die MFCxx.DLL von der Zeit vollständig initialisiert ist, die Ihre DllMain aufgerufen wird.

Gemeinsame Nutzung von Ressourcen und Klassen

Einfache MFC-Erweiterungs-DLLs müssen nur ein paar Low-Bandwidth-Funktionen in die Clientanwendung, und nichts mehr exportieren. Weitere Benutzeroberfläche intensive DLLs können Ressourcen und C++-Klassen an die Clientanwendung zu exportieren möchten.

Exportieren von Ressourcen erfolgt über eine Ressourcenliste. Jede Anwendung ist eine einfach verknüpfte Liste mit CDynLinkLibrary -Objekten. Wenn Sie eine Ressource, die meisten der standard-MFC-Implementierungen suchen, dass Ressourcen laden zunächst die aktuellen Ressource-Modul (AfxGetResourceHandle) aussehen und wenn nicht zu Fuß die Liste der CDynLinkLibrary Objekte, die zum Laden der angeforderten Ressource.

Dynamische Erstellung von C++-Objekten, die eine C++-Klasse Namen ähnelt. Der Mechanismus zur Deserialisierung von MFC-Objekten muss aller CRuntimeClass -Objekte registriert, sodass es rekonstruieren kann, indem Sie dynamisch C++-Objekt des erforderlichen Typs basierend auf was zuvor gespeichert wurde.

Wenn Sie möchten die Client-Anwendung mithilfe von Klassen in der Erweiterungs-DLL, die DECLARE_SERIALsind, dann müssen Sie Exportieren von Klassen für die Clientanwendung sichtbar sein. Dies geschieht auch zu Fuß die CDynLinkLibrary -Liste.

Für das Beispiel MFC Advanced Concepts DLLHUSK, die Liste sieht in etwa wie

kopf - ≫   DLLHUSK.EXE - oder - DLLHUSK.EXE
               |                      |
          TESTDLL2.DLL TESTDLL2.DLL
               |                      |
          TESTDLL1.DLL TESTDLL1.DLL
               |                      |
           MFCO42D.DLL                |
               |                      |
           MFCD42D.DLL                |
               |                      |
            MFC42D.DLL DATEI MFC42.DLL

Die MFCxx.DLL ist in der Regel letzten in der Ressourcen- und Klassenliste. MFCxx.DLL umfasst alle standard MFC-Ressourcen, einschließlich Eingabeaufforderungs-Zeichenfolgen für alle Standardbefehls-IDs. Platzieren es an das Ende der Liste kann DLLs und die Clientanwendung selbst nicht haben eine eigene Kopie der standard MFC-Ressourcen, sondern verlassen sich auf die freigegebenen Ressourcen in MFCxx.DLL statt.

Zusammenführen von Ressourcen und Klassennamen aller DLLs in der Clientanwendung Namensraum hat den Nachteil, die Sie vorsichtig sein, welche IDs müssen oder Namen, die Sie auswählen. Natürlich können Sie diese Funktion deaktivieren, indem Sie nicht exportieren Ihre Ressourcen oder ein CDynLinkLibrary -Objekt an die Clientanwendung. Die DLLHUSK -Beispiel der freigegebenen Ressource Name-Space mithilfe mehrerer Headerdateien verwaltet. Finden Sie unter technischer Hinweis 35 für weitere Tipps zur Verwendung von freigegebenen Ressourcendateien.

Die DLL initialisieren

Wie bereits erwähnt, werden Sie gewöhnlich ein CDynLinkLibrary -Objekt erstellen, um Ihre Ressourcen und Klassen an die Clientanwendung zu exportieren. Sie müssen ermöglichen exportierter Einstiegspunkt für die DLL initialisiert werden. Minimal ist nichtig-Routine, die keine Argumente und gibt nothing zurück kann, aber es alles, was Sie mögen.

Jede Clientanwendung, die die DLL verwenden möchte muss diese Initialisierungsroutine aufrufen, wenn Sie diesen Ansatz verwenden. Sie können auch das CDynLinkLibrary -Objekt in Ihrer DllMain zuordnen, nur nach dem Aufruf von AfxInitExtensionModule.

Die Initialisierungsroutine muss ein CDynLinkLibrary -Objekt in der aktuellen Anwendung Heap, verdrahtet bis auf die Erweiterungs-DLL-Informationen erstellen. Dies kann mit den folgenden:

extern "C" Extern void WI&NAPI InitXxxDLL()
{
 Nbsp; neue CDynLinkLibrary(extensionDLL);
}

Routinenname, InitXxxDLL in diesem Beispiel kann alles sein, was Sie wollen. Es muss nicht sein extern “C” , aber tun, so macht der Exportliste einfacher zu verwalten.

Hinweis&Nbsp;  Wenn Sie die Erweiterungs-DLL aus einer regulären DLL verwenden, müssen Sie diese Initialisierungsfunktion exportieren. Diese Funktion muss von der regulären DLL aufgerufen werden, bevor Sie jede Erweiterung DLL Klassen oder Ressourcen.

Einträge exportieren

Der einfache Weg zu Ihren Klassen exportieren ist die Verwendung von __declspec(dllimport) und __declspec(dllexport) für jede Klasse und globale Funktion, die Sie exportieren möchten. Dies macht es viel einfacher, aber ist weniger effizient als die Benennung jeder Einstiegspunkt (siehe unten), da Sie weniger Kontrolle haben über welche Funktionen exportiert und können nicht die Funktionen durch Ordnungszahl exportiert. Dies ist die Methode, die TESTDLL1 und TESTDLL2 verwenden, exportieren Sie ihre Einträge.

Eine effizientere Methode (und die Methode MFCxx.DLL) ist jeder Eintrag Exportieren von hand durch die Benennung jeder Eintrag in der.DEF-Datei. Da wir aus unserer DLL (das heißt, nicht alles) selektiven Export exportieren, müssen wir entscheiden, welche bestimmten Schnittstellen Wir exportieren möchten. Dies ist schwierig, da Sie die ergänzten Namen für den Linker, in Form von Einträgen in angeben müssen der.DEF-Datei. Exportieren Sie keine C++-Klassen, es sei denn, Sie wirklich brauchen, um einen symbolischen Link dafür haben.

Wenn Sie versucht haben, Exportieren von C++-Klassen mit ein.DEF-Datei vor, Sie können ein Tool zum Generieren dieser Liste automatisch entwickeln wollen. Dies kann mit einem zweistufigen Verbindung Prozess. Verknüpfen Ihre DLL einmal mit keine Exporte, und ermöglichen den Linker zum Generieren einer.MAP-Datei. Die.MAP-Datei kann verwendet werden, um eine Liste der Funktionen, die exportiert werden sollen, zu generieren, damit mit einigen verunstalten, es verwendet werden kann, Ihre EXPORT-Einträge für generiert Ihr.DEF-Datei. Der Exportliste für MFCxx.DLL und OLE und Datenbank-Erweiterungs-DLLs, mehrere tausend an der Zahl, war mit so einem Prozess generiert, (obwohl es nicht völlig automatisch ist und erfordert einige Hand Optimierung jeder einmal in eine Weile).

CWinApp vs. CDynLinkLibrary

Eine MFC-Erweiterungs-DLL keine CWinApp-abgeleitete Objekt eigene; Stattdessen muss es funktionieren mit der CWinApp-abgeleitete Objekt der Clientanwendung. Dies bedeutet, dass die Clientanwendung die Haupt-Meldungsverteilschleife, die Leerlaufschleife usw. besitzt.

Wenn Ihr MFC-Erweiterungs-DLL zusätzliche Daten für jede Anwendung verwalten muss, können Sie eine neue Klasse von CDynLinkLibrary ableiten und in der InitXxxDLL Routine beschreiben oben erstellen. Wenn Sie ausführen, kann die DLL der aktuellen Anwendung Liste mit CDynLinkLibrary -Objekten, die für diesen bestimmten Erweiterungs-DLL finden überprüfen.

Verwenden von Ressourcen in Ihrer DLL-Implementierung

Wie bereits erwähnt, gehen die Ressourcenbelastung Standard die Liste mit CDynLinkLibrary -Objekten, die auf der Suche nach der ersten exe- oder DLL, die die angeforderte Ressource besitzt. Alle MFC-APIs sowie alle internen Code verwendet AfxFindResourceHandle gehen die Ressourcenliste jeder Ressource, egal wo sie wohnen können.

Wenn Sie nur Ressourcen von einer bestimmten Stelle laden möchten, verwenden Sie die APIs AfxGetResourceHandle und AfxSetResourceHandle , um das alte Handle zu speichern und das neue Handle festzulegen. Achten Sie darauf, das alte Ressourcenhandle wiederherstellen, bevor Sie an die Clientanwendung zurückzugeben. Das Beispiel TESTDLL2 verwendet diesen Ansatz für explizit laden ein Menü.

Zu Fuß von der Liste hat die Nachteile, dass es etwas langsamer und Verwalten von Ressource-ID-Bereiche erfordert. Es hat den Vorteil, dass eine Clientanwendung, die mit mehreren Erweiterungs-DLLs verknüpft jede DLL bereitgestellte Ressource verwenden kann, ohne dass das DLL-Instanzenhandle angegeben. AfxFindResourceHandle ist eine API zum Wandern der Ressourcenliste zu einem bestimmten Spiel suchen. Es nimmt den Namen und Typ einer Ressource und gibt das Ressourcenhandle wo es zuerst gefunden wurde (oder NULL).

Schreiben Sie eine Anwendung, die DLL-Version verwendet

Anwendungsanforderungen

Eine Anwendung, die gemeinsam genutzte MFC-Version muss ein paar einfache Regeln folgen.:

Gebäude mit der Entwicklungsumgebung

Wenn Sie das interne Makefile mit den meisten standard-Standardeinstellungen verwenden, können Sie einfach das Projekt zum Erstellen der DLL-Version ändern.

Der folgende Schritt wird vorausgesetzt, dass Sie eine ordnungsgemäß funktionierende MFC-Anwendung mit NAFXCWD verbunden haben.LIB (für Debuggen) und NAFXCW.LIB (für Einzelhandel) und Sie möchten verwenden die gemeinsam genutzte Version der MFC-Bibliothek konvertieren. Sie sind die Visual C++-Umgebung ausgeführt und haben eine internes Projekt-Datei.

  1. Wählen Sie im Menü Erstellen Einstellungen. Festlegen Sie auf der Seite Allgemein unter Projekteinstellungen Microsoft Foundation Classes verwenden MFC in einer freigegebenen DLL (MFCxx(d).dll).

Gebäude mit NMAKE

Wenn Sie das externe Makefile-Feature von Visual C++ verwenden, oder direkt NMAKE verwenden, müssen Sie das Makefile zur Unterstützung von Compiler- und Linker-Optionen bearbeiten

Erforderliche Compiler-flags:

/ D_AFXDLL/MD

/ D_AFXDLL

Die MFC-Header benötigen dieses Symbol definiert werden:

/ MD

Die Anwendung muss die DLL-Version der C-Laufzeitbibliothek verwenden

Alle anderen Compiler-Flags führen Sie die MFC-Standardeinstellungen (z. B. _DEBUG für Debug).

Bearbeiten Sie die Linker-Liste der Bibliotheken. Änderung NAFXCWD.LIB, MFCxxD.LIB, und ändern Sie NAFXCW.LIB, MFCxx.LIB. Fügen Sie MFCOxx[U]D.LIB, MFCDxx[U]D.LIB und MFCNxx[U]D.LIB nach Bedarf (für Verwendung des MFC/OLE, Datenbank oder Netzwerkklassen erforderlich). LIBC zu ersetzen.LIB mit MSVCRT.LIB. Wie bei anderen MFC-Bibliothek es wichtig ist, dass MFCxxD.LIB, bevor platziert wird alle C-Laufzeit-Bibliotheken.

Optional sowohl Ihren Einzelhandel /D_AFXDLL hinzu und Debuggen Sie Ressourcen-Compiler-Optionen (die ein, die tatsächlich die Ressourcen mit/r kompiliert wird). Dies macht Ihre endgültige ausführbare Datei kleiner durch den Austausch von Ressourcen, die in der MFC-DLLs vorhanden sind.

Eine vollständige Neuerstellung ist erforderlich, nachdem diese Änderungen vorgenommen wurden.

Erstellen der Beispiele

Die meisten von der MFC-Beispielprogrammen können gebaut werden, aus Visual C++ oder aus einem freigegebenen NMAKE-kompatiblen MAKEFILE von der Befehlszeile aus.

Um alle diese Beispiele verwenden MFCxx.DLL zu konvertieren, können Sie laden die.MAK-Datei in der Visual C++ und die Projekt-Optionen festlegen, wie oben beschrieben. Wenn Sie das NMAKE-Build verwenden, können Sie "AFXDLL = 1" auf der NMAKE-Befehlszeile und die bauen das Beispiel mit die MFC-Bibliotheken.

Das Beispiel MFC Advanced Concepts DLLHUSK baut mit der DLL-Version von MFC. Dieses Beispiel verdeutlicht nicht nur zum Erstellen einer Anwendungs mit MFCxx.DLL verbunden, aber es zeigt auch andere Funktionen der MFC-DLL Verpackung Option z. B. MFC-Erweiterungs-DLLs, die weiter unten in diesem technischen Hinweis beschrieben.

Verpackung-Hinweise

Die Retail-Version der DLLs (MFCxx [U].DLL) sind frei verteilbare. Die Debug-Version der DLLs sind nicht frei verteilbare und sollte nur während der Entwicklung Ihrer Anwendung verwendet werden.

Das Debug-DLLs werden mit debugging-Informationen zur Verfügung gestellt. Mithilfe von Visual C++-Debugger können Sie die Ausführung der Anwendung sowie die DLL verfolgen. Die Release-DLLs (MFCxx [U].DLL) enthalten keine Debug-Informationen.

Wenn Sie anpassen oder neu DLLs erstellen, sollte dann Sie etwas anders als "MFCxx" der MFC SRC Datei MFCDLL nennen.MAK Buildoptionen beschreibt und enthält die Logik zum Umbenennen der DLL. Diese Regel gilt auch für die MFC/OLE, Datenbank und Netzwerk-DLLs, die von MFCOLE gebaut werden.MAK, MFCDB.MAK, und MFCNET.MAK, beziehungsweise. Umbenennen der Dateien ist erforderlich, da diese DLLs möglicherweise von vielen MFC-Anwendungen gemeinsam genutzt werden. Nachdem Ihre angepasste Version der MFC-DLLs kann ersetzen die auf dem System installiert eine andere MFC-Anwendung mithilfe der gemeinsam genutzten MFC-DLLs brechen.

Neuerstellung der MFC-DLLs ist nicht zu empfehlen.

Wie die MFCxx.DLL implementiert wird

Der folgende Abschnitt beschreibt, wie der MFC-DLL (MFCxx.DLL und MFCxxD.DLL). Verständnis, dass die Informationen hier auch nicht ist wichtig, wenn alles, was Sie wollen verwenden Sie die MFC-DLL mit Ihrer Anwendung. Die Informationen hier sind nicht wesentlich für das Verständnis eine MFC-Erweiterungs-DLL schreiben, aber Verständnis dieser Implementierung können Sie eigene DLL schreiben.

Übersicht über die Umsetzung

Der MFC-DLL ist wirklich ein besonderer Fall von einer MFC-Erweiterungs-DLL, wie oben beschrieben. Es hat eine sehr große Anzahl der Exporte für eine große Anzahl von Klassen. Es gibt ein paar zusätzliche Dinge tun wir in der MFC-DLL, die es noch spezieller als eine reguläre Erweiterung DLL machen.

Win32 ist die meiste Arbeit

Die 16-Bit-Version von MFC benötigt eine Reihe von speziellen Techniken einschließlich der pro-app Daten auf den Stack-Segment, spezielle Segmente erstellt von 80 x 86 Assemblycode, pro Prozess Ausnahme Kontexte und anderen Techniken. Win32 unterstützt direkt pro Prozess Daten in einer DLL, die ist, was Sie die meiste Zeit. MFCxx.DLL ist zum größten Teil nur NAFXCW.LIB in eine DLL gepackt. Wenn Sie den MFC-Quellcode betrachten, finden Sie nur sehr wenige # ifdef _AFXDLL, da gibt es sehr wenige Sonderfälle, die vorgenommen werden müssen. Die Sonderfälle, die sind, gibt es speziell mit Win32 auf Windows 3.1 (andernfalls bekannt als Win32s). Win32s tut nicht Unterstützung per-Process-DLL-Daten direkt so der MFC-DLL den lokalen Threadspeicher (TLS) Win32-APIs zu lokalen Prozessdaten verwenden müssen.

Auswirkungen auf die Bibliotheksquellen, zusätzliche Dateien

Die Auswirkungen der _AFXDLL -Version auf die normalen MFC-Klasse Bibliothek-Quellen und Header ist relativ gering. Es gibt eine spezielle Versionsdatei (AFXV_DLL.H) sowie eine zusätzliche Headerdatei (AFXDLL_.H) aufgenommen, indem die wichtigsten AFXWIN.H Header. Die AFXDLL_.H Header enthält die CDynLinkLibrary -Klasse und andere Implementierungsdetails von _AFXDLL Anwendungen und MFC-Erweiterungs-DLLs. Die AFXDLLX.H Header dient zum Erstellen von MFC-Erweiterungs-DLLs (Näheres siehe oben).

Die regelmäßigen Quellen der MFC-Bibliothek mit MFC SRC haben einige weiteren bedingten Code unter der _AFXDLL # ifdef. Eine weitere Quelle-Datei (DLLINIT.CPP) enthält die zusätzlichen DLL-Initialisierungscode und andere Kleber für die gemeinsam genutzte MFC-version.

Um die gemeinsam genutzte MFC-Version erstellen, werden zusätzliche Dateien zur Verfügung gestellt. (Siehe unten für Informationen zum Erstellen der DLL.)

Der MFC-DLL erstellen

Neuerstellung der MFC-DLL absichtlich schwer ist, so denken Sie zweimal (oder dreimal) bevor tuend es. Wenn Sie die verpackenprobleme des Potenzials und Umverteilung Einschränkungen beschrieben, und Sie immer noch wirklich verstehen der MFC-DLL neu erstellen müssen, können Sie.

Die MFCDLL.MAK-Datei wird die Debug-DLL mit Codeansichtsinformationen Informationen erstellen:

NMAKE/f mfcdll.mak DEBUG = 1 LIBNAME = MYMFC

Die MFCDLL.MAK-Datei wird die Release-DLL ohne Codeansichtsinformationen Informationen erstellen.:

NMAKE/f mfcdll.mak DEBUG = 0 LIBNAME = MYMFC

(ähnlich, verwenden Sie MFCOLE.MAK, MFCDB.MAK, und MFCNET.MAK baut die MFCOxxD.DLL, MFCDxxD.DLL und MFCNxxD.DLL--die DLLs enthalten die MFC/OLE, Datenbank und Netzwerkklassen)

Dadurch wird eine private Version der MFC-DLL in Ihre MFC SRC-Verzeichnis mit den standard MFCxx.DLL und MFCxxD.DLL Namen erstellt. Sie müssen kopieren sie an einer geeigneten Stelle auf dem Weg zur neuen DLLs verwenden. Die MFCDLL.MAK Makefile wird auch neu erstellen die Importbibliotheken (MFCxx.LIB und MFCxxD.LIB) und in der standardmäßigen MFC-LIB-Verzeichnis ablegen. Dies ersetzt die vorgefertigten MFCxx.LIB und MFCxxD.LIB Bibliotheken, also seien Sie vorsichtig.

Wenn Sie eine geänderte Version der Bibliothek MFC-DLL weiterverteilen möchten, bitte achten Sie auf den Namen der DLL, in der MFCDLL ändern.MAK Makefile und die beiden.DEF-Dateien. Finden Sie in der Makefile-Datei MFCDLL.MAK für mehr info.

Sie können die Bibliothek ändern und verteilen ein Einzelhandel (/ Version) der veränderten Bibliothek nur, wenn Sie es auf etwas anderes als MFCxx.DLL umbenennen. Nicht verteilen der Debugversion von entweder die vordefinierte oder benutzerdefinierte erstellte DLL.

Diese Umverteilung-Einschränkungen sind in erster Linie zu eine starken Zunahme von nicht dem Standard entsprechende und potenziell Virus mit DLLs. Idealerweise sollte nicht müssen Sie die DLLs neu erstellen und wenn Sie Ihre Anwendung mit vorgefertigten MFCxx.DLL bereitgestellt mit dem Visual C++-Produkt verteilen, werden Sie eine Menge Probleme vermeiden, für sich selbst und Ihre Benutzer.

Speicherverwaltung

Eine Anwendung mit MFCxx.DLL verwendet eine gemeinsame Speicherreservierungsfunktion bereitgestellt durch MSVCRTxx.DLL, die gemeinsam genutzte C-Laufzeit-DLL. Die Anwendung, alle Erweiterungs-DLLs, sowie die MFC-DLLs selbst verwenden diese shared-Memory-Zuweisung. Mithilfe von können für die Zuweisung einer gemeinsam genutzten DLL, die MFC-DLLs Speicher zuordnen, die später von der Anwendung oder umgekehrt freigegeben wird. Da die Anwendung und die DLL die gleiche Zuweisung verwenden müssen, sollten Sie nicht die C++ globale Operator neue oder Operator deleteüberschreiben. Die gleichen Regeln gelten für den Rest der C-Runtime Speicher Zuweisung Routinen (wie z. B. Malloc, Realloc, free, etc..).

Ordnungszahlen und Klasse __declspec(dllexport) und DLL Benennung

Wir verwenden nicht die class __declspec(dllexport) Funktionalität des C++-Compilers. Stattdessen ist eine Liste der Exporte in die Klasse Bibliotheksquellen (MFCxx.DEF und MFCxxD.DEF) enthalten. Nur diese ausgewählten Satz von Einstiegspunkte (Funktionen und Daten) werden exportiert. Anderen Symbolen, z. B. MFC private Anwendung Funktionen oder Klassen, werden nicht exportiert alle Ausfuhren erfolgen durch Ordnungszahl ohne einen Zeichenfolgennamen in der Namenstabelle ansässige oder nicht ansässige .

Mit class __declspec(dllexport) kann eine brauchbare Alternative für kleinere DLLs erstellen, aber bei einer großen DLL wie MFC, hat der Standardwert Export Mechanismus Effizienz und Kapazität Grenzen .

Was dieses alle Mittel ist, dass wir eine große Menge von Funktionen in der Version MFCxx.DLL verpacken können, die nur rund 800 kByte ohne Kompromisse viel Ausführung oder Geschwindigkeit beim Laden ist. MFCxx.DLL hätte 100 K größer war diese Technik nicht verwendet.Dies macht es auch möglich, zusätzliche Einstiegspunkte am Ende der.DEF-Datei, die einfache Versionsverwaltung ermöglichen, ohne dabei die Effizienz Geschwindigkeit und Größe der Exportieren nach Ordnungszahl. Hauptversion Revisionen in der MFC-Klassenbibliothek ändert den Namen den Bibliothek. Das heißt, MFC30.DLL ist die verteilbaren DLL mit Version 3.0 der MFC Klassenbibliothek. Ein Upgrade dieser DLL, sagen, in einem hypothetischen 3.1 MFC DLL MFC31 benannt werden würde.DLL statt. Wieder, wenn Sie den MFC-Quellcode eine benutzerdefinierte Version der MFC-DLL zu ändern, bitte benutzen Sie einen anderen Namen (und vorzugsweise ohne "MFC") im Namen.

Technische Hinweise von &Nummer |nbsp; Technische Hinweise nach Kategorie

Index