Verwenden von MFC-Erweiterungs-DLLs für Datenbanken, OLE und Sockets in regulären MFC-DLLs
Wenn Sie eine MFC-Erweiterungs-DLL aus einer regulären MFC-DLL verwenden und die MFC-Erweiterungs-DLL nicht mit der CDynLinkLibrary
-Objektkette der regulären MFC-DLL verbunden ist, können in diesem Zusammenhang Probleme auftreten. Da die Debugversionen der MFC-Unterstützungs-DLLs für Datenbanken, OLE und Sockets als MFC-Erweiterungs-DLLs implementiert sind, treten bei Verwendung dieser MFC-Features möglicherweise selbst dann ähnliche Probleme auf, wenn Sie nicht explizit eine Ihrer eigenen MFC-Erweiterungs-DLLs verwenden. Dies sind einige Anzeichen:
Beim Versuch, ein Objekt eines Klassentyps zu deserialisieren, der in der MFC-Erweiterungs-DLL definiert ist, wird die Meldung "Warnung: CYourClass kann nicht aus dem Archiv geladen werden. Klasse nicht definiert." wird im TRACE-Debugfenster angezeigt, und das Objekt kann nicht serialisiert werden.
Es wird eine Ausnahme ausgegeben, die angibt, dass es sich möglicherweise um eine ungültige Klasse handelt.
Ressourcen, die in der MFC-Erweiterungs-DLL gespeichert sind, können nicht geladen werden, da
AfxFindResourceHandle
ein RückgabeNULL
- oder ein falscher Ressourcenhandle zurückgegeben wird.DllGetClassObject
undDllCanUnloadNow
sowie die MemberfunktionenUpdateRegistry
,Revoke
,RevokeAll
undRegisterAll
vonCOleObjectFactory
können keine in der MFC-Erweiterungs-DLL definierte Klassenfactory finden.AfxDoForAllClasses
funktioniert für Klassen in der MFC-Erweiterungs-DLL nicht.MFC-Datenbank-, Socket- oder OLE-Standardressourcen können nicht geladen werden. Beispielsweise gibt
AfxLoadString(AFX_IDP_SQL_CONNECT_FAIL)
eine leere Zeichenfolge zurück, auch wenn die reguläre MFC-DLL die MFC-Datenbankklassen ordnungsgemäß verwendet.
Die Lösung für diese Probleme besteht darin, eine Initialisierungsfunktion in der MFC-Erweiterungs-DLL zu erstellen und zu exportieren, die ein CDynLinkLibrary
Objekt erstellt. Diese Initialisierungsfunktion wird von jeder regulären MFC-DLL, die die MFC-Erweiterungs-DLL verwendet, genau einmal aufgerufen.
MFC-Unterstützung für OLE, Datenbanken (oder DAO) oder Sockets
Wenn Sie in Ihrer regulären MFC-DLL die MFC-Unterstützung für OLE, Datenbanken (oder DAO) oder Sockets verwenden, werden die MFC-Erweiterungs-DLLs MFCOxxD.dll
, MFCDxxD.dll
und MFCNxxD.dll
für das MFC-Debugging automatisch verknüpft (xx steht für die Versionsnummer). Rufen Sie für jede von Ihnen verwendete DLLs eine vordefinierte Initialisierungsfunktion auf:
Fügen Sie zur Unterstützung von Datenbanken in der
CWinApp::InitInstance
-Funktion Ihrer regulären MFC-DLL einen Aufruf vonAfxDbInitModule
hinzu. Stellen Sie sicher, dass dieser Aufruf vor allen Basisklassenaufrufen und jeglichem hinzugefügten Code erfolgt, der auf dieMFCDxxD.dll
zugreift. Diese Funktion akzeptiert keine Parameter und gibtvoid
zurück.Fügen Sie zur Unterstützung von OLE in der
CWinApp::InitInstance
-Funktion Ihrer regulären MFC-DLL einen Aufruf vonAfxOleInitModule
hinzu. DieCOleControlModule::InitInstance
-Funktion ruftAfxOleInitModule
bereits auf. Wenn Sie also ein OLE-Steuerelement erstellen undCOleControlModule
verwenden, dürfen SieAfxOleInitModule
diesen Aufruf nicht hinzufügen.Fügen Sie zur Unterstützung von Sockets Ihrer regulären MFC-DLL in
CWinApp::InitInstance
einen Aufruf vonAfxNetInitModule
hinzu.
Releasebuilds von MFC-DLLs und -Anwendungen verwenden keine separaten DLLs für die Unterstützung von Datenbanken, Sockets oder OLE. Es ist jedoch sicher, diese Initialisierungsfunktionen im Releasemodus aufzurufen.
CDynLinkLibrary-Objekte
Bei allen Vorgängen, die am Anfang dieses Artikels erwähnt wurden, muss MFC nach einem bestimmten Wert oder Objekt suchen. Beispielsweise muss die MFC während der Deserialisierung alle zurzeit verfügbaren Runtimeklassen durchsuchen, um Objekte im Archiv mit der entsprechenden Runtimeklasse abzugleichen.
Als Teil dieser Suchvorgänge durchsucht MFC alle MFC-Erweiterungs-DLLs, die verwendet werden, indem sie eine Kette von CDynLinkLibrary
Objekten durchlaufen. CDynLinkLibrary
Objekte werden während der Erstellung automatisch an eine Kette angefügt und von jeder MFC-Erweiterungs-DLL wiederum während der Initialisierung erstellt. Jedes Modul (Anwendung oder reguläre MFC-DLL) verfügt über eine eigene Kette aus CDynLinkLibrary
-Objekten.
Damit eine MFC-Erweiterungs-DLL in eine CDynLinkLibrary
Kette verkabelt wird, muss sie ein CDynLinkLibrary
Objekt im Kontext jedes Moduls erstellen, das die MFC-Erweiterungs-DLL verwendet. Damit eine MFC-Erweiterungs-DLL von regulären MFC-DLLs verwendet werden kann, muss die Erweiterungs-DLL eine exportierte Initialisierungsfunktion bereitstellen, die ein CDynLinkLibrary
-Objekt erstellt. Jede reguläre MFC-DLL, die die MFC-Erweiterungs-DLL verwendet, muss die exportierte Initialisierungsfunktion aufrufen.
Wenn Sie eine MFC-Erweiterungs-DLL nur von einer MFC-Anwendung und nie von einer regulären MFC-DLL verwenden, genügt es, das CDynLinkLibrary
-Objekt in der DllMain
-Funktion der MFC-Erweiterungs-DLL zu erstellen. Genau das macht der MFC-Erweiterungs-DLL-Code des MFC-DLL-Assistenten. Beim impliziten Laden einer MFC-Erweiterungs-DLL wird DllMain
vor dem Starten der Anwendung geladen und ausgeführt. Alle CDynLinkLibrary
Kreationen werden in eine Standardkette verkabelt, die die MFC-DLL für eine MFC-Anwendung reserviert.
Es wird dringend davon abgeraten, mehrere CDynLinkLibrary
-Objekte aus einer einzigen MFC-Erweiterungs-DLL in einer Kette zu verwenden. Dies gilt besonders dann, wenn die MFC-Erweiterungs-DLL möglicherweise dynamisch aus dem Arbeitsspeicher entladen wird. Rufen Sie die Initialisierungsfunktion nicht mehr als einmal aus einem Modul auf.
Beispielcode
In diesem Beispielcode wird davon ausgegangen, dass die reguläre MFC-DLL implizit mit der MFC-Erweiterungs-DLL verknüpft ist. Für eine implizite Verknüpfung erstellen Sie eine Verknüpfung mit der Importbibliothek (LIB-Datei) der MFC-Erweiterungs-DLL, wenn Sie die reguläre MFC-DLL erstellen.
Die Quelle der MFC-Erweiterungs-DLL sollte die folgenden Zeilen enthalten:
// YourExtDLL.cpp:
// standard MFC extension DLL routines
#include "afxdllx.h"
static AFX_EXTENSION_MODULE extensionDLL;
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
// MFC extension DLL one-time initialization
if (!AfxInitExtensionModule(extensionDLL, hInstance))
return 0;
}
return 1; // ok
}
// Exported DLL initialization is run in context of
// application or regular MFC DLL
extern "C" void WINAPI InitYourExtDLL()
{
// create a new CDynLinkLibrary for this app
new CDynLinkLibrary(extensionDLL);
// add other initialization here
}
Stellen Sie sicher, dass Sie die InitYourExtDLL-Funktion exportieren. Sie können __declspec(dllexport)
verwenden oder die Funktion in der DEF-Datei für Ihre DLL exportieren, wie im Folgenden gezeigt:
// YourExtDLL.Def:
LIBRARY YOUREXTDLL
CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD SINGLE
EXPORTS
InitYourExtDLL
Fügen Sie mit der MFC-Erweiterungs-DLL in jeder regulären MFC-DLL einen Aufruf für den InitInstance
-Member des von CWinApp
abgeleiteten Objekts hinzu:
// YourRegularDLL.cpp:
class CYourRegularDLL : public CWinApp
{
public:
virtual BOOL InitInstance(); // Initialization
virtual int ExitInstance(); // Termination
// nothing special for the constructor
CYourRegularDLL(LPCTSTR pszAppName) : CWinApp(pszAppName) { }
};
BOOL CYourRegularDLL::InitInstance()
{
// any DLL initialization goes here
TRACE0("YOUR regular MFC DLL initializing\n");
// wire any MFC extension DLLs into CDynLinkLibrary chain
InitYourExtDLL();
return TRUE;
}
Wie möchten Sie vorgehen?
Worüber möchten Sie mehr erfahren?
Regular MFC DLLs Statically Linked to MFC (Reguläre, statisch mit MFC verknüpfte MFC-DLLs)
Regular MFC DLLs Dynamically Linked to MFC (Reguläre, dynamisch mit MFC verknüpfte MFC-DLLs)