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ückgabe NULL - oder ein falscher Ressourcenhandle zurückgegeben wird.

  • DllGetClassObject und DllCanUnloadNow sowie die Memberfunktionen UpdateRegistry, Revoke, RevokeAll und RegisterAll von COleObjectFactory 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 von AfxDbInitModule hinzu. Stellen Sie sicher, dass dieser Aufruf vor allen Basisklassenaufrufen und jeglichem hinzugefügten Code erfolgt, der auf die MFCDxxD.dll zugreift. Diese Funktion akzeptiert keine Parameter und gibt void zurück.

  • Fügen Sie zur Unterstützung von OLE in der CWinApp::InitInstance-Funktion Ihrer regulären MFC-DLL einen Aufruf von AfxOleInitModule hinzu. Die COleControlModule::InitInstance-Funktion ruft AfxOleInitModule bereits auf. Wenn Sie also ein OLE-Steuerelement erstellen und COleControlModule verwenden, dürfen Sie AfxOleInitModule diesen Aufruf nicht hinzufügen.

  • Fügen Sie zur Unterstützung von Sockets Ihrer regulären MFC-DLL in CWinApp::InitInstance einen Aufruf von AfxNetInitModule 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?

Siehe auch

MFC-Erweiterungs-DLLs